1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 import ctypes
18 import inspect
19 import logging
20 import threading
21
22
23 _log = logging.getLogger(__name__)
28 """
29 Re-entrant lock that logs when it is acquired and when it is released at the
30 debug log level.
31 """
33 self.__lock = threading.RLock()
34 self._is_owned = self.__lock._is_owned
35
36
37
39 return repr(self.__lock)
40
42 _log.debug('Thread %s called acquire' % threading.current_thread())
43 if not self.__lock.acquire(blocking):
44 return False
45 _log.debug('Lock %s ACQUIRED' % repr(self))
46 return True
47
49 _log.debug('Thread %s called release' % threading.current_thread())
50 self.__lock.release()
51 _log.debug('Lock %s RELEASED' % repr(self))
52
53 __enter__ = acquire
54
57
64 """
65 Raises an exception in the threads with id tid.
66 """
67 assert inspect.isclass(exc_type)
68
69
70 long_tid = ctypes.c_long(tid)
71 exc_ptr = ctypes.py_object(exc_type)
72 num = ctypes.pythonapi.PyThreadState_SetAsyncExc(long_tid, exc_ptr)
73 if num == 1:
74 return
75 if num == 0:
76 raise ValueError('Invalid thread id')
77
78
79 null_ptr = ctypes.py_object()
80 ctypes.pythonapi.PyThreadState_SetAsyncExc(long_tid, null_ptr)
81 raise SystemError('PyThreadState_SetAsyncExc failed')
82
85 """
86 A thread class that supports raising exception in the thread from another
87 thread.
88 """
89
94
95 @property
97 """
98 Determine this thread's id.
99 """
100 if not self.is_alive():
101 raise threading.ThreadError('Thread is not active')
102
103 if hasattr(self, '_thread_id'):
104 return self._thread_id
105
106 for tid, tobj in threading._active.items():
107 if tobj is self:
108 self._thread_id = tid
109 return tid
110 raise AssertionError('Could not determine thread id')
111
113 """
114 Flag that an exception has been delivered to the thread and handled.
115 This will unblock the thread trying to deliver the exception.
116 """
117 self.__exception_event.set()
118
120 """
121 Raise and exception in this thread.
122
123 NOTE this is executed in the context of the calling thread and blocks
124 until the exception has been delivered to this thread and this thread
125 exists.
126 """
127 while not self.__exception_event.is_set():
128 try:
129 _raise_exception_in_thread(self._tid, exc_type)
130 self.__exception_event.wait(self.__default_timeout)
131 except (threading.ThreadError, AssertionError,
132 ValueError, SystemError), e:
133 _log.error('Failed to deliver exception %s to thread[%s]: %s' %
134 (exc_type.__name__, str(self.ident), e.message))
135 break
136
140 """
141 Base class for task-specific exceptions to be raised in a task thread.
142 """
143 pass
144
147 """
148 Exception to interrupt a task with a time out.
149 """
150 pass
151
154 """
155 Exception to interrupt a task with a cancellation.
156 """
157 pass
158
161 """
162 Derived task thread class that allows for task-specific interruptions.
163 """
169
175