|
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) |