blob: 7c26f9e5ef00f8c0b7a2b3d80a5938b5fffd4a00 [file] [log] [blame]
Guido van Rossumad50ca92002-12-30 22:30:22 +00001"""Drop-in replacement for the thread module.
2
3Meant to be used as a brain-dead substitute so that threaded code does
4not need to be rewritten for when the thread module is not present.
5
6Suggested usage is::
Tim Peters2c60f7a2003-01-29 03:49:43 +00007
Guido van Rossumad50ca92002-12-30 22:30:22 +00008 try:
9 import thread
10 except ImportError:
11 import dummy_thread as thread
12
13"""
14__author__ = "Brett Cannon"
15__email__ = "brett@python.org"
16
17# Exports only things specified by thread documentation
18# (skipping obsolete synonyms allocate(), start_new(), exit_thread())
19__all__ = ['error', 'start_new_thread', 'exit', 'get_ident', 'allocate_lock',
Brett Cannon4e64d782003-06-13 23:44:35 +000020 'interrupt_main', 'LockType']
Guido van Rossumad50ca92002-12-30 22:30:22 +000021
22import traceback as _traceback
Andrew MacIntyre6539d2d2006-06-04 12:31:09 +000023import warnings
Guido van Rossumad50ca92002-12-30 22:30:22 +000024
25class error(Exception):
26 """Dummy implementation of thread.error."""
27
28 def __init__(self, *args):
29 self.args = args
30
31def start_new_thread(function, args, kwargs={}):
32 """Dummy implementation of thread.start_new_thread().
33
34 Compatibility is maintained by making sure that ``args`` is a
35 tuple and ``kwargs`` is a dictionary. If an exception is raised
36 and it is SystemExit (which can be done by thread.exit()) it is
37 caught and nothing is done; all other exceptions are printed out
38 by using traceback.print_exc().
39
Brett Cannon4e64d782003-06-13 23:44:35 +000040 If the executed function calls interrupt_main the KeyboardInterrupt will be
41 raised when the function returns.
42
Guido van Rossumad50ca92002-12-30 22:30:22 +000043 """
44 if type(args) != type(tuple()):
45 raise TypeError("2nd arg must be a tuple")
46 if type(kwargs) != type(dict()):
47 raise TypeError("3rd arg must be a dict")
Brett Cannon91012fe2003-06-13 23:56:32 +000048 global _main
49 _main = False
Guido van Rossumad50ca92002-12-30 22:30:22 +000050 try:
51 function(*args, **kwargs)
52 except SystemExit:
53 pass
54 except:
55 _traceback.print_exc()
Brett Cannon91012fe2003-06-13 23:56:32 +000056 _main = True
57 global _interrupt
Brett Cannon4e64d782003-06-13 23:44:35 +000058 if _interrupt:
Brett Cannon4e64d782003-06-13 23:44:35 +000059 _interrupt = False
60 raise KeyboardInterrupt
Guido van Rossumad50ca92002-12-30 22:30:22 +000061
62def exit():
63 """Dummy implementation of thread.exit()."""
64 raise SystemExit
65
66def get_ident():
67 """Dummy implementation of thread.get_ident().
68
69 Since this module should only be used when threadmodule is not
70 available, it is safe to assume that the current process is the
71 only thread. Thus a constant can be safely returned.
72 """
73 return -1
74
75def allocate_lock():
76 """Dummy implementation of thread.allocate_lock()."""
77 return LockType()
78
Andrew MacIntyre6539d2d2006-06-04 12:31:09 +000079def stack_size(size=None):
80 """Dummy implementation of thread.stack_size()."""
81 if size is not None:
82 msg = "setting thread stack size not supported on this platform"
83 warnings.warn(msg, RuntimeWarning)
84 return 0
85
Guido van Rossumad50ca92002-12-30 22:30:22 +000086class LockType(object):
87 """Class implementing dummy implementation of thread.LockType.
Tim Peters2c60f7a2003-01-29 03:49:43 +000088
Guido van Rossumad50ca92002-12-30 22:30:22 +000089 Compatibility is maintained by maintaining self.locked_status
90 which is a boolean that stores the state of the lock. Pickling of
91 the lock, though, should not be done since if the thread module is
92 then used with an unpickled ``lock()`` from here problems could
93 occur from this class not having atomic methods.
94
95 """
96
97 def __init__(self):
98 self.locked_status = False
Tim Peters2c60f7a2003-01-29 03:49:43 +000099
Guido van Rossumad50ca92002-12-30 22:30:22 +0000100 def acquire(self, waitflag=None):
101 """Dummy implementation of acquire().
102
103 For blocking calls, self.locked_status is automatically set to
104 True and returned appropriately based on value of
105 ``waitflag``. If it is non-blocking, then the value is
106 actually checked and not set if it is already acquired. This
107 is all done so that threading.Condition's assert statements
108 aren't triggered and throw a little fit.
109
110 """
111 if waitflag is None:
112 self.locked_status = True
Tim Peters2c60f7a2003-01-29 03:49:43 +0000113 return None
Guido van Rossumad50ca92002-12-30 22:30:22 +0000114 elif not waitflag:
115 if not self.locked_status:
116 self.locked_status = True
117 return True
118 else:
119 return False
120 else:
121 self.locked_status = True
Tim Peters2c60f7a2003-01-29 03:49:43 +0000122 return True
Guido van Rossumad50ca92002-12-30 22:30:22 +0000123
Phillip J. Eby849974f2006-03-27 23:32:10 +0000124 __enter__ = acquire
125
126 def __exit__(self, typ, val, tb):
127 self.release()
128
Guido van Rossumad50ca92002-12-30 22:30:22 +0000129 def release(self):
130 """Release the dummy lock."""
131 # XXX Perhaps shouldn't actually bother to test? Could lead
132 # to problems for complex, threaded code.
133 if not self.locked_status:
134 raise error
135 self.locked_status = False
136 return True
137
138 def locked(self):
139 return self.locked_status
Brett Cannon4e64d782003-06-13 23:44:35 +0000140
Brett Cannon91012fe2003-06-13 23:56:32 +0000141# Used to signal that interrupt_main was called in a "thread"
Brett Cannon4e64d782003-06-13 23:44:35 +0000142_interrupt = False
Brett Cannon91012fe2003-06-13 23:56:32 +0000143# True when not executing in a "thread"
144_main = True
Brett Cannon4e64d782003-06-13 23:44:35 +0000145
146def interrupt_main():
147 """Set _interrupt flag to True to have start_new_thread raise
148 KeyboardInterrupt upon exiting."""
Brett Cannon91012fe2003-06-13 23:56:32 +0000149 if _main:
150 raise KeyboardInterrupt
151 else:
152 global _interrupt
153 _interrupt = True