[Python-Dev] PyThreadState_SetAsyncExc bug?
tomer filiba
tomerfiliba at gmail.com
Fri Aug 11 11:27:32 CEST 2006
opened a new bug:
http://sourceforge.net/tracker/index.php?func=detail&aid=1538556&group_id=5470&atid=105470
On 8/11/06, tomer filiba <tomerfiliba at gmail.com> wrote:
> while working on a library for raising exceptions in the context
> of another thread, i've come across a bug in PyThreadState_SetAsyncExc.
> if i raise an instance, sys.exc_info() confuses the exception value for
> the exception type, and the exception value is set None. if i raise the
> type itself, the interpreter creates an instance internally, but then i can't
> pass arguments to the exception.
>
> code:
> =====================================
> import threading
> import ctypes
>
>
> def _async_raise(tid, excobj):
> res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid,
> ctypes.py_object(excobj))
> if res == 0:
> raise ValueError("nonexistent 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")
>
> class Thread(threading.Thread):
> def raise_exc(self, excobj):
> assert self.isAlive(), "thread must be started"
> for tid, tobj in threading._active.items():
> if tobj is self:
> _async_raise(tid, excobj)
> break
>
> # the thread was alive when we entered the loop, but was not found
> # in the dict, hence it must have been already terminated.
> should we raise
> # an exception here? silently ignore?
>
> def terminate(self):
> self.raise_exc(SystemExit())
>
> if __name__ == "__main__":
> import time
> import sys
>
> i_am_active = False
>
> def f():
> global i_am_active
> i_am_active = True
> try:
> try:
> while True:
> time.sleep(0.01)
> except IOError, ex:
> print "IOError handler"
> except TypeError, ex:
> print "TypeError handler"
> print "ex=", repr(ex)
> typ, val, tb = sys.exc_info()
> print "typ=", repr(typ)
> print "val=", repr(val)
> print "tb=", tb
> finally:
> i_am_active = False
>
> t1 = Thread(target = f)
> t1.start()
> time.sleep(1)
> t1.raise_exc(TypeError("blah blah"))
> while i_am_active:
> time.sleep(0.01)
> print "!! thread terminated"
>
> output:
> =====================================
> TypeError handler
> ex= None
> typ= <exceptions.TypeError instance at 0x00C15D28> # should be the type
> val= None # should be the instance
> tb= <traceback object at 0x00C159E0>
> !! thread terminated
>
> if i change:
> t1.raise_exc(TypeError("blah blah"))
>
> to:
> t1.raise_exc(TypeError)
>
> i get:
> =====================================
> TypeError handler
> ex= <exceptions.TypeError instance at 0x00C159B8>
> typ= <class exceptions.TypeError at 0x00B945A0>
> val= <exceptions.TypeError instance at 0x00C159B8>
> tb= <traceback object at 0x00C15D00>
> !! thread terminated
>
> but then of course i can't pass arguments to the exception
>
>
>
> -tomer
>
More information about the Python-Dev
mailing list