This commit is contained in:
nanwct
2022-05-19 14:55:02 +08:00
commit 8533fa17cf
29 changed files with 2467 additions and 0 deletions

65
util/thread_timeout.py Normal file
View File

@@ -0,0 +1,65 @@
from threading import Thread
import inspect
import ctypes
from functools import wraps
def _async_raise(tid, exctype):
"""raises the exception, performs cleanup if needed"""
tid = ctypes.c_long(tid)
if not inspect.isclass(exctype):
exctype = type(exctype)
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, None)
raise SystemError("PyThreadState_SetAsyncExc failed")
def stop_thread(thread):
_async_raise(thread.ident, SystemExit)
class TimeoutException(Exception):
# print("timeout!")
pass
ThreadStop = stop_thread
def time_limited(timeout):
def decorator(function):
@wraps(function)
def wrapped_function(*args, **kwargs):
class TimeLimited(Thread):
def __init__(self):
Thread.__init__(self)
self.error = None
self.result = None
def run(self):
self.result = function(*args, **kwargs)
def stop(self):
if self.is_alive():
ThreadStop(self)
t = TimeLimited()
t.start()
t.join(timeout)
if isinstance(t.error, TimeoutException):
t.stop()
raise TimeoutException('timeout for %s' % (repr(function)))
if t.is_alive():
t.stop()
raise TimeoutException('timeout for %s' % (repr(function)))
if t.error is None:
return t.result
return wrapped_function
return decorator