Source code for sdt.helper.raise_in_thread
# SPDX-FileCopyrightText: 2021 Lukas Schrangl <lukas.schrangl@tuwien.ac.at>
#
# SPDX-License-Identifier: BSD-3-Clause
import ctypes
import sys
[docs]def raise_in_thread(thread_id: int, exception_type: type):
"""Raises an exception an a thread
This can be used e.g. to stop a thread
.. code-block:: python
class StopThread(Exception):
pass
def worker():
try:
# do stuff
except StopThread:
pass
th = threading.Thread(target=worker)
th.start()
# a little later…
raise_in_thread(th.ident, StopThread)
Note that the exception is not raised while ``worker()`` is running C code,
but only when it returns to Python.
Adapted from http://tomerfiliba.com/recipes/Thread2/.
Parameters
----------
thread_id
ID of the thread. See :py:func:`threading.get_ident() and
:py:attr:`threading.Thread.ident`.
exception_type
Type of the exception to raise. Note that this should be a type, not
an instance.
"""
if sys.version_info.major >= 3 and sys.version_info.minor >= 7:
c_id = ctypes.c_ulong(thread_id)
else:
c_id = ctypes.c_long(thread_id)
c_exc = ctypes.py_object(exception_type)
n_threads = ctypes.pythonapi.PyThreadState_SetAsyncExc(c_id, c_exc)
if n_threads == 0:
raise ValueError("`thread_id` invalid")
if n_threads > 1:
# This should not happen. Try to undo previous call by using None as
# `exc` argument
ctypes.pythonapi.PyThreadState_SetAsyncExc(c_id, None)
raise SystemError(f"failed to raise {exception_type} in thread "
f"{thread_id}")