blob: fb3abbf75d0f2c0cf2093a823240eba39f2bc25e [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
23
24class error(Exception):
25 """Dummy implementation of thread.error."""
26
27 def __init__(self, *args):
28 self.args = args
29
30def start_new_thread(function, args, kwargs={}):
31 """Dummy implementation of thread.start_new_thread().
32
33 Compatibility is maintained by making sure that ``args`` is a
34 tuple and ``kwargs`` is a dictionary. If an exception is raised
35 and it is SystemExit (which can be done by thread.exit()) it is
36 caught and nothing is done; all other exceptions are printed out
37 by using traceback.print_exc().
38
Brett Cannon4e64d782003-06-13 23:44:35 +000039 If the executed function calls interrupt_main the KeyboardInterrupt will be
40 raised when the function returns.
41
Guido van Rossumad50ca92002-12-30 22:30:22 +000042 """
43 if type(args) != type(tuple()):
44 raise TypeError("2nd arg must be a tuple")
45 if type(kwargs) != type(dict()):
46 raise TypeError("3rd arg must be a dict")
Brett Cannon91012fe2003-06-13 23:56:32 +000047 global _main
48 _main = False
Guido van Rossumad50ca92002-12-30 22:30:22 +000049 try:
50 function(*args, **kwargs)
51 except SystemExit:
52 pass
53 except:
54 _traceback.print_exc()
Brett Cannon91012fe2003-06-13 23:56:32 +000055 _main = True
56 global _interrupt
Brett Cannon4e64d782003-06-13 23:44:35 +000057 if _interrupt:
Brett Cannon4e64d782003-06-13 23:44:35 +000058 _interrupt = False
59 raise KeyboardInterrupt
Guido van Rossumad50ca92002-12-30 22:30:22 +000060
61def exit():
62 """Dummy implementation of thread.exit()."""
63 raise SystemExit
64
65def get_ident():
66 """Dummy implementation of thread.get_ident().
67
68 Since this module should only be used when threadmodule is not
69 available, it is safe to assume that the current process is the
70 only thread. Thus a constant can be safely returned.
71 """
72 return -1
73
74def allocate_lock():
75 """Dummy implementation of thread.allocate_lock()."""
76 return LockType()
77
78class LockType(object):
79 """Class implementing dummy implementation of thread.LockType.
Tim Peters2c60f7a2003-01-29 03:49:43 +000080
Guido van Rossumad50ca92002-12-30 22:30:22 +000081 Compatibility is maintained by maintaining self.locked_status
82 which is a boolean that stores the state of the lock. Pickling of
83 the lock, though, should not be done since if the thread module is
84 then used with an unpickled ``lock()`` from here problems could
85 occur from this class not having atomic methods.
86
87 """
88
89 def __init__(self):
90 self.locked_status = False
Tim Peters2c60f7a2003-01-29 03:49:43 +000091
Guido van Rossumad50ca92002-12-30 22:30:22 +000092 def acquire(self, waitflag=None):
93 """Dummy implementation of acquire().
94
95 For blocking calls, self.locked_status is automatically set to
96 True and returned appropriately based on value of
97 ``waitflag``. If it is non-blocking, then the value is
98 actually checked and not set if it is already acquired. This
99 is all done so that threading.Condition's assert statements
100 aren't triggered and throw a little fit.
101
102 """
103 if waitflag is None:
104 self.locked_status = True
Tim Peters2c60f7a2003-01-29 03:49:43 +0000105 return None
Guido van Rossumad50ca92002-12-30 22:30:22 +0000106 elif not waitflag:
107 if not self.locked_status:
108 self.locked_status = True
109 return True
110 else:
111 return False
112 else:
113 self.locked_status = True
Tim Peters2c60f7a2003-01-29 03:49:43 +0000114 return True
Guido van Rossumad50ca92002-12-30 22:30:22 +0000115
116 def release(self):
117 """Release the dummy lock."""
118 # XXX Perhaps shouldn't actually bother to test? Could lead
119 # to problems for complex, threaded code.
120 if not self.locked_status:
121 raise error
122 self.locked_status = False
123 return True
124
125 def locked(self):
126 return self.locked_status
Brett Cannon4e64d782003-06-13 23:44:35 +0000127
Brett Cannon91012fe2003-06-13 23:56:32 +0000128# Used to signal that interrupt_main was called in a "thread"
Brett Cannon4e64d782003-06-13 23:44:35 +0000129_interrupt = False
Brett Cannon91012fe2003-06-13 23:56:32 +0000130# True when not executing in a "thread"
131_main = True
Brett Cannon4e64d782003-06-13 23:44:35 +0000132
133def interrupt_main():
134 """Set _interrupt flag to True to have start_new_thread raise
135 KeyboardInterrupt upon exiting."""
Brett Cannon91012fe2003-06-13 23:56:32 +0000136 if _main:
137 raise KeyboardInterrupt
138 else:
139 global _interrupt
140 _interrupt = True