blob: 16dcf7e9a2c69de7a5e186f07f424946d3263431 [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"""
Brett Cannon9875ba42007-01-25 23:30:39 +000014# Exports only things specified by thread documentation;
15# skipping obsolete synonyms allocate(), start_new(), exit_thread().
Guido van Rossumad50ca92002-12-30 22:30:22 +000016__all__ = ['error', 'start_new_thread', 'exit', 'get_ident', 'allocate_lock',
Brett Cannon4e64d782003-06-13 23:44:35 +000017 'interrupt_main', 'LockType']
Guido van Rossumad50ca92002-12-30 22:30:22 +000018
19import traceback as _traceback
Andrew MacIntyre92913322006-06-13 15:04:24 +000020import warnings
Guido van Rossumad50ca92002-12-30 22:30:22 +000021
22class error(Exception):
23 """Dummy implementation of thread.error."""
24
25 def __init__(self, *args):
26 self.args = args
27
28def start_new_thread(function, args, kwargs={}):
29 """Dummy implementation of thread.start_new_thread().
30
31 Compatibility is maintained by making sure that ``args`` is a
32 tuple and ``kwargs`` is a dictionary. If an exception is raised
33 and it is SystemExit (which can be done by thread.exit()) it is
34 caught and nothing is done; all other exceptions are printed out
35 by using traceback.print_exc().
36
Brett Cannon4e64d782003-06-13 23:44:35 +000037 If the executed function calls interrupt_main the KeyboardInterrupt will be
38 raised when the function returns.
39
Guido van Rossumad50ca92002-12-30 22:30:22 +000040 """
41 if type(args) != type(tuple()):
42 raise TypeError("2nd arg must be a tuple")
43 if type(kwargs) != type(dict()):
44 raise TypeError("3rd arg must be a dict")
Brett Cannon91012fe2003-06-13 23:56:32 +000045 global _main
46 _main = False
Guido van Rossumad50ca92002-12-30 22:30:22 +000047 try:
48 function(*args, **kwargs)
49 except SystemExit:
50 pass
51 except:
52 _traceback.print_exc()
Brett Cannon91012fe2003-06-13 23:56:32 +000053 _main = True
54 global _interrupt
Brett Cannon4e64d782003-06-13 23:44:35 +000055 if _interrupt:
Brett Cannon4e64d782003-06-13 23:44:35 +000056 _interrupt = False
57 raise KeyboardInterrupt
Guido van Rossumad50ca92002-12-30 22:30:22 +000058
59def exit():
60 """Dummy implementation of thread.exit()."""
61 raise SystemExit
62
63def get_ident():
64 """Dummy implementation of thread.get_ident().
65
66 Since this module should only be used when threadmodule is not
67 available, it is safe to assume that the current process is the
68 only thread. Thus a constant can be safely returned.
69 """
70 return -1
71
72def allocate_lock():
73 """Dummy implementation of thread.allocate_lock()."""
74 return LockType()
75
Andrew MacIntyre92913322006-06-13 15:04:24 +000076def stack_size(size=None):
77 """Dummy implementation of thread.stack_size()."""
78 if size is not None:
Andrew MacIntyrea7090df2006-06-13 17:14:36 +000079 raise error("setting thread stack size not supported")
Andrew MacIntyre92913322006-06-13 15:04:24 +000080 return 0
81
Guido van Rossumad50ca92002-12-30 22:30:22 +000082class LockType(object):
83 """Class implementing dummy implementation of thread.LockType.
Tim Peters2c60f7a2003-01-29 03:49:43 +000084
Guido van Rossumad50ca92002-12-30 22:30:22 +000085 Compatibility is maintained by maintaining self.locked_status
86 which is a boolean that stores the state of the lock. Pickling of
87 the lock, though, should not be done since if the thread module is
88 then used with an unpickled ``lock()`` from here problems could
89 occur from this class not having atomic methods.
90
91 """
92
93 def __init__(self):
94 self.locked_status = False
Tim Peters2c60f7a2003-01-29 03:49:43 +000095
Guido van Rossumad50ca92002-12-30 22:30:22 +000096 def acquire(self, waitflag=None):
97 """Dummy implementation of acquire().
98
99 For blocking calls, self.locked_status is automatically set to
100 True and returned appropriately based on value of
101 ``waitflag``. If it is non-blocking, then the value is
102 actually checked and not set if it is already acquired. This
103 is all done so that threading.Condition's assert statements
104 aren't triggered and throw a little fit.
105
106 """
Brett Cannon3d0b9f02008-07-13 01:15:07 +0000107 if waitflag is None or waitflag:
Guido van Rossumad50ca92002-12-30 22:30:22 +0000108 self.locked_status = True
Brett Cannon3d0b9f02008-07-13 01:15:07 +0000109 return True
110 else:
Guido van Rossumad50ca92002-12-30 22:30:22 +0000111 if not self.locked_status:
112 self.locked_status = True
113 return True
114 else:
115 return False
Guido van Rossumad50ca92002-12-30 22:30:22 +0000116
Phillip J. Eby849974f2006-03-27 23:32:10 +0000117 __enter__ = acquire
118
119 def __exit__(self, typ, val, tb):
120 self.release()
121
Guido van Rossumad50ca92002-12-30 22:30:22 +0000122 def release(self):
123 """Release the dummy lock."""
124 # XXX Perhaps shouldn't actually bother to test? Could lead
125 # to problems for complex, threaded code.
126 if not self.locked_status:
127 raise error
128 self.locked_status = False
129 return True
130
131 def locked(self):
132 return self.locked_status
Brett Cannon4e64d782003-06-13 23:44:35 +0000133
Brett Cannon91012fe2003-06-13 23:56:32 +0000134# Used to signal that interrupt_main was called in a "thread"
Brett Cannon4e64d782003-06-13 23:44:35 +0000135_interrupt = False
Brett Cannon91012fe2003-06-13 23:56:32 +0000136# True when not executing in a "thread"
137_main = True
Brett Cannon4e64d782003-06-13 23:44:35 +0000138
139def interrupt_main():
140 """Set _interrupt flag to True to have start_new_thread raise
141 KeyboardInterrupt upon exiting."""
Brett Cannon91012fe2003-06-13 23:56:32 +0000142 if _main:
143 raise KeyboardInterrupt
144 else:
145 global _interrupt
146 _interrupt = True