blob: 70d89fe41d61972e67e52f5da5727c86c1538141 [file] [log] [blame]
Christian Heimesdd15f6c2008-03-16 00:07:10 +00001import os
2import unittest
Guido van Rossumb26a1b41998-05-20 17:05:52 +00003import random
Benjamin Petersonee8712c2008-05-20 21:35:26 +00004from test import support
Georg Brandl2067bfd2008-05-25 13:05:15 +00005import _thread as thread
Guido van Rossumcc544171994-04-14 20:28:41 +00006import time
Antoine Pitrou65c9c642009-10-30 17:25:12 +00007import weakref
Guido van Rossumcc544171994-04-14 20:28:41 +00008
Antoine Pitrou557934f2009-11-06 22:41:14 +00009from test import lock_tests
Guido van Rossumcc544171994-04-14 20:28:41 +000010
Christian Heimesdd15f6c2008-03-16 00:07:10 +000011NUMTASKS = 10
12NUMTRIPS = 3
Guido van Rossumd3b68421994-05-23 12:17:36 +000013
Christian Heimesb186d002008-03-18 15:15:01 +000014_print_mutex = thread.allocate_lock()
15
Christian Heimesdd15f6c2008-03-16 00:07:10 +000016def verbose_print(arg):
17 """Helper function for printing out debugging output."""
Benjamin Petersonee8712c2008-05-20 21:35:26 +000018 if support.verbose:
Christian Heimesb186d002008-03-18 15:15:01 +000019 with _print_mutex:
20 print(arg)
Guido van Rossumcc544171994-04-14 20:28:41 +000021
Christian Heimesdd15f6c2008-03-16 00:07:10 +000022class BasicThreadTest(unittest.TestCase):
Guido van Rossumcc544171994-04-14 20:28:41 +000023
Christian Heimesdd15f6c2008-03-16 00:07:10 +000024 def setUp(self):
25 self.done_mutex = thread.allocate_lock()
26 self.done_mutex.acquire()
27 self.running_mutex = thread.allocate_lock()
28 self.random_mutex = thread.allocate_lock()
Antoine Pitrou97115d12009-10-23 18:34:17 +000029 self.created = 0
Christian Heimesdd15f6c2008-03-16 00:07:10 +000030 self.running = 0
31 self.next_ident = 0
Guido van Rossumcc544171994-04-14 20:28:41 +000032
Guido van Rossumd3b68421994-05-23 12:17:36 +000033
Christian Heimesdd15f6c2008-03-16 00:07:10 +000034class ThreadRunningTests(BasicThreadTest):
35
36 def newtask(self):
37 with self.running_mutex:
38 self.next_ident += 1
39 verbose_print("creating task %s" % self.next_ident)
40 thread.start_new_thread(self.task, (self.next_ident,))
Antoine Pitrou97115d12009-10-23 18:34:17 +000041 self.created += 1
Christian Heimesdd15f6c2008-03-16 00:07:10 +000042 self.running += 1
43
44 def task(self, ident):
45 with self.random_mutex:
Christian Heimesb186d002008-03-18 15:15:01 +000046 delay = random.random() / 10000.0
47 verbose_print("task %s will run for %sus" % (ident, round(delay*1e6)))
Christian Heimesdd15f6c2008-03-16 00:07:10 +000048 time.sleep(delay)
49 verbose_print("task %s done" % ident)
50 with self.running_mutex:
51 self.running -= 1
Antoine Pitrou97115d12009-10-23 18:34:17 +000052 if self.created == NUMTASKS and self.running == 0:
Christian Heimesdd15f6c2008-03-16 00:07:10 +000053 self.done_mutex.release()
54
55 def test_starting_threads(self):
56 # Basic test for thread creation.
57 for i in range(NUMTASKS):
58 self.newtask()
59 verbose_print("waiting for tasks to complete...")
60 self.done_mutex.acquire()
61 verbose_print("all tasks done")
62
63 def test_stack_size(self):
64 # Various stack size tests.
65 self.assertEquals(thread.stack_size(), 0, "intial stack size is not 0")
66
67 thread.stack_size(0)
68 self.assertEquals(thread.stack_size(), 0, "stack_size not reset to default")
69
70 if os.name not in ("nt", "os2", "posix"):
71 return
72
73 tss_supported = True
74 try:
75 thread.stack_size(4096)
76 except ValueError:
77 verbose_print("caught expected ValueError setting "
78 "stack_size(4096)")
79 except thread.error:
80 tss_supported = False
81 verbose_print("platform does not support changing thread stack "
82 "size")
83
84 if tss_supported:
85 fail_msg = "stack_size(%d) failed - should succeed"
86 for tss in (262144, 0x100000, 0):
87 thread.stack_size(tss)
88 self.assertEquals(thread.stack_size(), tss, fail_msg % tss)
89 verbose_print("successfully set stack_size(%d)" % tss)
90
91 for tss in (262144, 0x100000):
92 verbose_print("trying stack_size = (%d)" % tss)
93 self.next_ident = 0
Antoine Pitrou97115d12009-10-23 18:34:17 +000094 self.created = 0
Christian Heimesdd15f6c2008-03-16 00:07:10 +000095 for i in range(NUMTASKS):
96 self.newtask()
97
98 verbose_print("waiting for all tasks to complete")
99 self.done_mutex.acquire()
100 verbose_print("all tasks done")
101
102 thread.stack_size(0)
103
Antoine Pitrou65c9c642009-10-30 17:25:12 +0000104 def test__count(self):
105 # Test the _count() function.
106 orig = thread._count()
107 mut = thread.allocate_lock()
108 mut.acquire()
109 started = []
110 def task():
111 started.append(None)
112 mut.acquire()
113 mut.release()
114 thread.start_new_thread(task, ())
115 while not started:
116 time.sleep(0.01)
117 self.assertEquals(thread._count(), orig + 1)
118 # Allow the task to finish.
119 mut.release()
120 # The only reliable way to be sure that the thread ended from the
121 # interpreter's point of view is to wait for the function object to be
122 # destroyed.
123 done = []
124 wr = weakref.ref(task, lambda _: done.append(None))
125 del task
126 while not done:
127 time.sleep(0.01)
128 self.assertEquals(thread._count(), orig)
129
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000130
131class Barrier:
132 def __init__(self, num_threads):
133 self.num_threads = num_threads
Fred Drake004d5e62000-10-23 17:22:08 +0000134 self.waiting = 0
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000135 self.checkin_mutex = thread.allocate_lock()
136 self.checkout_mutex = thread.allocate_lock()
137 self.checkout_mutex.acquire()
Guido van Rossumd3b68421994-05-23 12:17:36 +0000138
Fred Drake004d5e62000-10-23 17:22:08 +0000139 def enter(self):
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000140 self.checkin_mutex.acquire()
Fred Drake004d5e62000-10-23 17:22:08 +0000141 self.waiting = self.waiting + 1
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000142 if self.waiting == self.num_threads:
143 self.waiting = self.num_threads - 1
144 self.checkout_mutex.release()
Fred Drake004d5e62000-10-23 17:22:08 +0000145 return
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000146 self.checkin_mutex.release()
Guido van Rossumd3b68421994-05-23 12:17:36 +0000147
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000148 self.checkout_mutex.acquire()
Fred Drake004d5e62000-10-23 17:22:08 +0000149 self.waiting = self.waiting - 1
150 if self.waiting == 0:
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000151 self.checkin_mutex.release()
Fred Drake004d5e62000-10-23 17:22:08 +0000152 return
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000153 self.checkout_mutex.release()
Guido van Rossumd3b68421994-05-23 12:17:36 +0000154
Guido van Rossumd3b68421994-05-23 12:17:36 +0000155
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000156class BarrierTest(BasicThreadTest):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000157
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000158 def test_barrier(self):
159 self.bar = Barrier(NUMTASKS)
160 self.running = NUMTASKS
161 for i in range(NUMTASKS):
162 thread.start_new_thread(self.task2, (i,))
163 verbose_print("waiting for tasks to end")
164 self.done_mutex.acquire()
165 verbose_print("tasks done")
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000166
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000167 def task2(self, ident):
168 for i in range(NUMTRIPS):
169 if ident == 0:
170 # give it a good chance to enter the next
171 # barrier before the others are all out
172 # of the current one
Christian Heimesb186d002008-03-18 15:15:01 +0000173 delay = 0
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000174 else:
175 with self.random_mutex:
Christian Heimesb186d002008-03-18 15:15:01 +0000176 delay = random.random() / 10000.0
177 verbose_print("task %s will run for %sus" %
178 (ident, round(delay * 1e6)))
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000179 time.sleep(delay)
180 verbose_print("task %s entering %s" % (ident, i))
181 self.bar.enter()
182 verbose_print("task %s leaving barrier" % ident)
183 with self.running_mutex:
184 self.running -= 1
185 # Must release mutex before releasing done, else the main thread can
186 # exit and set mutex to None as part of global teardown; then
187 # mutex.release() raises AttributeError.
188 finished = self.running == 0
189 if finished:
190 self.done_mutex.release()
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000191
Antoine Pitrou557934f2009-11-06 22:41:14 +0000192class LockTests(lock_tests.LockTests):
193 locktype = thread.allocate_lock
194
195
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000196def test_main():
Antoine Pitrou557934f2009-11-06 22:41:14 +0000197 support.run_unittest(ThreadRunningTests, BarrierTest, LockTests)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000198
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000199if __name__ == "__main__":
200 test_main()