2
Thread support based on OS-level threads.
6
from pypy.interpreter.error import OperationError
7
from pypy.interpreter.gateway import NoneNotWrapped
8
from pypy.interpreter.gateway import ObjSpace, W_Root, Arguments
10
# Force the declaration of thread.start_new_thread() & co. for RPython
11
import pypy.module.thread.rpython.exttable
14
THREAD_STARTUP_LOCK = thread.allocate_lock()
20
THREAD_STARTUP_LOCK.release()
21
space.threadlocals.enter_thread(space)
25
# release ownership of these objects before we release the GIL
27
self.w_callable = None
28
# at this point the thread should only have a reference to
29
# an empty 'self'. We hold the last reference to 'self'; indeed,
30
# the parent thread already forgot about it because the above
31
# enter_thread() must have blocked until long after the call to
32
# start_new_thread() below returned.
33
# (be careful of resetting *all* local variables to None here!)
35
# clean up space.threadlocals to remove the ExecutionContext
36
# entry corresponding to the current thread
37
space.threadlocals.leave_thread(space)
41
w_callable = self.w_callable
44
space.call_args(w_callable, args)
45
except OperationError, e:
46
if not e.match(space, space.w_SystemExit):
47
ident = thread.get_ident()
48
where = 'thread %d started by ' % ident
49
e.write_unraisable(space, where, w_callable)
53
def start_new_thread(space, w_callable, w_args, w_kwargs=NoneNotWrapped):
54
"""Start a new thread and return its identifier. The thread will call the
55
function with positional arguments from the tuple args and keyword arguments
56
taken from the optional dictionary kwargs. The thread exits when the
57
function returns; the return value is ignored. The thread will also exit
58
when the function raises an unhandled exception; a stack trace will be
59
printed unless the exception is SystemExit."""
60
if not space.is_true(space.isinstance(w_args, space.w_tuple)):
61
raise OperationError(space.w_TypeError,
62
space.wrap("2nd arg must be a tuple"))
63
if w_kwargs is not None and not space.is_true(space.isinstance(w_kwargs, space.w_dict)):
64
raise OperationError(space.w_TypeError,
65
space.wrap("optional 3rd arg must be a dictionary"))
66
if not space.is_true(space.callable(w_callable)):
67
raise OperationError(space.w_TypeError,
68
space.wrap("first arg must be callable"))
70
args = Arguments.frompacked(space, w_args, w_kwargs)
73
boot.w_callable = w_callable
76
THREAD_STARTUP_LOCK.acquire(True)
78
ident = thread.start_new_thread(Bootstrapper.bootstrap, (boot,))
80
# wait until the thread has really started and acquired a reference to
82
THREAD_STARTUP_LOCK.acquire(True)
83
THREAD_STARTUP_LOCK.release()
85
return space.wrap(ident)
89
"""Return a non-zero integer that uniquely identifies the current thread
90
amongst other threads that exist simultaneously.
91
This may be used to identify per-thread resources.
92
Even though on some platforms threads identities may appear to be
93
allocated consecutive numbers starting at 1, this behavior should not
94
be relied upon, and the number should be seen purely as a magic cookie.
95
A thread's identity may be reused for another thread after it exits."""
96
ident = thread.get_ident()
97
return space.wrap(ident)