|
22
|
1 |
import threading |
|
|
2 |
import inspect |
|
|
3 |
import ctypes |
|
|
4 |
|
|
|
5 |
def _async_raise(tid, exctype): |
|
|
6 |
"""raises the exception, performs cleanup if needed""" |
|
|
7 |
if not inspect.isclass(exctype): |
|
|
8 |
raise TypeError("Only types can be raised (not instances)") |
|
|
9 |
res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, ctypes.py_object(exctype)) |
|
|
10 |
if res == 0: |
|
|
11 |
raise ValueError("invalid thread id") |
|
|
12 |
elif res != 1: |
|
|
13 |
# """if it returns a number greater than one, you're in trouble, |
|
|
14 |
# and you should call it again with exc=NULL to revert the effect""" |
|
|
15 |
ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, 0) |
|
|
16 |
raise SystemError("PyThreadState_SetAsyncExc failed") |
|
|
17 |
|
|
|
18 |
|
|
|
19 |
class Thread(threading.Thread): |
|
|
20 |
def _get_my_tid(self): |
|
|
21 |
"""determines this (self's) thread id""" |
|
|
22 |
if not self.isAlive(): |
|
|
23 |
raise threading.ThreadError("the thread is not active") |
|
|
24 |
|
|
|
25 |
# do we have it cached? |
|
|
26 |
if hasattr(self, "_thread_id"): |
|
|
27 |
return self._thread_id |
|
|
28 |
|
|
|
29 |
# no, look for it in the _active dict |
|
|
30 |
for tid, tobj in threading._active.items(): |
|
|
31 |
if tobj is self: |
|
|
32 |
self._thread_id = tid |
|
|
33 |
return tid |
|
|
34 |
|
|
|
35 |
raise AssertionError("could not determine the thread's id") |
|
|
36 |
|
|
|
37 |
def raise_exc(self, exctype): |
|
|
38 |
"""raises the given exception type in the context of this thread""" |
|
|
39 |
_async_raise(self._get_my_tid(), exctype) |
|
|
40 |
|
|
|
41 |
def terminate(self): |
|
|
42 |
"""raises SystemExit in the context of the given thread, which should |
|
|
43 |
cause the thread to exit silently (unless caught)""" |
|
|
44 |
self.raise_exc(SystemExit) |