blob: c25668d781d718dc28c8feb551e178e220444fba [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
Guido van Rossumcc544171994-04-14 20:28:41 +00009
Christian Heimesdd15f6c2008-03-16 00:07:10 +000010NUMTASKS = 10
11NUMTRIPS = 3
Guido van Rossumd3b68421994-05-23 12:17:36 +000012
Christian Heimesb186d002008-03-18 15:15:01 +000013_print_mutex = thread.allocate_lock()
14
Christian Heimesdd15f6c2008-03-16 00:07:10 +000015def verbose_print(arg):
16 """Helper function for printing out debugging output."""
Benjamin Petersonee8712c2008-05-20 21:35:26 +000017 if support.verbose:
Christian Heimesb186d002008-03-18 15:15:01 +000018 with _print_mutex:
19 print(arg)
Guido van Rossumcc544171994-04-14 20:28:41 +000020
Christian Heimesdd15f6c2008-03-16 00:07:10 +000021class BasicThreadTest(unittest.TestCase):
Guido van Rossumcc544171994-04-14 20:28:41 +000022
Christian Heimesdd15f6c2008-03-16 00:07:10 +000023 def setUp(self):
24 self.done_mutex = thread.allocate_lock()
25 self.done_mutex.acquire()
26 self.running_mutex = thread.allocate_lock()
27 self.random_mutex = thread.allocate_lock()
Antoine Pitrou97115d12009-10-23 18:34:17 +000028 self.created = 0
Christian Heimesdd15f6c2008-03-16 00:07:10 +000029 self.running = 0
30 self.next_ident = 0
Guido van Rossumcc544171994-04-14 20:28:41 +000031
Guido van Rossumd3b68421994-05-23 12:17:36 +000032
Christian Heimesdd15f6c2008-03-16 00:07:10 +000033class ThreadRunningTests(BasicThreadTest):
34
35 def newtask(self):
36 with self.running_mutex:
37 self.next_ident += 1
38 verbose_print("creating task %s" % self.next_ident)
39 thread.start_new_thread(self.task, (self.next_ident,))
Antoine Pitrou97115d12009-10-23 18:34:17 +000040 self.created += 1
Christian Heimesdd15f6c2008-03-16 00:07:10 +000041 self.running += 1
42
43 def task(self, ident):
44 with self.random_mutex:
Christian Heimesb186d002008-03-18 15:15:01 +000045 delay = random.random() / 10000.0
46 verbose_print("task %s will run for %sus" % (ident, round(delay*1e6)))
Christian Heimesdd15f6c2008-03-16 00:07:10 +000047 time.sleep(delay)
48 verbose_print("task %s done" % ident)
49 with self.running_mutex:
50 self.running -= 1
Antoine Pitrou97115d12009-10-23 18:34:17 +000051 if self.created == NUMTASKS and self.running == 0:
Christian Heimesdd15f6c2008-03-16 00:07:10 +000052 self.done_mutex.release()
53
54 def test_starting_threads(self):
55 # Basic test for thread creation.
56 for i in range(NUMTASKS):
57 self.newtask()
58 verbose_print("waiting for tasks to complete...")
59 self.done_mutex.acquire()
60 verbose_print("all tasks done")
61
62 def test_stack_size(self):
63 # Various stack size tests.
64 self.assertEquals(thread.stack_size(), 0, "intial stack size is not 0")
65
66 thread.stack_size(0)
67 self.assertEquals(thread.stack_size(), 0, "stack_size not reset to default")
68
69 if os.name not in ("nt", "os2", "posix"):
70 return
71
72 tss_supported = True
73 try:
74 thread.stack_size(4096)
75 except ValueError:
76 verbose_print("caught expected ValueError setting "
77 "stack_size(4096)")
78 except thread.error:
79 tss_supported = False
80 verbose_print("platform does not support changing thread stack "
81 "size")
82
83 if tss_supported:
84 fail_msg = "stack_size(%d) failed - should succeed"
85 for tss in (262144, 0x100000, 0):
86 thread.stack_size(tss)
87 self.assertEquals(thread.stack_size(), tss, fail_msg % tss)
88 verbose_print("successfully set stack_size(%d)" % tss)
89
90 for tss in (262144, 0x100000):
91 verbose_print("trying stack_size = (%d)" % tss)
92 self.next_ident = 0
Antoine Pitrou97115d12009-10-23 18:34:17 +000093 self.created = 0
Christian Heimesdd15f6c2008-03-16 00:07:10 +000094 for i in range(NUMTASKS):
95 self.newtask()
96
97 verbose_print("waiting for all tasks to complete")
98 self.done_mutex.acquire()
99 verbose_print("all tasks done")
100
101 thread.stack_size(0)
102
Antoine Pitrou65c9c642009-10-30 17:25:12 +0000103 def test__count(self):
104 # Test the _count() function.
105 orig = thread._count()
106 mut = thread.allocate_lock()
107 mut.acquire()
108 started = []
109 def task():
110 started.append(None)
111 mut.acquire()
112 mut.release()
113 thread.start_new_thread(task, ())
114 while not started:
115 time.sleep(0.01)
116 self.assertEquals(thread._count(), orig + 1)
117 # Allow the task to finish.
118 mut.release()
119 # The only reliable way to be sure that the thread ended from the
120 # interpreter's point of view is to wait for the function object to be
121 # destroyed.
122 done = []
123 wr = weakref.ref(task, lambda _: done.append(None))
124 del task
125 while not done:
126 time.sleep(0.01)
127 self.assertEquals(thread._count(), orig)
128
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000129
130class Barrier:
131 def __init__(self, num_threads):
132 self.num_threads = num_threads
Fred Drake004d5e62000-10-23 17:22:08 +0000133 self.waiting = 0
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000134 self.checkin_mutex = thread.allocate_lock()
135 self.checkout_mutex = thread.allocate_lock()
136 self.checkout_mutex.acquire()
Guido van Rossumd3b68421994-05-23 12:17:36 +0000137
Fred Drake004d5e62000-10-23 17:22:08 +0000138 def enter(self):
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000139 self.checkin_mutex.acquire()
Fred Drake004d5e62000-10-23 17:22:08 +0000140 self.waiting = self.waiting + 1
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000141 if self.waiting == self.num_threads:
142 self.waiting = self.num_threads - 1
143 self.checkout_mutex.release()
Fred Drake004d5e62000-10-23 17:22:08 +0000144 return
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000145 self.checkin_mutex.release()
Guido van Rossumd3b68421994-05-23 12:17:36 +0000146
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000147 self.checkout_mutex.acquire()
Fred Drake004d5e62000-10-23 17:22:08 +0000148 self.waiting = self.waiting - 1
149 if self.waiting == 0:
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000150 self.checkin_mutex.release()
Fred Drake004d5e62000-10-23 17:22:08 +0000151 return
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000152 self.checkout_mutex.release()
Guido van Rossumd3b68421994-05-23 12:17:36 +0000153
Guido van Rossumd3b68421994-05-23 12:17:36 +0000154
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000155class BarrierTest(BasicThreadTest):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000156
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000157 def test_barrier(self):
158 self.bar = Barrier(NUMTASKS)
159 self.running = NUMTASKS
160 for i in range(NUMTASKS):
161 thread.start_new_thread(self.task2, (i,))
162 verbose_print("waiting for tasks to end")
163 self.done_mutex.acquire()
164 verbose_print("tasks done")
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000165
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000166 def task2(self, ident):
167 for i in range(NUMTRIPS):
168 if ident == 0:
169 # give it a good chance to enter the next
170 # barrier before the others are all out
171 # of the current one
Christian Heimesb186d002008-03-18 15:15:01 +0000172 delay = 0
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000173 else:
174 with self.random_mutex:
Christian Heimesb186d002008-03-18 15:15:01 +0000175 delay = random.random() / 10000.0
176 verbose_print("task %s will run for %sus" %
177 (ident, round(delay * 1e6)))
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000178 time.sleep(delay)
179 verbose_print("task %s entering %s" % (ident, i))
180 self.bar.enter()
181 verbose_print("task %s leaving barrier" % ident)
182 with self.running_mutex:
183 self.running -= 1
184 # Must release mutex before releasing done, else the main thread can
185 # exit and set mutex to None as part of global teardown; then
186 # mutex.release() raises AttributeError.
187 finished = self.running == 0
188 if finished:
189 self.done_mutex.release()
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000190
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000191def test_main():
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000192 support.run_unittest(ThreadRunningTests, BarrierTest)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000193
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000194if __name__ == "__main__":
195 test_main()