Skip to content

Commit d014c65

Browse files
author
Andreas Büsching
committed
* notifier/threads.py (Enhanced): new thread cass supporting thread-safe signals
(threaded): a decorator that simplifies running a function as a thread * notifier/nf_generic.py (step): if there are no timers and socket events the loop sleeps for dispatch.MIN_TIMER that was passed to time.sleep without dividing by 1000. That caused a sleep for 1 minute and 40 seconds instead of 100 milliseconds.
1 parent f850275 commit d014c65

File tree

5 files changed

+78
-40
lines changed

5 files changed

+78
-40
lines changed

ChangeLog

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
1+
2012-03-23 Andreas B�sching <crunchy@bitkipper.net>
2+
3+
* notifier/threads.py (Enhanced): new thread cass supporting thread-safe signals
4+
(threaded): a decorator that simplifies running a function as a thread
5+
6+
* notifier/nf_generic.py (step): if there are no timers and socket
7+
events the loop sleeps for dispatch.MIN_TIMER that was passed to
8+
time.sleep without dividing by 1000. That caused a sleep for 1
9+
minute and 40 seconds instead of 100 milliseconds.
10+
111
2011-10-23 Andreas B�sching <crunchy@bitkipper.net>
212

313
* notifier/version.py: set version to 0.9.3

notifier/nf_generic.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
#
66
# generic notifier implementation
77
#
8-
# Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
8+
# Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
99
# Andreas Büsching <crunchy@bitkipper.net>
1010
#
1111
# This library is free software; you can redistribute it and/or modify
@@ -225,7 +225,7 @@ def step( sleep = True, external = True ):
225225
elif timeout:
226226
time_sleep( timeout / 1000.0 )
227227
elif timeout == None: # if there are no timers and no sockets, do not burn the CPU
228-
time_sleep( dispatch.MIN_TIMER )
228+
time_sleep( dispatch.MIN_TIMER / 1000.0 )
229229

230230
# handle timers
231231
for i, timer in __timers.items():

notifier/signals.py

Lines changed: 29 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
#
66
# a generic signal implementation for propagating asynchron events
77
#
8-
# Copyright (C) 2005, 2006, 2010
8+
# Copyright (C) 2005, 2006, 2010, 2011
99
# Andreas Büsching <crunchy@bitkipper.net>
1010
#
1111
# This library is free software; you can redistribute it and/or modify
@@ -24,22 +24,30 @@
2424

2525
__signals = {}
2626

27+
# exception classes
28+
class UnknownSignalError( Exception ):
29+
pass
30+
31+
class SignalExistsError( Exception ):
32+
pass
33+
2734
class Signal( object ):
2835
def __init__( self, name ):
2936
self.name = name
3037
self.__callbacks = []
3138

3239
def emit( self, *args ):
3340
for cb in self.__callbacks:
34-
if args: cb( *args )
35-
else: cb()
41+
cb( *args )
3642

3743
def connect( self, callback ):
3844
self.__callbacks.append( callback )
3945

4046
def disconnect( self, callback ):
41-
try: self.__callbacks.remove( callback )
42-
except: pass
47+
try:
48+
self.__callbacks.remove( callback )
49+
except:
50+
pass
4351

4452
def __str__( self ):
4553
return self.name
@@ -61,63 +69,55 @@ def signal_disconnect( self, signal, callback ):
6169
disconnect( signal, callback, self.__signals )
6270

6371
def signal_emit( self, signal, *args ):
64-
if isinstance( signal, Signal ) and \
65-
self.__signals.has_key( signal.name ):
72+
if isinstance( signal, Signal ) and signal.name in self.__signals:
6673
self.__signals[ signal.name ].emit( *args )
67-
elif isinstance( signal, str ) and self.__signals.has_key( signal ):
74+
elif isinstance( signal, basestring ) and signal in self.__signals:
6875
self.__signals[ signal ].emit( *args )
6976

7077
def _select_signals( signals ):
7178
global __signals
72-
if signals == None: return __signals
73-
else: return signals
79+
return signals is None and __signals or signals
7480

7581
def new( signal, signals = None ):
7682
_signals = _select_signals( signals )
77-
if isinstance( signal, str ):
83+
if isinstance( signal, basestring ):
7884
signal = Signal( signal )
7985

80-
if _signals.has_key( signal.name ):
86+
if signal.name in _signals:
8187
raise SignalExistsError( "Signal '%s' already exists" % signal.name )
8288
else:
8389
_signals[ signal.name ] = signal
8490

8591
def exists( signal, signals = None ):
8692
_signals = _select_signals( signals )
87-
if isinstance( signal, str ):
88-
return _signals.has_key( signal )
93+
if isinstance( signal, basestring ):
94+
return signal in _signals
8995
else:
90-
return _signals.has_key( signal.name )
96+
return signal.name in _signals
9197

9298
def connect( signal, callback, signals = None ):
9399
_signals = _select_signals( signals )
94-
if isinstance( signal, Signal ) and _signals.has_key( signal.name ):
100+
if isinstance( signal, Signal ) and signal.name in _signals:
95101
_signals[ signal.name ].connect( callback )
96-
elif isinstance( signal, str ):
97-
if _signals.has_key( signal ):
102+
elif isinstance( signal, basestring ):
103+
if signal in _signals:
98104
_signals[ signal ].connect( callback )
99105
else:
100106
raise UnknownSignalError( "unknown signal '%s'" % signal )
101107

102108

103109
def disconnect( signal, callback, signals = None ):
104110
_signals = _select_signals( signals )
105-
if isinstance( signal, Signal ) and _signals.has_key( signal.name ):
111+
if isinstance( signal, Signal ) and signal.name in _signals:
106112
_signals[ signal.name ].disconnect( callback )
107-
elif isinstance( signal, str ) and _signals.has_key( signal ):
113+
elif isinstance( signal, basestring ) and signal in _signals:
108114
_signals[ signal ].disconnect( callback )
109115

110116
def emit( signal, *args ):
111-
if isinstance( signal, Signal ) and __signals.has_key( signal.name ):
117+
if isinstance( signal, Signal ) and signal.name in __signals:
112118
__signals[ signal.name ].emit( *args )
113-
elif isinstance( signal, str ):
114-
if __signals.has_key( signal ):
119+
elif isinstance( signal, basestring ):
120+
if signal in __signals:
115121
__signals[ signal ].emit( *args )
116122
else:
117123
raise UnknownSignalError( "unknown signal '%s'" % signal )
118-
119-
class UnknownSignalError( Exception ):
120-
pass
121-
122-
class SignalExistsError( Exception ):
123-
pass

notifier/threads.py

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
#
66
# simple interface to handle threads synchron to the notifier loop
77
#
8-
# Copyright (C) 2006, 2011
8+
# Copyright (C) 2006, 2011, 2012
99
# Andreas Büsching <crunchy@bitkipper.net>
1010
#
1111
# This library is free software; you can redistribute it and/or modify
@@ -24,10 +24,13 @@
2424

2525
import notifier
2626

27+
import functools
2728
import sys
2829
import thread
2930
import traceback
3031

32+
import .signals
33+
3134
__all__ = [ 'Simple' ]
3235

3336
_threads = []
@@ -133,18 +136,43 @@ def unlock( self ):
133136
def announce( self ):
134137
self._callback( self, self._result )
135138

139+
class Enhanced( Simple ):
140+
def __init__( self, function, callback ):
141+
Simple.__init__( self, '__enhanced__', function, callback )
142+
self._signals = []
143+
144+
def signal_emit( self, signal, *args ):
145+
self.lock()
146+
self._signals.append( ( signal, args ) )
147+
self.unlock()
148+
136149
def _simple_threads_dispatcher():
137150
"""Dispatcher function checking for finished threads"""
138-
finished = []
139151
global _threads
140-
for task in _threads:
152+
153+
for task in _threads[ : ]:
141154
task.lock()
142155
if task.finished:
143156
task.announce()
144-
finished.append( task )
157+
_threads.remove( task )
158+
elif getattr( task, '_signals' ):
159+
for signal, args in task._signals:
160+
signals.emit( signal, *args )
161+
task._signals = []
145162
task.unlock()
146163

147-
for t in finished:
148-
_threads.remove( t )
149-
150164
return ( len( _threads ) > 0 )
165+
166+
def threaded( finished_func ):
167+
"""A decorator function making it simple to start a thread. Just
168+
add the decorator to the function that should be the main thread
169+
function. The argument is the function that should be invoked when
170+
the thread has finished"""
171+
172+
def inner_thread( func ):
173+
def wrapped( *args, **kwargs ):
174+
thread = Enhanced( notifier.Callback( func, *args, **kwargs ), finished_func )
175+
thread.run()
176+
return functools.wraps( func )( wrapped )
177+
return inner_thread
178+

notifier/version.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
#
66
# version information
77
#
8-
# Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
8+
# Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
99
# Andreas Büsching <crunchy@bitkipper.net>
1010
#
1111
# This library is free software; you can redistribute it and/or modify
@@ -24,7 +24,7 @@
2424

2525
major_number = 0
2626
minor_number = 9
27-
revision_number = 3
27+
revision_number = 4
2828
extension = ''
2929

3030
VERSION = "%d.%d.%d%s" % ( major_number, minor_number,

0 commit comments

Comments
 (0)