Add python-eventlet package to MOS 8.0 repository
[packages/trusty/python-eventlet.git] / python-eventlet / eventlet / green / thread.py
1 """Implements the standard thread module, using greenthreads."""
2 from eventlet.support.six.moves import _thread as __thread
3 from eventlet.support import greenlets as greenlet, six
4 from eventlet import greenthread
5 from eventlet.semaphore import Semaphore as LockType
6 import sys
7
8
9 __patched__ = ['get_ident', 'start_new_thread', 'start_new', 'allocate_lock',
10                'allocate', 'exit', 'interrupt_main', 'stack_size', '_local',
11                'LockType', '_count']
12
13 error = __thread.error
14 __threadcount = 0
15
16
17 if six.PY3:
18     def _set_sentinel():
19         # TODO this is a dummy code, reimplementing this may be needed:
20         # https://hg.python.org/cpython/file/b5e9bc4352e1/Modules/_threadmodule.c#l1203
21         return allocate_lock()
22
23     TIMEOUT_MAX = __thread.TIMEOUT_MAX
24
25
26 def _count():
27     return __threadcount
28
29
30 def get_ident(gr=None):
31     if gr is None:
32         return id(greenlet.getcurrent())
33     else:
34         return id(gr)
35
36
37 def __thread_body(func, args, kwargs):
38     global __threadcount
39     __threadcount += 1
40     try:
41         func(*args, **kwargs)
42     finally:
43         __threadcount -= 1
44
45
46 def start_new_thread(function, args=(), kwargs=None):
47     if (sys.version_info >= (3, 4)
48             and getattr(function, '__module__', '') == 'threading'
49             and hasattr(function, '__self__')):
50         # Since Python 3.4, threading.Thread uses an internal lock
51         # automatically released when the python thread state is deleted.
52         # With monkey patching, eventlet uses green threads without python
53         # thread state, so the lock is not automatically released.
54         #
55         # Wrap _bootstrap_inner() to release explicitly the thread state lock
56         # when the thread completes.
57         thread = function.__self__
58         bootstrap_inner = thread._bootstrap_inner
59
60         def wrap_bootstrap_inner():
61             try:
62                 bootstrap_inner()
63             finally:
64                 # The lock can be cleared (ex: by a fork())
65                 if thread._tstate_lock is not None:
66                     thread._tstate_lock.release()
67
68         thread._bootstrap_inner = wrap_bootstrap_inner
69
70     kwargs = kwargs or {}
71     g = greenthread.spawn_n(__thread_body, function, args, kwargs)
72     return get_ident(g)
73
74
75 start_new = start_new_thread
76
77
78 def allocate_lock(*a):
79     return LockType(1)
80
81
82 allocate = allocate_lock
83
84
85 def exit():
86     raise greenlet.GreenletExit
87
88
89 exit_thread = __thread.exit_thread
90
91
92 def interrupt_main():
93     curr = greenlet.getcurrent()
94     if curr.parent and not curr.parent.dead:
95         curr.parent.throw(KeyboardInterrupt())
96     else:
97         raise KeyboardInterrupt()
98
99
100 if hasattr(__thread, 'stack_size'):
101     __original_stack_size__ = __thread.stack_size
102
103     def stack_size(size=None):
104         if size is None:
105             return __original_stack_size__()
106         if size > __original_stack_size__():
107             return __original_stack_size__(size)
108         else:
109             pass
110             # not going to decrease stack_size, because otherwise other greenlets in
111             # this thread will suffer
112
113 from eventlet.corolocal import local as _local