~ubuntu-branches/ubuntu/karmic/pypy/karmic

« back to all changes in this revision

Viewing changes to pypy/module/thread/os_thread.py

  • Committer: Bazaar Package Importer
  • Author(s): Alexandre Fayolle
  • Date: 2007-04-13 09:33:09 UTC
  • Revision ID: james.westby@ubuntu.com-20070413093309-yoojh4jcoocu2krz
Tags: upstream-1.0.0
ImportĀ upstreamĀ versionĀ 1.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
"""
 
2
Thread support based on OS-level threads.
 
3
"""
 
4
 
 
5
import thread
 
6
from pypy.interpreter.error import OperationError
 
7
from pypy.interpreter.gateway import NoneNotWrapped
 
8
from pypy.interpreter.gateway import ObjSpace, W_Root, Arguments
 
9
 
 
10
# Force the declaration of thread.start_new_thread() & co. for RPython
 
11
import pypy.module.thread.rpython.exttable
 
12
 
 
13
 
 
14
THREAD_STARTUP_LOCK = thread.allocate_lock()
 
15
 
 
16
 
 
17
class Bootstrapper:
 
18
    def bootstrap(self):
 
19
        space = self.space
 
20
        THREAD_STARTUP_LOCK.release()
 
21
        space.threadlocals.enter_thread(space)
 
22
        try:
 
23
            self.run()
 
24
        finally:
 
25
            # release ownership of these objects before we release the GIL
 
26
            self.args       = None
 
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!)
 
34
 
 
35
            # clean up space.threadlocals to remove the ExecutionContext
 
36
            # entry corresponding to the current thread
 
37
            space.threadlocals.leave_thread(space)
 
38
 
 
39
    def run(self):
 
40
        space      = self.space
 
41
        w_callable = self.w_callable
 
42
        args       = self.args
 
43
        try:
 
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)
 
50
            e.clear(space)
 
51
 
 
52
 
 
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"))
 
69
 
 
70
    args = Arguments.frompacked(space, w_args, w_kwargs)
 
71
    boot = Bootstrapper()
 
72
    boot.space      = space
 
73
    boot.w_callable = w_callable
 
74
    boot.args       = args
 
75
 
 
76
    THREAD_STARTUP_LOCK.acquire(True)
 
77
 
 
78
    ident = thread.start_new_thread(Bootstrapper.bootstrap, (boot,))
 
79
 
 
80
    # wait until the thread has really started and acquired a reference to
 
81
    # 'boot'.
 
82
    THREAD_STARTUP_LOCK.acquire(True)
 
83
    THREAD_STARTUP_LOCK.release()
 
84
 
 
85
    return space.wrap(ident)
 
86
 
 
87
 
 
88
def get_ident(space):
 
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)