PageRenderTime 34ms CodeModel.GetById 8ms RepoModel.GetById 0ms app.codeStats 0ms

/rpython/rlib/test/test_rthread.py

https://bitbucket.org/pypy/pypy/
Python | 309 lines | 252 code | 41 blank | 16 comment | 25 complexity | b3ad2c789a0cc00b61ec4e8b15ab9304 MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. import gc, time
  2. from rpython.rlib.rthread import *
  3. from rpython.rlib.rarithmetic import r_longlong
  4. from rpython.rlib import objectmodel
  5. from rpython.translator.c.test.test_boehm import AbstractGCTestClass
  6. from rpython.rtyper.lltypesystem import lltype, rffi
  7. import py
  8. import platform
  9. def test_lock():
  10. l = allocate_lock()
  11. ok1 = l.acquire(True)
  12. ok2 = l.acquire(False)
  13. l.release()
  14. ok3 = l.acquire(False)
  15. res = ok1 and not ok2 and ok3
  16. assert res == 1
  17. def test_thread_error():
  18. l = allocate_lock()
  19. try:
  20. l.release()
  21. except error:
  22. pass
  23. else:
  24. py.test.fail("Did not raise")
  25. def test_tlref_untranslated():
  26. import thread
  27. class FooBar(object):
  28. pass
  29. t = ThreadLocalReference(FooBar)
  30. results = []
  31. def subthread():
  32. x = FooBar()
  33. results.append(t.get() is None)
  34. t.set(x)
  35. results.append(t.get() is x)
  36. time.sleep(0.2)
  37. results.append(t.get() is x)
  38. for i in range(5):
  39. thread.start_new_thread(subthread, ())
  40. time.sleep(0.5)
  41. assert results == [True] * 15
  42. def test_get_ident():
  43. import thread
  44. assert get_ident() == thread.get_ident()
  45. def test_threadlocalref_on_llinterp():
  46. from rpython.rtyper.test.test_llinterp import interpret
  47. tlfield = ThreadLocalField(lltype.Signed, "rthread_test_")
  48. #
  49. def f():
  50. x = tlfield.setraw(42)
  51. return tlfield.getraw()
  52. #
  53. res = interpret(f, [])
  54. assert res == 42
  55. class AbstractThreadTests(AbstractGCTestClass):
  56. use_threads = True
  57. def test_start_new_thread(self):
  58. import time
  59. class State:
  60. pass
  61. state = State()
  62. def bootstrap1():
  63. state.my_thread_ident1 = get_ident()
  64. def bootstrap2():
  65. state.my_thread_ident2 = get_ident()
  66. def f():
  67. state.my_thread_ident1 = get_ident()
  68. state.my_thread_ident2 = get_ident()
  69. start_new_thread(bootstrap1, ())
  70. start_new_thread(bootstrap2, ())
  71. willing_to_wait_more = 1000
  72. while (state.my_thread_ident1 == get_ident() or
  73. state.my_thread_ident2 == get_ident()):
  74. willing_to_wait_more -= 1
  75. if not willing_to_wait_more:
  76. raise Exception("thread didn't start?")
  77. time.sleep(0.01)
  78. return 42
  79. fn = self.getcompiled(f, [])
  80. res = fn()
  81. assert res == 42
  82. @py.test.mark.xfail(platform.machine() == 's390x',
  83. reason='may fail this test under heavy load')
  84. def test_gc_locking(self):
  85. import time
  86. from rpython.rlib.debug import ll_assert
  87. class State:
  88. pass
  89. state = State()
  90. class Z:
  91. def __init__(self, i, j):
  92. self.i = i
  93. self.j = j
  94. def run(self):
  95. j = self.j
  96. if self.i > 1:
  97. g(self.i-1, self.j * 2)
  98. ll_assert(j == self.j, "1: bad j")
  99. g(self.i-2, self.j * 2 + 1)
  100. else:
  101. if len(state.answers) % 7 == 5:
  102. gc.collect()
  103. state.answers.append(self.j)
  104. ll_assert(j == self.j, "2: bad j")
  105. run._dont_inline_ = True
  106. def bootstrap():
  107. # after_extcall() is called before we arrive here.
  108. # We can't just acquire and release the GIL manually here,
  109. # because it is unsafe: bootstrap() is called from a rffi
  110. # callback which checks for and reports exceptions after
  111. # bootstrap() returns. The exception checking code must be
  112. # protected by the GIL too.
  113. z = state.z
  114. state.z = None
  115. state.bootstrapping.release()
  116. z.run()
  117. gc_thread_die()
  118. # before_extcall() is called after we leave here
  119. def g(i, j):
  120. state.bootstrapping.acquire(True)
  121. state.z = Z(i, j)
  122. start_new_thread(bootstrap, ())
  123. def f():
  124. state.bootstrapping = allocate_lock()
  125. state.answers = []
  126. state.finished = 0
  127. g(10, 1)
  128. done = False
  129. willing_to_wait_more = 2000
  130. while not done:
  131. if not willing_to_wait_more:
  132. break
  133. willing_to_wait_more -= 1
  134. done = len(state.answers) == expected
  135. print "waitting %d more iterations" % willing_to_wait_more
  136. time.sleep(0.01)
  137. time.sleep(0.1)
  138. return len(state.answers)
  139. expected = 89
  140. fn = self.getcompiled(f, [])
  141. answers = fn()
  142. assert answers == expected
  143. def test_acquire_timed(self):
  144. import time
  145. def f():
  146. l = allocate_lock()
  147. l.acquire(True)
  148. t1 = time.time()
  149. ok = l.acquire_timed(1000001)
  150. t2 = time.time()
  151. delay = t2 - t1
  152. if ok == 0: # RPY_LOCK_FAILURE
  153. return -delay
  154. elif ok == 2: # RPY_LOCK_INTR
  155. return delay
  156. else: # RPY_LOCK_ACQUIRED
  157. return 0.0
  158. fn = self.getcompiled(f, [])
  159. res = fn()
  160. assert res < -1.0
  161. def test_acquire_timed_huge_timeout(self):
  162. t = r_longlong(2 ** 61)
  163. def f():
  164. l = allocate_lock()
  165. return l.acquire_timed(t)
  166. fn = self.getcompiled(f, [])
  167. res = fn()
  168. assert res == 1 # RPY_LOCK_ACQUIRED
  169. def test_acquire_timed_alarm(self):
  170. import sys
  171. if not sys.platform.startswith('linux'):
  172. py.test.skip("skipped on non-linux")
  173. import time
  174. from rpython.rlib import rsignal
  175. def f():
  176. l = allocate_lock()
  177. l.acquire(True)
  178. #
  179. rsignal.pypysig_setflag(rsignal.SIGALRM)
  180. rsignal.c_alarm(1)
  181. #
  182. t1 = time.time()
  183. ok = l.acquire_timed(2500000)
  184. t2 = time.time()
  185. delay = t2 - t1
  186. if ok == 0: # RPY_LOCK_FAILURE
  187. return -delay
  188. elif ok == 2: # RPY_LOCK_INTR
  189. return delay
  190. else: # RPY_LOCK_ACQUIRED
  191. return 0.0
  192. fn = self.getcompiled(f, [])
  193. res = fn()
  194. assert res >= 0.95
  195. def test_tlref(self):
  196. class FooBar(object):
  197. pass
  198. t = ThreadLocalReference(FooBar)
  199. def f():
  200. x1 = FooBar()
  201. t.set(x1)
  202. import gc; gc.collect()
  203. assert t.get() is x1
  204. return 42
  205. fn = self.getcompiled(f, [])
  206. res = fn()
  207. assert res == 42
  208. #class TestRunDirectly(AbstractThreadTests):
  209. # def getcompiled(self, f, argtypes):
  210. # return f
  211. # These are disabled because they crash occasionally for bad reasons
  212. # related to the fact that ll2ctypes is not at all thread-safe
  213. class TestUsingBoehm(AbstractThreadTests):
  214. gcpolicy = 'boehm'
  215. class TestUsingFramework(AbstractThreadTests):
  216. gcpolicy = 'minimark'
  217. def test_tlref_keepalive(self, no__thread=True):
  218. import weakref
  219. from rpython.config.translationoption import SUPPORT__THREAD
  220. if not (SUPPORT__THREAD or no__thread):
  221. py.test.skip("no __thread support here")
  222. class FooBar(object):
  223. pass
  224. t = ThreadLocalReference(FooBar)
  225. def tset():
  226. x1 = FooBar()
  227. t.set(x1)
  228. return weakref.ref(x1)
  229. tset._dont_inline_ = True
  230. class WrFromThread:
  231. pass
  232. wr_from_thread = WrFromThread()
  233. def f():
  234. config = objectmodel.fetch_translated_config()
  235. assert t.automatic_keepalive(config) is True
  236. wr = tset()
  237. import gc; gc.collect() # 'x1' should not be collected
  238. x2 = t.get()
  239. assert x2 is not None
  240. assert wr() is not None
  241. assert wr() is x2
  242. return wr
  243. def thread_entry_point():
  244. wr = f()
  245. wr_from_thread.wr = wr
  246. wr_from_thread.seen = True
  247. def main():
  248. wr_from_thread.seen = False
  249. start_new_thread(thread_entry_point, ())
  250. wr1 = f()
  251. count = 0
  252. while True:
  253. time.sleep(0.5)
  254. if wr_from_thread.seen or count >= 50:
  255. break
  256. count += 1
  257. assert wr_from_thread.seen is True
  258. wr2 = wr_from_thread.wr
  259. import gc; gc.collect() # wr2() should be collected here
  260. assert wr1() is not None # this thread, still running
  261. assert wr2() is None # other thread, not running any more
  262. return 42
  263. extra_options = {'no__thread': no__thread, 'shared': True}
  264. fn = self.getcompiled(main, [], extra_options=extra_options)
  265. res = fn()
  266. assert res == 42
  267. def test_tlref_keepalive__thread(self):
  268. self.test_tlref_keepalive(no__thread=False)