src/ldt/ldt/utils/threading_utils.py
changeset 1466 f1c220ead0d7
parent 63 93325a5d61f0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ldt/ldt/utils/threading_utils.py	Mon Dec 28 17:40:47 2015 +0100
@@ -0,0 +1,44 @@
+import ctypes
+import inspect
+import threading
+ 
+def _async_raise(tid, exctype):
+    """raises the exception, performs cleanup if needed"""
+    if not inspect.isclass(exctype):
+        raise TypeError("Only types can be raised (not instances)")
+    res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, ctypes.py_object(exctype))
+    if res == 0:
+        raise ValueError("invalid thread id")
+    elif res != 1:
+        # """if it returns a number greater than one, you're in trouble, 
+        # and you should call it again with exc=NULL to revert the effect"""
+        ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, 0)
+        raise SystemError("PyThreadState_SetAsyncExc failed")
+ 
+ 
+class Thread(threading.Thread):
+    def _get_my_tid(self):
+        """determines this (self's) thread id"""
+        if not self.isAlive():
+            raise threading.ThreadError("the thread is not active")
+ 
+        # do we have it cached?
+        if hasattr(self, "_thread_id"):
+            return self._thread_id
+ 
+        # no, look for it in the _active dict
+        for tid, tobj in threading._active.items():
+            if tobj is self:
+                self._thread_id = tid
+                return tid
+ 
+        raise AssertionError("could not determine the thread's id")
+ 
+    def raise_exc(self, exctype):
+        """raises the given exception type in the context of this thread"""
+        _async_raise(self._get_my_tid(), exctype)
+ 
+    def terminate(self):
+        """raises SystemExit in the context of the given thread, which should 
+        cause the thread to exit silently (unless caught)"""
+        self.raise_exc(SystemExit)