PageRenderTime 61ms CodeModel.GetById 33ms RepoModel.GetById 1ms app.codeStats 0ms

/python/Lib/test/test_thread.py

https://gitlab.com/pmuontains/Odoo
Python | 261 lines | 204 code | 42 blank | 15 comment | 38 complexity | 3bf6cfc1b5e84e86ec7862166d4fb361 MD5 | raw file
  1. import os
  2. import unittest
  3. import random
  4. from test import test_support
  5. thread = test_support.import_module('thread')
  6. import time
  7. import sys
  8. import weakref
  9. from test import lock_tests
  10. NUMTASKS = 10
  11. NUMTRIPS = 3
  12. _print_mutex = thread.allocate_lock()
  13. def verbose_print(arg):
  14. """Helper function for printing out debugging output."""
  15. if test_support.verbose:
  16. with _print_mutex:
  17. print arg
  18. class BasicThreadTest(unittest.TestCase):
  19. def setUp(self):
  20. self.done_mutex = thread.allocate_lock()
  21. self.done_mutex.acquire()
  22. self.running_mutex = thread.allocate_lock()
  23. self.random_mutex = thread.allocate_lock()
  24. self.created = 0
  25. self.running = 0
  26. self.next_ident = 0
  27. class ThreadRunningTests(BasicThreadTest):
  28. def newtask(self):
  29. with self.running_mutex:
  30. self.next_ident += 1
  31. verbose_print("creating task %s" % self.next_ident)
  32. thread.start_new_thread(self.task, (self.next_ident,))
  33. self.created += 1
  34. self.running += 1
  35. def task(self, ident):
  36. with self.random_mutex:
  37. delay = random.random() / 10000.0
  38. verbose_print("task %s will run for %sus" % (ident, round(delay*1e6)))
  39. time.sleep(delay)
  40. verbose_print("task %s done" % ident)
  41. with self.running_mutex:
  42. self.running -= 1
  43. if self.created == NUMTASKS and self.running == 0:
  44. self.done_mutex.release()
  45. def test_starting_threads(self):
  46. # Basic test for thread creation.
  47. for i in range(NUMTASKS):
  48. self.newtask()
  49. verbose_print("waiting for tasks to complete...")
  50. self.done_mutex.acquire()
  51. verbose_print("all tasks done")
  52. def test_stack_size(self):
  53. # Various stack size tests.
  54. self.assertEqual(thread.stack_size(), 0, "initial stack size is not 0")
  55. thread.stack_size(0)
  56. self.assertEqual(thread.stack_size(), 0, "stack_size not reset to default")
  57. @unittest.skipIf(os.name not in ("nt", "os2", "posix"), 'test meant for nt, os2, and posix')
  58. def test_nt_and_posix_stack_size(self):
  59. try:
  60. thread.stack_size(4096)
  61. except ValueError:
  62. verbose_print("caught expected ValueError setting "
  63. "stack_size(4096)")
  64. except thread.error:
  65. self.skipTest("platform does not support changing thread stack "
  66. "size")
  67. fail_msg = "stack_size(%d) failed - should succeed"
  68. for tss in (262144, 0x100000, 0):
  69. thread.stack_size(tss)
  70. self.assertEqual(thread.stack_size(), tss, fail_msg % tss)
  71. verbose_print("successfully set stack_size(%d)" % tss)
  72. for tss in (262144, 0x100000):
  73. verbose_print("trying stack_size = (%d)" % tss)
  74. self.next_ident = 0
  75. self.created = 0
  76. for i in range(NUMTASKS):
  77. self.newtask()
  78. verbose_print("waiting for all tasks to complete")
  79. self.done_mutex.acquire()
  80. verbose_print("all tasks done")
  81. thread.stack_size(0)
  82. def test__count(self):
  83. # Test the _count() function.
  84. orig = thread._count()
  85. mut = thread.allocate_lock()
  86. mut.acquire()
  87. started = []
  88. def task():
  89. started.append(None)
  90. mut.acquire()
  91. mut.release()
  92. thread.start_new_thread(task, ())
  93. while not started:
  94. time.sleep(0.01)
  95. self.assertEqual(thread._count(), orig + 1)
  96. # Allow the task to finish.
  97. mut.release()
  98. # The only reliable way to be sure that the thread ended from the
  99. # interpreter's point of view is to wait for the function object to be
  100. # destroyed.
  101. done = []
  102. wr = weakref.ref(task, lambda _: done.append(None))
  103. del task
  104. while not done:
  105. time.sleep(0.01)
  106. self.assertEqual(thread._count(), orig)
  107. def test_save_exception_state_on_error(self):
  108. # See issue #14474
  109. def task():
  110. started.release()
  111. raise SyntaxError
  112. def mywrite(self, *args):
  113. try:
  114. raise ValueError
  115. except ValueError:
  116. pass
  117. real_write(self, *args)
  118. c = thread._count()
  119. started = thread.allocate_lock()
  120. with test_support.captured_output("stderr") as stderr:
  121. real_write = stderr.write
  122. stderr.write = mywrite
  123. started.acquire()
  124. thread.start_new_thread(task, ())
  125. started.acquire()
  126. while thread._count() > c:
  127. time.sleep(0.01)
  128. self.assertIn("Traceback", stderr.getvalue())
  129. class Barrier:
  130. def __init__(self, num_threads):
  131. self.num_threads = num_threads
  132. self.waiting = 0
  133. self.checkin_mutex = thread.allocate_lock()
  134. self.checkout_mutex = thread.allocate_lock()
  135. self.checkout_mutex.acquire()
  136. def enter(self):
  137. self.checkin_mutex.acquire()
  138. self.waiting = self.waiting + 1
  139. if self.waiting == self.num_threads:
  140. self.waiting = self.num_threads - 1
  141. self.checkout_mutex.release()
  142. return
  143. self.checkin_mutex.release()
  144. self.checkout_mutex.acquire()
  145. self.waiting = self.waiting - 1
  146. if self.waiting == 0:
  147. self.checkin_mutex.release()
  148. return
  149. self.checkout_mutex.release()
  150. class BarrierTest(BasicThreadTest):
  151. def test_barrier(self):
  152. self.bar = Barrier(NUMTASKS)
  153. self.running = NUMTASKS
  154. for i in range(NUMTASKS):
  155. thread.start_new_thread(self.task2, (i,))
  156. verbose_print("waiting for tasks to end")
  157. self.done_mutex.acquire()
  158. verbose_print("tasks done")
  159. def task2(self, ident):
  160. for i in range(NUMTRIPS):
  161. if ident == 0:
  162. # give it a good chance to enter the next
  163. # barrier before the others are all out
  164. # of the current one
  165. delay = 0
  166. else:
  167. with self.random_mutex:
  168. delay = random.random() / 10000.0
  169. verbose_print("task %s will run for %sus" %
  170. (ident, round(delay * 1e6)))
  171. time.sleep(delay)
  172. verbose_print("task %s entering %s" % (ident, i))
  173. self.bar.enter()
  174. verbose_print("task %s leaving barrier" % ident)
  175. with self.running_mutex:
  176. self.running -= 1
  177. # Must release mutex before releasing done, else the main thread can
  178. # exit and set mutex to None as part of global teardown; then
  179. # mutex.release() raises AttributeError.
  180. finished = self.running == 0
  181. if finished:
  182. self.done_mutex.release()
  183. class LockTests(lock_tests.LockTests):
  184. locktype = thread.allocate_lock
  185. class TestForkInThread(unittest.TestCase):
  186. def setUp(self):
  187. self.read_fd, self.write_fd = os.pipe()
  188. @unittest.skipIf(sys.platform.startswith('win'),
  189. "This test is only appropriate for POSIX-like systems.")
  190. @test_support.reap_threads
  191. def test_forkinthread(self):
  192. def thread1():
  193. try:
  194. pid = os.fork() # fork in a thread
  195. except RuntimeError:
  196. sys.exit(0) # exit the child
  197. if pid == 0: # child
  198. os.close(self.read_fd)
  199. os.write(self.write_fd, "OK")
  200. sys.exit(0)
  201. else: # parent
  202. os.close(self.write_fd)
  203. thread.start_new_thread(thread1, ())
  204. self.assertEqual(os.read(self.read_fd, 2), "OK",
  205. "Unable to fork() in thread")
  206. def tearDown(self):
  207. try:
  208. os.close(self.read_fd)
  209. except OSError:
  210. pass
  211. try:
  212. os.close(self.write_fd)
  213. except OSError:
  214. pass
  215. def test_main():
  216. test_support.run_unittest(ThreadRunningTests, BarrierTest, LockTests,
  217. TestForkInThread)
  218. if __name__ == "__main__":
  219. test_main()