[pypy-commit] pypy py3k: explicitly run the signal handlers on RPY_LOCK_INTR in acquire_timed
pjenvey
noreply at buildbot.pypy.org
Wed Mar 13 03:21:27 CET 2013
Author: Philip Jenvey <pjenvey at underboss.org>
Branch: py3k
Changeset: r62327:e60b56f3fc81
Date: 2013-03-12 19:19 -0700
http://bitbucket.org/pypy/pypy/changeset/e60b56f3fc81/
Log: explicitly run the signal handlers on RPY_LOCK_INTR in acquire_timed
diff --git a/pypy/module/thread/os_lock.py b/pypy/module/thread/os_lock.py
--- a/pypy/module/thread/os_lock.py
+++ b/pypy/module/thread/os_lock.py
@@ -53,12 +53,14 @@
return microseconds
-def acquire_timed(lock, microseconds):
+def acquire_timed(space, lock, microseconds):
"""Helper to acquire an interruptible lock with a timeout."""
endtime = (time.time() * 1e6) + microseconds
while True:
result = lock.acquire_timed(microseconds)
if result == RPY_LOCK_INTR:
+ # Run signal handlers if we were interrupted
+ space.getexecutioncontext().checksignals()
if microseconds >= 0:
microseconds = r_longlong(endtime - (time.time() * 1e6))
# Check for negative values, since those mean block
@@ -89,7 +91,7 @@
and the return value reflects whether the lock is acquired.
The blocking operation is interruptible."""
microseconds = parse_acquire_args(space, blocking, timeout)
- result = acquire_timed(self.lock, microseconds)
+ result = acquire_timed(space, self.lock, microseconds)
return space.newbool(result == RPY_LOCK_ACQUIRED)
def descr_lock_release(self, space):
@@ -201,7 +203,7 @@
if self.rlock_count > 0 or not self.lock.acquire(False):
if not blocking:
return space.w_False
- r = acquire_timed(self.lock, microseconds)
+ r = acquire_timed(space, self.lock, microseconds)
r = (r == RPY_LOCK_ACQUIRED)
if r:
assert self.rlock_count == 0
diff --git a/pypy/module/thread/test/test_lock.py b/pypy/module/thread/test/test_lock.py
--- a/pypy/module/thread/test/test_lock.py
+++ b/pypy/module/thread/test/test_lock.py
@@ -1,4 +1,5 @@
from __future__ import with_statement
+import sys
from pypy.module.thread.test.support import GenericTestThread
from rpython.translator.c.test.test_genc import compile
@@ -149,6 +150,9 @@
class AppTestLockSignals(GenericTestThread):
+ def setup_class(cls):
+ cls.w_using_pthread_cond = cls.space.wrap(sys.platform == 'freebsd6')
+
def w_acquire_retries_on_intr(self, lock):
import _thread, os, signal, time
self.sig_recvd = False
@@ -186,3 +190,73 @@
def test_rlock_acquire_retries_on_intr(self):
import _thread
self.acquire_retries_on_intr(_thread.RLock())
+
+ def w_alarm_interrupt(self, sig, frame):
+ raise KeyboardInterrupt
+
+ def test_lock_acquire_interruption(self):
+ if self.using_pthread_cond:
+ skip('POSIX condition variables cannot be interrupted')
+ import _thread, signal, time
+ # Mimic receiving a SIGINT (KeyboardInterrupt) with SIGALRM while stuck
+ # in a deadlock.
+ # XXX this test can fail when the legacy (non-semaphore) implementation
+ # of locks is used in thread_pthread.h, see issue #11223.
+ oldalrm = signal.signal(signal.SIGALRM, self.alarm_interrupt)
+ try:
+ lock = _thread.allocate_lock()
+ lock.acquire()
+ signal.alarm(1)
+ t1 = time.time()
+ # XXX: raises doesn't work here?
+ #raises(KeyboardInterrupt, lock.acquire, timeout=5)
+ try:
+ lock.acquire(timeout=5)
+ except KeyboardInterrupt:
+ pass
+ else:
+ assert False, 'Expected KeyboardInterrupt'
+ dt = time.time() - t1
+ # Checking that KeyboardInterrupt was raised is not sufficient.
+ # We want to assert that lock.acquire() was interrupted because
+ # of the signal, not that the signal handler was called immediately
+ # after timeout return of lock.acquire() (which can fool assertRaises).
+ assert dt < 3.0
+ finally:
+ signal.signal(signal.SIGALRM, oldalrm)
+
+ def test_rlock_acquire_interruption(self):
+ if self.using_pthread_cond:
+ skip('POSIX condition variables cannot be interrupted')
+ import _thread, signal, time
+ # Mimic receiving a SIGINT (KeyboardInterrupt) with SIGALRM while stuck
+ # in a deadlock.
+ # XXX this test can fail when the legacy (non-semaphore) implementation
+ # of locks is used in thread_pthread.h, see issue #11223.
+ oldalrm = signal.signal(signal.SIGALRM, self.alarm_interrupt)
+ try:
+ rlock = _thread.RLock()
+ # For reentrant locks, the initial acquisition must be in another
+ # thread.
+ def other_thread():
+ rlock.acquire()
+ _thread.start_new_thread(other_thread, ())
+ # Wait until we can't acquire it without blocking...
+ while rlock.acquire(blocking=False):
+ rlock.release()
+ time.sleep(0.01)
+ signal.alarm(1)
+ t1 = time.time()
+ #raises(KeyboardInterrupt, rlock.acquire, timeout=5)
+ try:
+ rlock.acquire(timeout=5)
+ except KeyboardInterrupt:
+ pass
+ else:
+ assert False, 'Expected KeyboardInterrupt'
+ dt = time.time() - t1
+ # See rationale above in test_lock_acquire_interruption
+ assert dt < 3.0
+ finally:
+ signal.signal(signal.SIGALRM, oldalrm)
+
More information about the pypy-commit
mailing list