| 
									
										
										
										
											2002-08-14 19:25:42 +00:00
										 |  |  | """Thread module emulating a subset of Java's threading model.""" | 
					
						
							| 
									
										
										
										
											1998-04-09 22:01:42 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-12-30 23:32:50 +00:00
										 |  |  | import sys as _sys | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | try: | 
					
						
							|  |  |  |     import thread | 
					
						
							|  |  |  | except ImportError: | 
					
						
							|  |  |  |     del _sys.modules[__name__] | 
					
						
							|  |  |  |     raise | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | from time import time as _time, sleep as _sleep | 
					
						
							| 
									
										
										
										
											2003-11-05 23:03:00 +00:00
										 |  |  | from traceback import format_exc as _format_exc | 
					
						
							| 
									
										
										
										
											2004-01-29 06:37:52 +00:00
										 |  |  | from collections import deque | 
					
						
							| 
									
										
										
										
											1998-04-09 22:01:42 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | # Rename some stuff so "from threading import *" is safe | 
					
						
							| 
									
										
										
										
											2002-12-30 21:59:55 +00:00
										 |  |  | __all__ = ['activeCount', 'Condition', 'currentThread', 'enumerate', 'Event', | 
					
						
							| 
									
										
										
										
											2003-06-29 16:50:06 +00:00
										 |  |  |            'Lock', 'RLock', 'Semaphore', 'BoundedSemaphore', 'Thread', | 
					
						
							| 
									
										
										
										
											2006-06-13 15:04:24 +00:00
										 |  |  |            'Timer', 'setprofile', 'settrace', 'local', 'stack_size'] | 
					
						
							| 
									
										
										
										
											1998-04-09 22:01:42 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | _start_new_thread = thread.start_new_thread | 
					
						
							|  |  |  | _allocate_lock = thread.allocate_lock | 
					
						
							|  |  |  | _get_ident = thread.get_ident | 
					
						
							| 
									
										
										
										
											2000-06-01 01:17:17 +00:00
										 |  |  | ThreadError = thread.error | 
					
						
							| 
									
										
										
										
											1998-04-09 22:01:42 +00:00
										 |  |  | del thread | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-07-01 20:01:55 +00:00
										 |  |  | # Debug support (adapted from ihooks.py). | 
					
						
							|  |  |  | # All the major classes here derive from _Verbose.  We force that to | 
					
						
							|  |  |  | # be a new-style class so that all the major classes here are new-style. | 
					
						
							|  |  |  | # This helps debugging (type(instance) is more revealing for instances | 
					
						
							|  |  |  | # of new-style classes). | 
					
						
							| 
									
										
										
										
											1998-04-09 22:01:42 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-07-01 19:28:44 +00:00
										 |  |  | _VERBOSE = False | 
					
						
							| 
									
										
										
										
											1998-04-09 22:01:42 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | if __debug__: | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-07-01 20:01:55 +00:00
										 |  |  |     class _Verbose(object): | 
					
						
							| 
									
										
										
										
											1998-04-09 22:01:42 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         def __init__(self, verbose=None): | 
					
						
							|  |  |  |             if verbose is None: | 
					
						
							|  |  |  |                 verbose = _VERBOSE | 
					
						
							|  |  |  |             self.__verbose = verbose | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def _note(self, format, *args): | 
					
						
							|  |  |  |             if self.__verbose: | 
					
						
							|  |  |  |                 format = format % args | 
					
						
							|  |  |  |                 format = "%s: %s\n" % ( | 
					
						
							|  |  |  |                     currentThread().getName(), format) | 
					
						
							|  |  |  |                 _sys.stderr.write(format) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | else: | 
					
						
							|  |  |  |     # Disable this when using "python -O" | 
					
						
							| 
									
										
										
										
											2003-07-01 20:01:55 +00:00
										 |  |  |     class _Verbose(object): | 
					
						
							| 
									
										
										
										
											1998-04-09 22:01:42 +00:00
										 |  |  |         def __init__(self, verbose=None): | 
					
						
							|  |  |  |             pass | 
					
						
							|  |  |  |         def _note(self, *args): | 
					
						
							|  |  |  |             pass | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-06-29 16:58:41 +00:00
										 |  |  | # Support for profile and trace hooks | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | _profile_hook = None | 
					
						
							|  |  |  | _trace_hook = None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def setprofile(func): | 
					
						
							|  |  |  |     global _profile_hook | 
					
						
							|  |  |  |     _profile_hook = func | 
					
						
							| 
									
										
										
										
											2003-06-29 17:24:17 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-06-29 16:58:41 +00:00
										 |  |  | def settrace(func): | 
					
						
							|  |  |  |     global _trace_hook | 
					
						
							|  |  |  |     _trace_hook = func | 
					
						
							| 
									
										
										
										
											1998-04-09 22:01:42 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | # Synchronization classes | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Lock = _allocate_lock | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def RLock(*args, **kwargs): | 
					
						
							| 
									
										
										
										
											2003-02-27 20:14:51 +00:00
										 |  |  |     return _RLock(*args, **kwargs) | 
					
						
							| 
									
										
										
										
											1998-04-09 22:01:42 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | class _RLock(_Verbose): | 
					
						
							| 
									
										
										
										
											2001-01-15 03:26:36 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1998-04-09 22:01:42 +00:00
										 |  |  |     def __init__(self, verbose=None): | 
					
						
							|  |  |  |         _Verbose.__init__(self, verbose) | 
					
						
							|  |  |  |         self.__block = _allocate_lock() | 
					
						
							|  |  |  |         self.__owner = None | 
					
						
							|  |  |  |         self.__count = 0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __repr__(self): | 
					
						
							| 
									
										
										
										
											2007-07-31 13:38:01 +00:00
										 |  |  |         owner = self.__owner | 
					
						
							| 
									
										
										
										
											1998-04-09 22:01:42 +00:00
										 |  |  |         return "<%s(%s, %d)>" % ( | 
					
						
							|  |  |  |                 self.__class__.__name__, | 
					
						
							| 
									
										
										
										
											2007-07-31 13:38:01 +00:00
										 |  |  |                 owner and owner.getName(), | 
					
						
							| 
									
										
										
										
											1998-04-09 22:01:42 +00:00
										 |  |  |                 self.__count) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def acquire(self, blocking=1): | 
					
						
							|  |  |  |         me = currentThread() | 
					
						
							|  |  |  |         if self.__owner is me: | 
					
						
							|  |  |  |             self.__count = self.__count + 1 | 
					
						
							|  |  |  |             if __debug__: | 
					
						
							|  |  |  |                 self._note("%s.acquire(%s): recursive success", self, blocking) | 
					
						
							|  |  |  |             return 1 | 
					
						
							|  |  |  |         rc = self.__block.acquire(blocking) | 
					
						
							|  |  |  |         if rc: | 
					
						
							|  |  |  |             self.__owner = me | 
					
						
							|  |  |  |             self.__count = 1 | 
					
						
							|  |  |  |             if __debug__: | 
					
						
							| 
									
										
										
										
											2005-01-27 22:48:30 +00:00
										 |  |  |                 self._note("%s.acquire(%s): initial success", self, blocking) | 
					
						
							| 
									
										
										
										
											1998-04-09 22:01:42 +00:00
										 |  |  |         else: | 
					
						
							|  |  |  |             if __debug__: | 
					
						
							|  |  |  |                 self._note("%s.acquire(%s): failure", self, blocking) | 
					
						
							|  |  |  |         return rc | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-02-28 21:57:43 +00:00
										 |  |  |     __enter__ = acquire | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1998-04-09 22:01:42 +00:00
										 |  |  |     def release(self): | 
					
						
							| 
									
										
										
										
											2007-06-06 00:17:35 +00:00
										 |  |  |         if self.__owner is not currentThread(): | 
					
						
							|  |  |  |             raise RuntimeError("cannot release un-aquired lock") | 
					
						
							| 
									
										
										
										
											1998-04-09 22:01:42 +00:00
										 |  |  |         self.__count = count = self.__count - 1 | 
					
						
							|  |  |  |         if not count: | 
					
						
							|  |  |  |             self.__owner = None | 
					
						
							|  |  |  |             self.__block.release() | 
					
						
							|  |  |  |             if __debug__: | 
					
						
							|  |  |  |                 self._note("%s.release(): final release", self) | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             if __debug__: | 
					
						
							|  |  |  |                 self._note("%s.release(): non-final release", self) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-02-28 21:57:43 +00:00
										 |  |  |     def __exit__(self, t, v, tb): | 
					
						
							|  |  |  |         self.release() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1998-04-09 22:01:42 +00:00
										 |  |  |     # Internal methods used by condition variables | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _acquire_restore(self, (count, owner)): | 
					
						
							|  |  |  |         self.__block.acquire() | 
					
						
							|  |  |  |         self.__count = count | 
					
						
							|  |  |  |         self.__owner = owner | 
					
						
							|  |  |  |         if __debug__: | 
					
						
							|  |  |  |             self._note("%s._acquire_restore()", self) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _release_save(self): | 
					
						
							|  |  |  |         if __debug__: | 
					
						
							|  |  |  |             self._note("%s._release_save()", self) | 
					
						
							|  |  |  |         count = self.__count | 
					
						
							|  |  |  |         self.__count = 0 | 
					
						
							|  |  |  |         owner = self.__owner | 
					
						
							|  |  |  |         self.__owner = None | 
					
						
							|  |  |  |         self.__block.release() | 
					
						
							|  |  |  |         return (count, owner) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _is_owned(self): | 
					
						
							|  |  |  |         return self.__owner is currentThread() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def Condition(*args, **kwargs): | 
					
						
							| 
									
										
										
										
											2003-02-27 20:14:51 +00:00
										 |  |  |     return _Condition(*args, **kwargs) | 
					
						
							| 
									
										
										
										
											1998-04-09 22:01:42 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | class _Condition(_Verbose): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __init__(self, lock=None, verbose=None): | 
					
						
							|  |  |  |         _Verbose.__init__(self, verbose) | 
					
						
							|  |  |  |         if lock is None: | 
					
						
							|  |  |  |             lock = RLock() | 
					
						
							|  |  |  |         self.__lock = lock | 
					
						
							|  |  |  |         # Export the lock's acquire() and release() methods | 
					
						
							|  |  |  |         self.acquire = lock.acquire | 
					
						
							|  |  |  |         self.release = lock.release | 
					
						
							|  |  |  |         # If the lock defines _release_save() and/or _acquire_restore(), | 
					
						
							|  |  |  |         # these override the default implementations (which just call | 
					
						
							|  |  |  |         # release() and acquire() on the lock).  Ditto for _is_owned(). | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             self._release_save = lock._release_save | 
					
						
							|  |  |  |         except AttributeError: | 
					
						
							|  |  |  |             pass | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             self._acquire_restore = lock._acquire_restore | 
					
						
							|  |  |  |         except AttributeError: | 
					
						
							|  |  |  |             pass | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             self._is_owned = lock._is_owned | 
					
						
							|  |  |  |         except AttributeError: | 
					
						
							|  |  |  |             pass | 
					
						
							|  |  |  |         self.__waiters = [] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-05-02 19:47:52 +00:00
										 |  |  |     def __enter__(self): | 
					
						
							|  |  |  |         return self.__lock.__enter__() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __exit__(self, *args): | 
					
						
							|  |  |  |         return self.__lock.__exit__(*args) | 
					
						
							| 
									
										
										
										
											2006-02-28 21:57:43 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1998-04-09 22:01:42 +00:00
										 |  |  |     def __repr__(self): | 
					
						
							|  |  |  |         return "<Condition(%s, %d)>" % (self.__lock, len(self.__waiters)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _release_save(self): | 
					
						
							|  |  |  |         self.__lock.release()           # No state to save | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _acquire_restore(self, x): | 
					
						
							|  |  |  |         self.__lock.acquire()           # Ignore saved state | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _is_owned(self): | 
					
						
							| 
									
										
										
										
											2002-08-14 17:46:40 +00:00
										 |  |  |         # Return True if lock is owned by currentThread. | 
					
						
							| 
									
										
										
										
											2002-08-14 17:43:59 +00:00
										 |  |  |         # This method is called only if __lock doesn't have _is_owned(). | 
					
						
							| 
									
										
										
										
											1998-04-09 22:01:42 +00:00
										 |  |  |         if self.__lock.acquire(0): | 
					
						
							|  |  |  |             self.__lock.release() | 
					
						
							| 
									
										
										
										
											2002-04-04 22:55:58 +00:00
										 |  |  |             return False | 
					
						
							| 
									
										
										
										
											1998-04-09 22:01:42 +00:00
										 |  |  |         else: | 
					
						
							| 
									
										
										
										
											2002-04-04 22:55:58 +00:00
										 |  |  |             return True | 
					
						
							| 
									
										
										
										
											1998-04-09 22:01:42 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def wait(self, timeout=None): | 
					
						
							| 
									
										
										
										
											2007-06-06 00:17:35 +00:00
										 |  |  |         if not self._is_owned(): | 
					
						
							|  |  |  |             raise RuntimeError("cannot wait on un-aquired lock") | 
					
						
							| 
									
										
										
										
											1998-04-09 22:01:42 +00:00
										 |  |  |         waiter = _allocate_lock() | 
					
						
							|  |  |  |         waiter.acquire() | 
					
						
							|  |  |  |         self.__waiters.append(waiter) | 
					
						
							|  |  |  |         saved_state = self._release_save() | 
					
						
							| 
									
										
										
										
											2001-04-02 20:15:57 +00:00
										 |  |  |         try:    # restore state no matter what (e.g., KeyboardInterrupt) | 
					
						
							|  |  |  |             if timeout is None: | 
					
						
							|  |  |  |                 waiter.acquire() | 
					
						
							| 
									
										
										
										
											1998-04-09 22:01:42 +00:00
										 |  |  |                 if __debug__: | 
					
						
							| 
									
										
										
										
											2001-04-02 20:15:57 +00:00
										 |  |  |                     self._note("%s.wait(): got it", self) | 
					
						
							| 
									
										
										
										
											1998-04-09 22:01:42 +00:00
										 |  |  |             else: | 
					
						
							| 
									
										
										
										
											2001-08-12 00:41:33 +00:00
										 |  |  |                 # Balancing act:  We can't afford a pure busy loop, so we | 
					
						
							|  |  |  |                 # have to sleep; but if we sleep the whole timeout time, | 
					
						
							|  |  |  |                 # we'll be unresponsive.  The scheme here sleeps very | 
					
						
							|  |  |  |                 # little at first, longer as time goes on, but never longer | 
					
						
							|  |  |  |                 # than 20 times per second (or the timeout time remaining). | 
					
						
							| 
									
										
										
										
											2001-04-02 20:15:57 +00:00
										 |  |  |                 endtime = _time() + timeout | 
					
						
							| 
									
										
										
										
											2001-08-12 00:41:33 +00:00
										 |  |  |                 delay = 0.0005 # 500 us -> initial delay of 1 ms | 
					
						
							| 
									
										
										
										
											2002-04-07 06:36:23 +00:00
										 |  |  |                 while True: | 
					
						
							| 
									
										
										
										
											2001-04-02 20:15:57 +00:00
										 |  |  |                     gotit = waiter.acquire(0) | 
					
						
							| 
									
										
										
										
											2001-08-12 00:41:33 +00:00
										 |  |  |                     if gotit: | 
					
						
							| 
									
										
										
										
											2001-04-02 20:15:57 +00:00
										 |  |  |                         break | 
					
						
							| 
									
										
										
										
											2001-08-12 00:41:33 +00:00
										 |  |  |                     remaining = endtime - _time() | 
					
						
							|  |  |  |                     if remaining <= 0: | 
					
						
							|  |  |  |                         break | 
					
						
							|  |  |  |                     delay = min(delay * 2, remaining, .05) | 
					
						
							| 
									
										
										
										
											2001-04-02 20:15:57 +00:00
										 |  |  |                     _sleep(delay) | 
					
						
							|  |  |  |                 if not gotit: | 
					
						
							|  |  |  |                     if __debug__: | 
					
						
							|  |  |  |                         self._note("%s.wait(%s): timed out", self, timeout) | 
					
						
							|  |  |  |                     try: | 
					
						
							|  |  |  |                         self.__waiters.remove(waiter) | 
					
						
							|  |  |  |                     except ValueError: | 
					
						
							|  |  |  |                         pass | 
					
						
							|  |  |  |                 else: | 
					
						
							|  |  |  |                     if __debug__: | 
					
						
							|  |  |  |                         self._note("%s.wait(%s): got it", self, timeout) | 
					
						
							|  |  |  |         finally: | 
					
						
							|  |  |  |             self._acquire_restore(saved_state) | 
					
						
							| 
									
										
										
										
											1998-04-09 22:01:42 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def notify(self, n=1): | 
					
						
							| 
									
										
										
										
											2007-06-06 00:17:35 +00:00
										 |  |  |         if not self._is_owned(): | 
					
						
							|  |  |  |             raise RuntimeError("cannot notify on un-aquired lock") | 
					
						
							| 
									
										
										
										
											1998-04-09 22:01:42 +00:00
										 |  |  |         __waiters = self.__waiters | 
					
						
							|  |  |  |         waiters = __waiters[:n] | 
					
						
							|  |  |  |         if not waiters: | 
					
						
							|  |  |  |             if __debug__: | 
					
						
							|  |  |  |                 self._note("%s.notify(): no waiters", self) | 
					
						
							|  |  |  |             return | 
					
						
							|  |  |  |         self._note("%s.notify(): notifying %d waiter%s", self, n, | 
					
						
							|  |  |  |                    n!=1 and "s" or "") | 
					
						
							|  |  |  |         for waiter in waiters: | 
					
						
							|  |  |  |             waiter.release() | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 __waiters.remove(waiter) | 
					
						
							|  |  |  |             except ValueError: | 
					
						
							|  |  |  |                 pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def notifyAll(self): | 
					
						
							|  |  |  |         self.notify(len(self.__waiters)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def Semaphore(*args, **kwargs): | 
					
						
							| 
									
										
										
										
											2003-02-27 20:14:51 +00:00
										 |  |  |     return _Semaphore(*args, **kwargs) | 
					
						
							| 
									
										
										
										
											1998-04-09 22:01:42 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | class _Semaphore(_Verbose): | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-02-29 00:10:24 +00:00
										 |  |  |     # After Tim Peters' semaphore class, but not quite the same (no maximum) | 
					
						
							| 
									
										
										
										
											1998-04-09 22:01:42 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def __init__(self, value=1, verbose=None): | 
					
						
							| 
									
										
										
										
											2007-06-06 00:17:35 +00:00
										 |  |  |         if value < 0: | 
					
						
							|  |  |  |             raise ValueError("semaphore initial value must be >= 0") | 
					
						
							| 
									
										
										
										
											1998-04-09 22:01:42 +00:00
										 |  |  |         _Verbose.__init__(self, verbose) | 
					
						
							|  |  |  |         self.__cond = Condition(Lock()) | 
					
						
							|  |  |  |         self.__value = value | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def acquire(self, blocking=1): | 
					
						
							| 
									
										
										
										
											2002-04-07 06:36:23 +00:00
										 |  |  |         rc = False | 
					
						
							| 
									
										
										
										
											1998-04-09 22:01:42 +00:00
										 |  |  |         self.__cond.acquire() | 
					
						
							|  |  |  |         while self.__value == 0: | 
					
						
							|  |  |  |             if not blocking: | 
					
						
							|  |  |  |                 break | 
					
						
							| 
									
										
										
										
											2001-08-19 04:25:24 +00:00
										 |  |  |             if __debug__: | 
					
						
							|  |  |  |                 self._note("%s.acquire(%s): blocked waiting, value=%s", | 
					
						
							|  |  |  |                            self, blocking, self.__value) | 
					
						
							| 
									
										
										
										
											1998-04-09 22:01:42 +00:00
										 |  |  |             self.__cond.wait() | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             self.__value = self.__value - 1 | 
					
						
							| 
									
										
										
										
											2001-08-19 04:25:24 +00:00
										 |  |  |             if __debug__: | 
					
						
							| 
									
										
										
										
											2001-08-19 05:53:47 +00:00
										 |  |  |                 self._note("%s.acquire: success, value=%s", | 
					
						
							|  |  |  |                            self, self.__value) | 
					
						
							| 
									
										
										
										
											2002-04-07 06:36:23 +00:00
										 |  |  |             rc = True | 
					
						
							| 
									
										
										
										
											1998-04-09 22:01:42 +00:00
										 |  |  |         self.__cond.release() | 
					
						
							|  |  |  |         return rc | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-02-28 21:57:43 +00:00
										 |  |  |     __enter__ = acquire | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1998-04-09 22:01:42 +00:00
										 |  |  |     def release(self): | 
					
						
							|  |  |  |         self.__cond.acquire() | 
					
						
							|  |  |  |         self.__value = self.__value + 1 | 
					
						
							| 
									
										
										
										
											2001-08-19 04:25:24 +00:00
										 |  |  |         if __debug__: | 
					
						
							| 
									
										
										
										
											2001-08-19 05:53:47 +00:00
										 |  |  |             self._note("%s.release: success, value=%s", | 
					
						
							|  |  |  |                        self, self.__value) | 
					
						
							| 
									
										
										
										
											1998-04-09 22:01:42 +00:00
										 |  |  |         self.__cond.notify() | 
					
						
							|  |  |  |         self.__cond.release() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-02-28 21:57:43 +00:00
										 |  |  |     def __exit__(self, t, v, tb): | 
					
						
							|  |  |  |         self.release() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1998-04-09 22:01:42 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-08-20 20:27:58 +00:00
										 |  |  | def BoundedSemaphore(*args, **kwargs): | 
					
						
							| 
									
										
										
										
											2003-02-27 20:14:51 +00:00
										 |  |  |     return _BoundedSemaphore(*args, **kwargs) | 
					
						
							| 
									
										
										
										
											2001-08-20 20:27:58 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | class _BoundedSemaphore(_Semaphore): | 
					
						
							|  |  |  |     """Semaphore that checks that # releases is <= # acquires""" | 
					
						
							|  |  |  |     def __init__(self, value=1, verbose=None): | 
					
						
							|  |  |  |         _Semaphore.__init__(self, value, verbose) | 
					
						
							|  |  |  |         self._initial_value = value | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def release(self): | 
					
						
							|  |  |  |         if self._Semaphore__value >= self._initial_value: | 
					
						
							|  |  |  |             raise ValueError, "Semaphore released too many times" | 
					
						
							|  |  |  |         return _Semaphore.release(self) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1998-04-09 22:01:42 +00:00
										 |  |  | def Event(*args, **kwargs): | 
					
						
							| 
									
										
										
										
											2003-02-27 20:14:51 +00:00
										 |  |  |     return _Event(*args, **kwargs) | 
					
						
							| 
									
										
										
										
											1998-04-09 22:01:42 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | class _Event(_Verbose): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # After Tim Peters' event class (without is_posted()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __init__(self, verbose=None): | 
					
						
							|  |  |  |         _Verbose.__init__(self, verbose) | 
					
						
							|  |  |  |         self.__cond = Condition(Lock()) | 
					
						
							| 
									
										
										
										
											2002-04-07 06:36:23 +00:00
										 |  |  |         self.__flag = False | 
					
						
							| 
									
										
										
										
											1998-04-09 22:01:42 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def isSet(self): | 
					
						
							|  |  |  |         return self.__flag | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def set(self): | 
					
						
							|  |  |  |         self.__cond.acquire() | 
					
						
							| 
									
										
										
										
											2002-11-21 21:08:39 +00:00
										 |  |  |         try: | 
					
						
							|  |  |  |             self.__flag = True | 
					
						
							|  |  |  |             self.__cond.notifyAll() | 
					
						
							|  |  |  |         finally: | 
					
						
							|  |  |  |             self.__cond.release() | 
					
						
							| 
									
										
										
										
											1998-04-09 22:01:42 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def clear(self): | 
					
						
							|  |  |  |         self.__cond.acquire() | 
					
						
							| 
									
										
										
										
											2002-11-21 21:08:39 +00:00
										 |  |  |         try: | 
					
						
							|  |  |  |             self.__flag = False | 
					
						
							|  |  |  |         finally: | 
					
						
							|  |  |  |             self.__cond.release() | 
					
						
							| 
									
										
										
										
											1998-04-09 22:01:42 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def wait(self, timeout=None): | 
					
						
							|  |  |  |         self.__cond.acquire() | 
					
						
							| 
									
										
										
										
											2002-11-21 21:08:39 +00:00
										 |  |  |         try: | 
					
						
							|  |  |  |             if not self.__flag: | 
					
						
							|  |  |  |                 self.__cond.wait(timeout) | 
					
						
							|  |  |  |         finally: | 
					
						
							|  |  |  |             self.__cond.release() | 
					
						
							| 
									
										
										
										
											1998-04-09 22:01:42 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | # Helper to generate new thread names | 
					
						
							|  |  |  | _counter = 0 | 
					
						
							|  |  |  | def _newname(template="Thread-%d"): | 
					
						
							|  |  |  |     global _counter | 
					
						
							|  |  |  |     _counter = _counter + 1 | 
					
						
							|  |  |  |     return template % _counter | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # Active thread administration | 
					
						
							|  |  |  | _active_limbo_lock = _allocate_lock() | 
					
						
							| 
									
										
										
										
											2005-01-08 07:30:42 +00:00
										 |  |  | _active = {}    # maps thread id to Thread object | 
					
						
							| 
									
										
										
										
											1998-04-09 22:01:42 +00:00
										 |  |  | _limbo = {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # Main class for threads | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class Thread(_Verbose): | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-04-07 06:36:23 +00:00
										 |  |  |     __initialized = False | 
					
						
							| 
									
										
										
										
											2004-07-03 03:52:35 +00:00
										 |  |  |     # Need to store a reference to sys.exc_info for printing | 
					
						
							|  |  |  |     # out exceptions when a thread tries to use a global var. during interp. | 
					
						
							|  |  |  |     # shutdown and thus raises an exception about trying to perform some | 
					
						
							|  |  |  |     # operation on/with a NoneType | 
					
						
							|  |  |  |     __exc_info = _sys.exc_info | 
					
						
							| 
									
										
										
										
											1998-04-09 22:01:42 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def __init__(self, group=None, target=None, name=None, | 
					
						
							| 
									
										
										
										
											2005-07-15 09:13:21 +00:00
										 |  |  |                  args=(), kwargs=None, verbose=None): | 
					
						
							| 
									
										
										
										
											1998-06-09 19:04:26 +00:00
										 |  |  |         assert group is None, "group argument must be None for now" | 
					
						
							| 
									
										
										
										
											1998-04-09 22:01:42 +00:00
										 |  |  |         _Verbose.__init__(self, verbose) | 
					
						
							| 
									
										
										
										
											2005-07-15 09:13:21 +00:00
										 |  |  |         if kwargs is None: | 
					
						
							|  |  |  |             kwargs = {} | 
					
						
							| 
									
										
										
										
											1998-04-09 22:01:42 +00:00
										 |  |  |         self.__target = target | 
					
						
							|  |  |  |         self.__name = str(name or _newname()) | 
					
						
							|  |  |  |         self.__args = args | 
					
						
							|  |  |  |         self.__kwargs = kwargs | 
					
						
							|  |  |  |         self.__daemonic = self._set_daemon() | 
					
						
							| 
									
										
										
										
											2002-04-07 06:36:23 +00:00
										 |  |  |         self.__started = False | 
					
						
							|  |  |  |         self.__stopped = False | 
					
						
							| 
									
										
										
										
											1998-04-09 22:01:42 +00:00
										 |  |  |         self.__block = Condition(Lock()) | 
					
						
							| 
									
										
										
										
											2002-04-07 06:36:23 +00:00
										 |  |  |         self.__initialized = True | 
					
						
							| 
									
										
										
										
											2004-07-03 03:52:35 +00:00
										 |  |  |         # sys.stderr is not stored in the class like | 
					
						
							|  |  |  |         # sys.exc_info since it can be changed between instances | 
					
						
							|  |  |  |         self.__stderr = _sys.stderr | 
					
						
							| 
									
										
										
										
											1998-04-09 22:01:42 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def _set_daemon(self): | 
					
						
							|  |  |  |         # Overridden in _MainThread and _DummyThread | 
					
						
							|  |  |  |         return currentThread().isDaemon() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __repr__(self): | 
					
						
							|  |  |  |         assert self.__initialized, "Thread.__init__() was not called" | 
					
						
							|  |  |  |         status = "initial" | 
					
						
							|  |  |  |         if self.__started: | 
					
						
							|  |  |  |             status = "started" | 
					
						
							|  |  |  |         if self.__stopped: | 
					
						
							|  |  |  |             status = "stopped" | 
					
						
							|  |  |  |         if self.__daemonic: | 
					
						
							|  |  |  |             status = status + " daemon" | 
					
						
							|  |  |  |         return "<%s(%s, %s)>" % (self.__class__.__name__, self.__name, status) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def start(self): | 
					
						
							| 
									
										
										
										
											2007-06-06 00:17:35 +00:00
										 |  |  |         if not self.__initialized: | 
					
						
							|  |  |  |             raise RuntimeError("thread.__init__() not called") | 
					
						
							|  |  |  |         if self.__started: | 
					
						
							|  |  |  |             raise RuntimeError("thread already started") | 
					
						
							| 
									
										
										
										
											1998-04-09 22:01:42 +00:00
										 |  |  |         if __debug__: | 
					
						
							|  |  |  |             self._note("%s.start(): starting thread", self) | 
					
						
							|  |  |  |         _active_limbo_lock.acquire() | 
					
						
							|  |  |  |         _limbo[self] = self | 
					
						
							|  |  |  |         _active_limbo_lock.release() | 
					
						
							|  |  |  |         _start_new_thread(self.__bootstrap, ()) | 
					
						
							| 
									
										
										
										
											2002-04-07 06:36:23 +00:00
										 |  |  |         self.__started = True | 
					
						
							| 
									
										
										
										
											1998-04-09 22:01:42 +00:00
										 |  |  |         _sleep(0.000001)    # 1 usec, to let the thread run (Solaris hack) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def run(self): | 
					
						
							|  |  |  |         if self.__target: | 
					
						
							| 
									
										
										
										
											2003-02-27 20:14:51 +00:00
										 |  |  |             self.__target(*self.__args, **self.__kwargs) | 
					
						
							| 
									
										
										
										
											1998-04-09 22:01:42 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def __bootstrap(self): | 
					
						
							|  |  |  |         try: | 
					
						
							| 
									
										
										
										
											2002-04-07 06:36:23 +00:00
										 |  |  |             self.__started = True | 
					
						
							| 
									
										
										
										
											1998-04-09 22:01:42 +00:00
										 |  |  |             _active_limbo_lock.acquire() | 
					
						
							|  |  |  |             _active[_get_ident()] = self | 
					
						
							|  |  |  |             del _limbo[self] | 
					
						
							|  |  |  |             _active_limbo_lock.release() | 
					
						
							|  |  |  |             if __debug__: | 
					
						
							|  |  |  |                 self._note("%s.__bootstrap(): thread started", self) | 
					
						
							| 
									
										
										
										
											2003-06-29 16:58:41 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |             if _trace_hook: | 
					
						
							|  |  |  |                 self._note("%s.__bootstrap(): registering trace hook", self) | 
					
						
							|  |  |  |                 _sys.settrace(_trace_hook) | 
					
						
							|  |  |  |             if _profile_hook: | 
					
						
							|  |  |  |                 self._note("%s.__bootstrap(): registering profile hook", self) | 
					
						
							|  |  |  |                 _sys.setprofile(_profile_hook) | 
					
						
							| 
									
										
										
										
											2003-06-29 17:24:17 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1998-04-09 22:01:42 +00:00
										 |  |  |             try: | 
					
						
							|  |  |  |                 self.run() | 
					
						
							|  |  |  |             except SystemExit: | 
					
						
							|  |  |  |                 if __debug__: | 
					
						
							|  |  |  |                     self._note("%s.__bootstrap(): raised SystemExit", self) | 
					
						
							|  |  |  |             except: | 
					
						
							|  |  |  |                 if __debug__: | 
					
						
							|  |  |  |                     self._note("%s.__bootstrap(): unhandled exception", self) | 
					
						
							| 
									
										
										
										
											2004-07-03 03:52:35 +00:00
										 |  |  |                 # If sys.stderr is no more (most likely from interpreter | 
					
						
							|  |  |  |                 # shutdown) use self.__stderr.  Otherwise still use sys (as in | 
					
						
							|  |  |  |                 # _sys) in case sys.stderr was redefined since the creation of | 
					
						
							|  |  |  |                 # self. | 
					
						
							|  |  |  |                 if _sys: | 
					
						
							|  |  |  |                     _sys.stderr.write("Exception in thread %s:\n%s\n" % | 
					
						
							|  |  |  |                                       (self.getName(), _format_exc())) | 
					
						
							|  |  |  |                 else: | 
					
						
							|  |  |  |                     # Do the best job possible w/o a huge amt. of code to | 
					
						
							|  |  |  |                     # approximate a traceback (code ideas from | 
					
						
							|  |  |  |                     # Lib/traceback.py) | 
					
						
							|  |  |  |                     exc_type, exc_value, exc_tb = self.__exc_info() | 
					
						
							|  |  |  |                     try: | 
					
						
							|  |  |  |                         print>>self.__stderr, ( | 
					
						
							|  |  |  |                             "Exception in thread " + self.getName() + | 
					
						
							|  |  |  |                             " (most likely raised during interpreter shutdown):") | 
					
						
							|  |  |  |                         print>>self.__stderr, ( | 
					
						
							|  |  |  |                             "Traceback (most recent call last):") | 
					
						
							|  |  |  |                         while exc_tb: | 
					
						
							|  |  |  |                             print>>self.__stderr, ( | 
					
						
							|  |  |  |                                 '  File "%s", line %s, in %s' % | 
					
						
							|  |  |  |                                 (exc_tb.tb_frame.f_code.co_filename, | 
					
						
							|  |  |  |                                     exc_tb.tb_lineno, | 
					
						
							|  |  |  |                                     exc_tb.tb_frame.f_code.co_name)) | 
					
						
							|  |  |  |                             exc_tb = exc_tb.tb_next | 
					
						
							|  |  |  |                         print>>self.__stderr, ("%s: %s" % (exc_type, exc_value)) | 
					
						
							|  |  |  |                     # Make sure that exc_tb gets deleted since it is a memory | 
					
						
							|  |  |  |                     # hog; deleting everything else is just for thoroughness | 
					
						
							|  |  |  |                     finally: | 
					
						
							|  |  |  |                         del exc_type, exc_value, exc_tb | 
					
						
							| 
									
										
										
										
											1998-04-09 22:01:42 +00:00
										 |  |  |             else: | 
					
						
							|  |  |  |                 if __debug__: | 
					
						
							|  |  |  |                     self._note("%s.__bootstrap(): normal return", self) | 
					
						
							|  |  |  |         finally: | 
					
						
							|  |  |  |             self.__stop() | 
					
						
							| 
									
										
										
										
											2001-12-28 22:07:09 +00:00
										 |  |  |             try: | 
					
						
							|  |  |  |                 self.__delete() | 
					
						
							|  |  |  |             except: | 
					
						
							|  |  |  |                 pass | 
					
						
							| 
									
										
										
										
											1998-04-09 22:01:42 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def __stop(self): | 
					
						
							|  |  |  |         self.__block.acquire() | 
					
						
							| 
									
										
										
										
											2002-04-07 06:36:23 +00:00
										 |  |  |         self.__stopped = True | 
					
						
							| 
									
										
										
										
											1998-04-09 22:01:42 +00:00
										 |  |  |         self.__block.notifyAll() | 
					
						
							|  |  |  |         self.__block.release() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __delete(self): | 
					
						
							| 
									
										
										
										
											2004-07-21 03:36:52 +00:00
										 |  |  |         "Remove current thread from the dict of currently running threads." | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Notes about running with dummy_thread: | 
					
						
							|  |  |  |         # | 
					
						
							|  |  |  |         # Must take care to not raise an exception if dummy_thread is being | 
					
						
							|  |  |  |         # used (and thus this module is being used as an instance of | 
					
						
							|  |  |  |         # dummy_threading).  dummy_thread.get_ident() always returns -1 since | 
					
						
							|  |  |  |         # there is only one thread if dummy_thread is being used.  Thus | 
					
						
							|  |  |  |         # len(_active) is always <= 1 here, and any Thread instance created | 
					
						
							|  |  |  |         # overwrites the (if any) thread currently registered in _active. | 
					
						
							|  |  |  |         # | 
					
						
							|  |  |  |         # An instance of _MainThread is always created by 'threading'.  This | 
					
						
							|  |  |  |         # gets overwritten the instant an instance of Thread is created; both | 
					
						
							|  |  |  |         # threads return -1 from dummy_thread.get_ident() and thus have the | 
					
						
							|  |  |  |         # same key in the dict.  So when the _MainThread instance created by | 
					
						
							|  |  |  |         # 'threading' tries to clean itself up when atexit calls this method | 
					
						
							|  |  |  |         # it gets a KeyError if another Thread instance was created. | 
					
						
							|  |  |  |         # | 
					
						
							|  |  |  |         # This all means that KeyError from trying to delete something from | 
					
						
							|  |  |  |         # _active if dummy_threading is being used is a red herring.  But | 
					
						
							|  |  |  |         # since it isn't if dummy_threading is *not* being used then don't | 
					
						
							|  |  |  |         # hide the exception. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1998-04-09 22:01:42 +00:00
										 |  |  |         _active_limbo_lock.acquire() | 
					
						
							| 
									
										
										
										
											2004-07-21 03:36:52 +00:00
										 |  |  |         try: | 
					
						
							| 
									
										
										
										
											2004-07-21 02:21:58 +00:00
										 |  |  |             try: | 
					
						
							|  |  |  |                 del _active[_get_ident()] | 
					
						
							|  |  |  |             except KeyError: | 
					
						
							| 
									
										
										
										
											2004-07-21 03:36:52 +00:00
										 |  |  |                 if 'dummy_threading' not in _sys.modules: | 
					
						
							|  |  |  |                     raise | 
					
						
							|  |  |  |         finally: | 
					
						
							|  |  |  |             _active_limbo_lock.release() | 
					
						
							| 
									
										
										
										
											1998-04-09 22:01:42 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def join(self, timeout=None): | 
					
						
							| 
									
										
										
										
											2007-06-06 00:17:35 +00:00
										 |  |  |         if not self.__initialized: | 
					
						
							|  |  |  |             raise RuntimeError("Thread.__init__() not called") | 
					
						
							|  |  |  |         if not self.__started: | 
					
						
							|  |  |  |             raise RuntimeError("cannot join thread before it is started") | 
					
						
							|  |  |  |         if self is currentThread(): | 
					
						
							|  |  |  |             raise RuntimeError("cannot join current thread") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1998-04-09 22:01:42 +00:00
										 |  |  |         if __debug__: | 
					
						
							|  |  |  |             if not self.__stopped: | 
					
						
							|  |  |  |                 self._note("%s.join(): waiting until thread stops", self) | 
					
						
							|  |  |  |         self.__block.acquire() | 
					
						
							| 
									
										
										
										
											2005-11-23 02:15:50 +00:00
										 |  |  |         try: | 
					
						
							|  |  |  |             if timeout is None: | 
					
						
							|  |  |  |                 while not self.__stopped: | 
					
						
							|  |  |  |                     self.__block.wait() | 
					
						
							| 
									
										
										
										
											1998-04-09 22:01:42 +00:00
										 |  |  |                 if __debug__: | 
					
						
							|  |  |  |                     self._note("%s.join(): thread stopped", self) | 
					
						
							| 
									
										
										
										
											2005-11-23 02:15:50 +00:00
										 |  |  |             else: | 
					
						
							|  |  |  |                 deadline = _time() + timeout | 
					
						
							|  |  |  |                 while not self.__stopped: | 
					
						
							|  |  |  |                     delay = deadline - _time() | 
					
						
							|  |  |  |                     if delay <= 0: | 
					
						
							|  |  |  |                         if __debug__: | 
					
						
							|  |  |  |                             self._note("%s.join(): timed out", self) | 
					
						
							|  |  |  |                         break | 
					
						
							|  |  |  |                     self.__block.wait(delay) | 
					
						
							|  |  |  |                 else: | 
					
						
							|  |  |  |                     if __debug__: | 
					
						
							|  |  |  |                         self._note("%s.join(): thread stopped", self) | 
					
						
							|  |  |  |         finally: | 
					
						
							|  |  |  |             self.__block.release() | 
					
						
							| 
									
										
										
										
											1998-04-09 22:01:42 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def getName(self): | 
					
						
							|  |  |  |         assert self.__initialized, "Thread.__init__() not called" | 
					
						
							|  |  |  |         return self.__name | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def setName(self, name): | 
					
						
							|  |  |  |         assert self.__initialized, "Thread.__init__() not called" | 
					
						
							|  |  |  |         self.__name = str(name) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def isAlive(self): | 
					
						
							|  |  |  |         assert self.__initialized, "Thread.__init__() not called" | 
					
						
							|  |  |  |         return self.__started and not self.__stopped | 
					
						
							| 
									
										
										
										
											2001-01-15 03:26:36 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1998-04-09 22:01:42 +00:00
										 |  |  |     def isDaemon(self): | 
					
						
							|  |  |  |         assert self.__initialized, "Thread.__init__() not called" | 
					
						
							|  |  |  |         return self.__daemonic | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def setDaemon(self, daemonic): | 
					
						
							| 
									
										
										
										
											2007-06-06 00:17:35 +00:00
										 |  |  |         if not self.__initialized: | 
					
						
							|  |  |  |             raise RuntimeError("Thread.__init__() not called") | 
					
						
							|  |  |  |         if self.__started: | 
					
						
							|  |  |  |             raise RuntimeError("cannot set daemon status of active thread"); | 
					
						
							| 
									
										
										
										
											1998-04-09 22:01:42 +00:00
										 |  |  |         self.__daemonic = daemonic | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-09-05 13:44:54 +00:00
										 |  |  | # The timer class was contributed by Itamar Shtull-Trauring | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def Timer(*args, **kwargs): | 
					
						
							|  |  |  |     return _Timer(*args, **kwargs) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class _Timer(Thread): | 
					
						
							|  |  |  |     """Call a function after a specified number of seconds:
 | 
					
						
							| 
									
										
										
										
											2001-09-18 02:26:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-09-05 13:44:54 +00:00
										 |  |  |     t = Timer(30.0, f, args=[], kwargs={}) | 
					
						
							|  |  |  |     t.start() | 
					
						
							|  |  |  |     t.cancel() # stop the timer's action if it's still waiting | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2001-09-18 02:26:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-09-05 13:44:54 +00:00
										 |  |  |     def __init__(self, interval, function, args=[], kwargs={}): | 
					
						
							|  |  |  |         Thread.__init__(self) | 
					
						
							|  |  |  |         self.interval = interval | 
					
						
							|  |  |  |         self.function = function | 
					
						
							|  |  |  |         self.args = args | 
					
						
							|  |  |  |         self.kwargs = kwargs | 
					
						
							|  |  |  |         self.finished = Event() | 
					
						
							| 
									
										
										
										
											2001-09-18 02:26:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-09-05 13:44:54 +00:00
										 |  |  |     def cancel(self): | 
					
						
							|  |  |  |         """Stop the timer if it hasn't finished yet""" | 
					
						
							|  |  |  |         self.finished.set() | 
					
						
							| 
									
										
										
										
											2001-09-18 02:26:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-09-05 13:44:54 +00:00
										 |  |  |     def run(self): | 
					
						
							|  |  |  |         self.finished.wait(self.interval) | 
					
						
							|  |  |  |         if not self.finished.isSet(): | 
					
						
							|  |  |  |             self.function(*self.args, **self.kwargs) | 
					
						
							|  |  |  |         self.finished.set() | 
					
						
							| 
									
										
										
										
											1998-04-09 22:01:42 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | # Special thread class to represent the main thread | 
					
						
							|  |  |  | # This is garbage collected through an exit handler | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class _MainThread(Thread): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __init__(self): | 
					
						
							|  |  |  |         Thread.__init__(self, name="MainThread") | 
					
						
							| 
									
										
										
										
											2002-04-07 06:36:23 +00:00
										 |  |  |         self._Thread__started = True | 
					
						
							| 
									
										
										
										
											1998-04-09 22:01:42 +00:00
										 |  |  |         _active_limbo_lock.acquire() | 
					
						
							|  |  |  |         _active[_get_ident()] = self | 
					
						
							|  |  |  |         _active_limbo_lock.release() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _set_daemon(self): | 
					
						
							| 
									
										
										
										
											2002-04-07 06:36:23 +00:00
										 |  |  |         return False | 
					
						
							| 
									
										
										
										
											1998-04-09 22:01:42 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-01-04 21:06:12 +00:00
										 |  |  |     def _exitfunc(self): | 
					
						
							| 
									
										
										
										
											1998-04-09 22:01:42 +00:00
										 |  |  |         self._Thread__stop() | 
					
						
							|  |  |  |         t = _pickSomeNonDaemonThread() | 
					
						
							|  |  |  |         if t: | 
					
						
							|  |  |  |             if __debug__: | 
					
						
							|  |  |  |                 self._note("%s: waiting for other threads", self) | 
					
						
							|  |  |  |         while t: | 
					
						
							|  |  |  |             t.join() | 
					
						
							|  |  |  |             t = _pickSomeNonDaemonThread() | 
					
						
							|  |  |  |         if __debug__: | 
					
						
							|  |  |  |             self._note("%s: exiting", self) | 
					
						
							|  |  |  |         self._Thread__delete() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def _pickSomeNonDaemonThread(): | 
					
						
							|  |  |  |     for t in enumerate(): | 
					
						
							|  |  |  |         if not t.isDaemon() and t.isAlive(): | 
					
						
							|  |  |  |             return t | 
					
						
							|  |  |  |     return None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # Dummy thread class to represent threads not started here. | 
					
						
							| 
									
										
										
										
											2005-01-08 07:30:42 +00:00
										 |  |  | # These aren't garbage collected when they die, nor can they be waited for. | 
					
						
							|  |  |  | # If they invoke anything in threading.py that calls currentThread(), they | 
					
						
							|  |  |  | # leave an entry in the _active dict forever after. | 
					
						
							| 
									
										
										
										
											1998-04-09 22:01:42 +00:00
										 |  |  | # Their purpose is to return *something* from currentThread(). | 
					
						
							|  |  |  | # They are marked as daemon threads so we won't wait for them | 
					
						
							|  |  |  | # when we exit (conform previous semantics). | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class _DummyThread(Thread): | 
					
						
							| 
									
										
										
										
											2001-01-15 03:26:36 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1998-04-09 22:01:42 +00:00
										 |  |  |     def __init__(self): | 
					
						
							|  |  |  |         Thread.__init__(self, name=_newname("Dummy-%d")) | 
					
						
							| 
									
										
										
										
											2005-01-08 07:30:42 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # Thread.__block consumes an OS-level locking primitive, which | 
					
						
							|  |  |  |         # can never be used by a _DummyThread.  Since a _DummyThread | 
					
						
							|  |  |  |         # instance is immortal, that's bad, so release this resource. | 
					
						
							| 
									
										
										
										
											2005-01-08 02:43:53 +00:00
										 |  |  |         del self._Thread__block | 
					
						
							| 
									
										
										
										
											2005-01-08 07:30:42 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-04-07 06:36:23 +00:00
										 |  |  |         self._Thread__started = True | 
					
						
							| 
									
										
										
										
											1998-04-09 22:01:42 +00:00
										 |  |  |         _active_limbo_lock.acquire() | 
					
						
							|  |  |  |         _active[_get_ident()] = self | 
					
						
							|  |  |  |         _active_limbo_lock.release() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _set_daemon(self): | 
					
						
							| 
									
										
										
										
											2002-04-07 06:36:23 +00:00
										 |  |  |         return True | 
					
						
							| 
									
										
										
										
											1998-04-09 22:01:42 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-02-19 03:01:36 +00:00
										 |  |  |     def join(self, timeout=None): | 
					
						
							| 
									
										
										
										
											2002-04-07 06:36:23 +00:00
										 |  |  |         assert False, "cannot join a dummy thread" | 
					
						
							| 
									
										
										
										
											1998-04-09 22:01:42 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # Global API functions | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def currentThread(): | 
					
						
							|  |  |  |     try: | 
					
						
							|  |  |  |         return _active[_get_ident()] | 
					
						
							|  |  |  |     except KeyError: | 
					
						
							| 
									
										
										
										
											2000-12-15 20:08:39 +00:00
										 |  |  |         ##print "currentThread(): no current thread for", _get_ident() | 
					
						
							| 
									
										
										
										
											1998-04-09 22:01:42 +00:00
										 |  |  |         return _DummyThread() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def activeCount(): | 
					
						
							|  |  |  |     _active_limbo_lock.acquire() | 
					
						
							|  |  |  |     count = len(_active) + len(_limbo) | 
					
						
							|  |  |  |     _active_limbo_lock.release() | 
					
						
							|  |  |  |     return count | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def enumerate(): | 
					
						
							|  |  |  |     _active_limbo_lock.acquire() | 
					
						
							|  |  |  |     active = _active.values() + _limbo.values() | 
					
						
							|  |  |  |     _active_limbo_lock.release() | 
					
						
							|  |  |  |     return active | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-06-13 15:04:24 +00:00
										 |  |  | from thread import stack_size | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-01-04 21:06:12 +00:00
										 |  |  | # Create the main thread object, | 
					
						
							|  |  |  | # and make it available for the interpreter | 
					
						
							|  |  |  | # (Py_Main) as threading._shutdown. | 
					
						
							| 
									
										
										
										
											1998-04-09 22:01:42 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-01-04 21:06:12 +00:00
										 |  |  | _shutdown = _MainThread()._exitfunc | 
					
						
							| 
									
										
										
										
											1998-04-09 22:01:42 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-07-14 19:11:50 +00:00
										 |  |  | # get thread-local implementation, either from the thread | 
					
						
							|  |  |  | # module, or from the python fallback | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | try: | 
					
						
							|  |  |  |     from thread import _local as local | 
					
						
							|  |  |  | except ImportError: | 
					
						
							|  |  |  |     from _threading_local import local | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1998-04-09 22:01:42 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | # Self-test code | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def _test(): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     class BoundedQueue(_Verbose): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def __init__(self, limit): | 
					
						
							|  |  |  |             _Verbose.__init__(self) | 
					
						
							|  |  |  |             self.mon = RLock() | 
					
						
							|  |  |  |             self.rc = Condition(self.mon) | 
					
						
							|  |  |  |             self.wc = Condition(self.mon) | 
					
						
							|  |  |  |             self.limit = limit | 
					
						
							| 
									
										
										
										
											2004-01-29 06:37:52 +00:00
										 |  |  |             self.queue = deque() | 
					
						
							| 
									
										
										
										
											1998-04-09 22:01:42 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         def put(self, item): | 
					
						
							|  |  |  |             self.mon.acquire() | 
					
						
							|  |  |  |             while len(self.queue) >= self.limit: | 
					
						
							|  |  |  |                 self._note("put(%s): queue full", item) | 
					
						
							|  |  |  |                 self.wc.wait() | 
					
						
							|  |  |  |             self.queue.append(item) | 
					
						
							|  |  |  |             self._note("put(%s): appended, length now %d", | 
					
						
							|  |  |  |                        item, len(self.queue)) | 
					
						
							|  |  |  |             self.rc.notify() | 
					
						
							|  |  |  |             self.mon.release() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def get(self): | 
					
						
							|  |  |  |             self.mon.acquire() | 
					
						
							|  |  |  |             while not self.queue: | 
					
						
							|  |  |  |                 self._note("get(): queue empty") | 
					
						
							|  |  |  |                 self.rc.wait() | 
					
						
							| 
									
										
										
										
											2004-01-29 06:37:52 +00:00
										 |  |  |             item = self.queue.popleft() | 
					
						
							| 
									
										
										
										
											1998-04-09 22:01:42 +00:00
										 |  |  |             self._note("get(): got %s, %d left", item, len(self.queue)) | 
					
						
							|  |  |  |             self.wc.notify() | 
					
						
							|  |  |  |             self.mon.release() | 
					
						
							|  |  |  |             return item | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     class ProducerThread(Thread): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def __init__(self, queue, quota): | 
					
						
							|  |  |  |             Thread.__init__(self, name="Producer") | 
					
						
							|  |  |  |             self.queue = queue | 
					
						
							|  |  |  |             self.quota = quota | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def run(self): | 
					
						
							| 
									
										
										
										
											1998-05-20 17:05:52 +00:00
										 |  |  |             from random import random | 
					
						
							| 
									
										
										
										
											1998-04-09 22:01:42 +00:00
										 |  |  |             counter = 0 | 
					
						
							|  |  |  |             while counter < self.quota: | 
					
						
							|  |  |  |                 counter = counter + 1 | 
					
						
							|  |  |  |                 self.queue.put("%s.%d" % (self.getName(), counter)) | 
					
						
							|  |  |  |                 _sleep(random() * 0.00001) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     class ConsumerThread(Thread): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def __init__(self, queue, count): | 
					
						
							|  |  |  |             Thread.__init__(self, name="Consumer") | 
					
						
							|  |  |  |             self.queue = queue | 
					
						
							|  |  |  |             self.count = count | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def run(self): | 
					
						
							|  |  |  |             while self.count > 0: | 
					
						
							|  |  |  |                 item = self.queue.get() | 
					
						
							|  |  |  |                 print item | 
					
						
							|  |  |  |                 self.count = self.count - 1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     NP = 3 | 
					
						
							|  |  |  |     QL = 4 | 
					
						
							|  |  |  |     NI = 5 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Q = BoundedQueue(QL) | 
					
						
							|  |  |  |     P = [] | 
					
						
							|  |  |  |     for i in range(NP): | 
					
						
							|  |  |  |         t = ProducerThread(Q, NI) | 
					
						
							|  |  |  |         t.setName("Producer-%d" % (i+1)) | 
					
						
							|  |  |  |         P.append(t) | 
					
						
							|  |  |  |     C = ConsumerThread(Q, NI*NP) | 
					
						
							|  |  |  |     for t in P: | 
					
						
							|  |  |  |         t.start() | 
					
						
							|  |  |  |         _sleep(0.000001) | 
					
						
							|  |  |  |     C.start() | 
					
						
							|  |  |  |     for t in P: | 
					
						
							|  |  |  |         t.join() | 
					
						
							|  |  |  |     C.join() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | if __name__ == '__main__': | 
					
						
							|  |  |  |     _test() |