PageRenderTime 53ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/pypy/module/thread/test/test_lock.py

https://bitbucket.org/pypy/pypy/
Python | 207 lines | 167 code | 17 blank | 23 comment | 23 complexity | c0bcc934bb1e26cb99e4caedd45f84f5 MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. from __future__ import with_statement
  2. import py
  3. import sys, os
  4. from pypy.module.thread.test.support import GenericTestThread
  5. from rpython.translator.c.test.test_genc import compile
  6. from platform import machine
  7. class AppTestLock(GenericTestThread):
  8. def test_lock(self):
  9. import thread
  10. lock = thread.allocate_lock()
  11. assert type(lock) is thread.LockType
  12. assert lock.locked() is False
  13. raises(thread.error, lock.release)
  14. assert lock.locked() is False
  15. r = lock.acquire()
  16. assert r is True
  17. r = lock.acquire(False)
  18. assert r is False
  19. assert lock.locked() is True
  20. lock.release()
  21. assert lock.locked() is False
  22. raises(thread.error, lock.release)
  23. assert lock.locked() is False
  24. feedback = []
  25. lock.acquire()
  26. def f():
  27. self.busywait(0.25)
  28. feedback.append(42)
  29. lock.release()
  30. assert lock.locked() is True
  31. thread.start_new_thread(f, ())
  32. lock.acquire()
  33. assert lock.locked() is True
  34. assert feedback == [42]
  35. def test_lock_in_with(self):
  36. import thread
  37. lock = thread.allocate_lock()
  38. feedback = []
  39. lock.acquire()
  40. def f():
  41. self.busywait(0.25)
  42. feedback.append(42)
  43. lock.release()
  44. assert lock.locked() is True
  45. thread.start_new_thread(f, ())
  46. with lock:
  47. assert lock.locked() is True
  48. assert feedback == [42]
  49. assert lock.locked() is False
  50. def test_timeout(self):
  51. import thread
  52. lock = thread.allocate_lock()
  53. assert lock.acquire() is True
  54. assert lock.acquire(False) is False
  55. raises(TypeError, lock.acquire, True, timeout=.1)
  56. if hasattr(lock, '_py3k_acquire'):
  57. lock._py3k_acquire(True, timeout=.01)
  58. lock._py3k_acquire(True, .01)
  59. else:
  60. assert self.runappdirect, "missing lock._py3k_acquire()"
  61. def test_py3k_acquire_timeout_overflow(self):
  62. import thread
  63. lock = thread.allocate_lock()
  64. if not hasattr(lock, '_py3k_acquire'):
  65. skip("missing lock._py3k_acquire()")
  66. maxint = 2**63 - 1
  67. boundary = int(maxint * 1e-6)
  68. for i in [-100000, -10000, -1000, -100, -10, -1, 0,
  69. 1, 10, 100, 1000, 10000, 100000]:
  70. timeout = (maxint + i) * 1e-6
  71. try:
  72. lock._py3k_acquire(True, timeout=timeout)
  73. except OverflowError:
  74. got_ovf = True
  75. else:
  76. got_ovf = False
  77. lock.release()
  78. assert (i, got_ovf) == (i, int(timeout * 1e6) > maxint)
  79. @py.test.mark.xfail(machine()=='s390x', reason='may fail under heavy load')
  80. def test_ping_pong(self):
  81. # The purpose of this test is that doing a large number of ping-pongs
  82. # between two threads, using locks, should complete in a reasonable
  83. # time on a translated pypy with -A. If the GIL logic causes too
  84. # much sleeping, then it will fail.
  85. import thread, time
  86. COUNT = 100000 if self.runappdirect else 50
  87. lock1 = thread.allocate_lock()
  88. lock2 = thread.allocate_lock()
  89. def fn():
  90. for i in range(COUNT):
  91. lock1.acquire()
  92. lock2.release()
  93. lock2.acquire()
  94. print "STARTING"
  95. start = time.time()
  96. thread.start_new_thread(fn, ())
  97. for i in range(COUNT):
  98. lock2.acquire()
  99. lock1.release()
  100. stop = time.time()
  101. assert stop - start < 30.0 # ~0.6 sec on pypy-c-jit
  102. def test_compile_lock():
  103. from rpython.rlib import rgc
  104. from rpython.rlib.rthread import allocate_lock
  105. def g():
  106. l = allocate_lock()
  107. ok1 = l.acquire(True)
  108. ok2 = l.acquire(False)
  109. l.release()
  110. ok3 = l.acquire(False)
  111. res = ok1 and not ok2 and ok3
  112. return res
  113. g._dont_inline_ = True
  114. def f():
  115. res = g()
  116. # the lock must have been freed by now - we use refcounting
  117. return res
  118. fn = compile(f, [], gcpolicy='ref')
  119. res = fn()
  120. assert res
  121. class AppTestLockAgain(GenericTestThread):
  122. # test it at app-level again to detect strange interactions
  123. test_lock_again = AppTestLock.test_lock.im_func
  124. class AppTestLockSignals(GenericTestThread):
  125. pytestmark = py.test.mark.skipif("os.name != 'posix'")
  126. def w_acquire_retries_on_intr(self, lock):
  127. import thread, os, signal, time
  128. self.sig_recvd = False
  129. def my_handler(signal, frame):
  130. self.sig_recvd = True
  131. old_handler = signal.signal(signal.SIGUSR1, my_handler)
  132. try:
  133. ready = thread.allocate_lock()
  134. ready.acquire()
  135. def other_thread():
  136. # Acquire the lock in a non-main thread, so this test works for
  137. # RLocks.
  138. lock.acquire()
  139. # Notify the main thread that we're ready
  140. ready.release()
  141. # Wait for 5 seconds here
  142. for n in range(50):
  143. time.sleep(0.1)
  144. # Send the signal
  145. os.kill(os.getpid(), signal.SIGUSR1)
  146. # Let the main thread take the interrupt, handle it, and retry
  147. # the lock acquisition. Then we'll let it run.
  148. for n in range(50):
  149. time.sleep(0.1)
  150. lock.release()
  151. thread.start_new_thread(other_thread, ())
  152. ready.acquire()
  153. result = lock.acquire() # Block while we receive a signal.
  154. assert self.sig_recvd
  155. assert result
  156. finally:
  157. signal.signal(signal.SIGUSR1, old_handler)
  158. def test_lock_acquire_retries_on_intr(self):
  159. import thread
  160. self.acquire_retries_on_intr(thread.allocate_lock())
  161. def w_alarm_interrupt(self, sig, frame):
  162. raise KeyboardInterrupt
  163. def test_lock_acquire_interruption(self):
  164. import thread, signal, time
  165. # Mimic receiving a SIGINT (KeyboardInterrupt) with SIGALRM while stuck
  166. # in a deadlock.
  167. # XXX this test can fail when the legacy (non-semaphore) implementation
  168. # of locks is used in thread_pthread.h, see issue #11223.
  169. oldalrm = signal.signal(signal.SIGALRM, self.alarm_interrupt)
  170. try:
  171. lock = thread.allocate_lock()
  172. lock.acquire()
  173. signal.alarm(1)
  174. t1 = time.time()
  175. # XXX: raises doesn't work here?
  176. #raises(KeyboardInterrupt, lock.acquire, timeout=5)
  177. try:
  178. lock._py3k_acquire(timeout=10)
  179. except KeyboardInterrupt:
  180. pass
  181. else:
  182. assert False, 'Expected KeyboardInterrupt'
  183. dt = time.time() - t1
  184. # Checking that KeyboardInterrupt was raised is not sufficient.
  185. # We want to assert that lock.acquire() was interrupted because
  186. # of the signal, not that the signal handler was called immediately
  187. # after timeout return of lock.acquire() (which can fool assertRaises).
  188. assert dt < 8.0
  189. finally:
  190. signal.signal(signal.SIGALRM, oldalrm)