[pypy-commit] pypy stm-thread-2: A PyPy extension: add to thread locks a method acquire_interruptible().
arigo
noreply at buildbot.pypy.org
Thu Jan 31 18:19:49 CET 2013
Author: Armin Rigo <arigo at tunes.org>
Branch: stm-thread-2
Changeset: r60784:b2f107c5c3c5
Date: 2013-01-31 18:14 +0100
http://bitbucket.org/pypy/pypy/changeset/b2f107c5c3c5/
Log: A PyPy extension: add to thread locks a method
acquire_interruptible(). This is like acquire() but handles signals,
similarly to Python 3's acquire() method.
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
@@ -2,6 +2,7 @@
Python locks, based on true threading locks provided by the OS.
"""
+import sys
from rpython.rlib import rthread as thread
from pypy.module.thread.error import wrap_thread_error
from pypy.interpreter.baseobjspace import Wrappable
@@ -51,6 +52,23 @@
result = mylock.acquire(bool(waitflag))
return space.newbool(result)
+ def descr_lock_acquire_interruptible(self, space):
+ """Lock the lock. Unlike acquire(), this is always blocking
+but may be interrupted: signal handlers are still called, and may
+raise (e.g. a Ctrl-C will correctly raise KeyboardInterrupt).
+
+This is an extension only available on PyPy."""
+ mylock = self.lock
+ while True:
+ result = mylock.acquire_timed(-1)
+ if result == 1: # RPY_LOCK_ACQUIRED
+ return
+ assert result == 2 # RPY_LOCK_INTR
+ space.getexecutioncontext().checksignals()
+ # then retry, if the signal handler did not raise
+ assert sys.platform != 'win32', (
+ "acquire_interruptible: fix acquire_timed() on Windows")
+
def descr_lock_release(self, space):
"""Release the lock, allowing another thread that is blocked waiting for
the lock to acquire the lock. The lock must be in the locked state,
@@ -83,6 +101,7 @@
self.descr_lock_release(self.space)
descr_acquire = interp2app(Lock.descr_lock_acquire)
+descr_acquire_interruptible = interp2app(Lock.descr_lock_acquire_interruptible)
descr_release = interp2app(Lock.descr_lock_release)
descr_locked = interp2app(Lock.descr_lock_locked)
descr__enter__ = interp2app(Lock.descr__enter__)
@@ -102,6 +121,7 @@
unlock it. A thread attempting to lock a lock that it has already locked
will block until another thread unlocks it. Deadlocks may ensue.""",
acquire = descr_acquire,
+ acquire_interruptible = descr_acquire_interruptible,
release = descr_release,
locked = descr_locked,
__enter__ = descr__enter__,
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
@@ -46,6 +46,34 @@
assert feedback == [42]
assert lock.locked() is False
+ def test_acquire_interruptible(self):
+ import thread, signal, posix
+ ticks = []
+ def tick(*args):
+ ticks.append(1)
+ if len(ticks) == 3:
+ raise OverflowError
+ prev_handler = signal.signal(signal.SIGUSR1, tick)
+ #
+ lock = thread.allocate_lock()
+ lock.acquire()
+ def f():
+ self.busywait(0.25)
+ posix.kill(posix.getpid(), signal.SIGUSR1)
+ self.busywait(0.25)
+ posix.kill(posix.getpid(), signal.SIGUSR1)
+ self.busywait(0.25)
+ posix.kill(posix.getpid(), signal.SIGUSR1)
+ thread.start_new_thread(f, ())
+ try:
+ lock.acquire_interruptible()
+ raise AssertionError("should not reach here")
+ except OverflowError:
+ pass
+ assert ticks == [1, 1, 1]
+ signal.signal(signal.SIGUSR1, prev_handler)
+
+
def test_compile_lock():
from rpython.rlib import rgc
from rpython.rlib.rthread import allocate_lock
More information about the pypy-commit
mailing list