[pypy-commit] pypy stm-thread-2: Preparing for the merge of default
arigo
noreply at buildbot.pypy.org
Thu Jan 31 12:46:12 CET 2013
Author: Armin Rigo <arigo at tunes.org>
Branch: stm-thread-2
Changeset: r60763:131909e488a9
Date: 2013-01-31 12:20 +0100
http://bitbucket.org/pypy/pypy/changeset/131909e488a9/
Log: Preparing for the merge of default
diff --git a/pypy/module/signal/__init__.py b/pypy/module/signal/__init__.py
--- a/pypy/module/signal/__init__.py
+++ b/pypy/module/signal/__init__.py
@@ -30,7 +30,8 @@
}
def buildloaders(cls):
- from pypy.rlib import rsignal
+ from rpython.rlib import rsignal
+
for name in rsignal.signal_names:
signum = getattr(rsignal, name)
if signum is not None:
diff --git a/pypy/module/signal/interp_signal.py b/pypy/module/signal/interp_signal.py
--- a/pypy/module/signal/interp_signal.py
+++ b/pypy/module/signal/interp_signal.py
@@ -1,20 +1,21 @@
from __future__ import with_statement
import signal as cpy_signal
+import sys
from pypy.interpreter.error import OperationError, exception_from_errno
from pypy.interpreter.executioncontext import (AsyncAction, AbstractActionFlag,
PeriodicAsyncAction)
from pypy.interpreter.gateway import unwrap_spec
-from pypy.rlib import jit, rposix
-from pypy.rlib.rarithmetic import intmask
-from pypy.rlib.rsignal import (pypysig_getaddr_occurred, pypysig_setflag,
- pypysig_poll, pypysig_reinstall, pypysig_ignore, pypysig_default,
- pypysig_set_wakeup_fd, c_alarm, c_pause, c_getitimer, c_setitimer,
- c_siginterrupt, itimervalP, NSIG, SIG_DFL, SIG_IGN, ITIMER_REAL,
- ITIMER_PROF, ITIMER_VIRTUAL, signal_values)
-from pypy.rpython.lltypesystem import lltype, rffi
+from rpython.rlib import jit, rposix, rgc
+from rpython.rlib.objectmodel import we_are_translated
+from rpython.rlib.rarithmetic import intmask
+from rpython.rlib.rsignal import *
+from rpython.rtyper.lltypesystem import lltype, rffi
+
+
+WIN32 = sys.platform == 'win32'
class SignalActionFlag(AbstractActionFlag):
@@ -31,6 +32,11 @@
p = pypysig_getaddr_occurred()
p.c_value = value
+ @staticmethod
+ def rearm_ticker():
+ p = pypysig_getaddr_occurred()
+ p.c_value = -1
+
def decrement_ticker(self, by):
p = pypysig_getaddr_occurred()
value = p.c_value
@@ -46,41 +52,63 @@
class CheckSignalAction(PeriodicAsyncAction):
"""An action that is automatically invoked when a signal is received."""
+ # Note that this is a PeriodicAsyncAction: it means more precisely
+ # that it is called whenever the C-level ticker becomes < 0.
+ # Without threads, it is only ever set to -1 when we receive a
+ # signal. With threads, it also decrements steadily (but slowly).
+
def __init__(self, space):
+ "NOT_RPYTHON"
AsyncAction.__init__(self, space)
self.handlers_w = {}
- self.emulated_sigint = False
+ self.pending_signal = -1
+ self.fire_in_main_thread = False
+ if self.space.config.objspace.usemodules.thread:
+ from pypy.module.thread import gil
+ gil.after_thread_switch = self._after_thread_switch
+
+ @rgc.no_collect
+ def _after_thread_switch(self):
+ if self.fire_in_main_thread:
+ if self.space.threadlocals.ismainthread():
+ self.fire_in_main_thread = False
+ SignalActionFlag.rearm_ticker()
+ # this occurs when we just switched to the main thread
+ # and there is a signal pending: we force the ticker to
+ # -1, which should ensure perform() is called quickly.
@jit.dont_look_inside
def perform(self, executioncontext, frame):
- if self.space.config.objspace.usemodules.thread:
- main_ec = self.space.threadlocals.getmainthreadvalue()
- in_main = executioncontext is main_ec
- else:
- in_main = True
- # If we are in the main thread, poll and report the signals now.
- if in_main:
- if self.emulated_sigint:
- self.emulated_sigint = False
- self._report_signal(cpy_signal.SIGINT)
- while True:
- n = pypysig_poll()
- if n < 0:
- break
+ # Poll for the next signal, if any
+ n = self.pending_signal
+ if n < 0: n = pypysig_poll()
+ while n >= 0:
+ if self.space.config.objspace.usemodules.thread:
+ in_main = self.space.threadlocals.ismainthread()
+ else:
+ in_main = True
+ if in_main:
+ # If we are in the main thread, report the signal now,
+ # and poll more
+ self.pending_signal = -1
self._report_signal(n)
- else:
- # Otherwise, don't call pypysig_poll() at all. Instead,
- # arrange for perform() to be called again after a thread
- # switch. It might be called again and again, until we
- # land in the main thread.
- self.fire_after_thread_switch()
+ n = self.pending_signal
+ if n < 0: n = pypysig_poll()
+ else:
+ # Otherwise, arrange for perform() to be called again
+ # after we switch to the main thread.
+ self.pending_signal = n
+ self.fire_in_main_thread = True
+ break
- @jit.dont_look_inside
def set_interrupt(self):
"Simulates the effect of a SIGINT signal arriving"
- ec = self.space.getexecutioncontext()
- self.emulated_sigint = True
- self.perform(ec, None)
+ if not we_are_translated():
+ self.pending_signal = cpy_signal.SIGINT
+ # ^^^ may override another signal, but it's just for testing
+ else:
+ pypysig_pushback(cpy_signal.SIGINT)
+ self.fire_in_main_thread = True
def _report_signal(self, n):
try:
@@ -109,12 +137,16 @@
None -- if an unknown handler is in effect (XXX UNIMPLEMENTED)
anything else -- the callable Python object used as a handler
"""
- check_signum_in_range(space, signum)
+ if WIN32:
+ check_signum_exists(space, signum)
+ else:
+ check_signum_in_range(space, signum)
action = space.check_signal_action
if signum in action.handlers_w:
return action.handlers_w[signum]
return space.wrap(SIG_DFL)
+
def default_int_handler(space, w_signum, w_frame):
"""
default_int_handler(...)
@@ -125,22 +157,26 @@
raise OperationError(space.w_KeyboardInterrupt,
space.w_None)
+
@jit.dont_look_inside
@unwrap_spec(timeout=int)
def alarm(space, timeout):
return space.wrap(c_alarm(timeout))
+
@jit.dont_look_inside
def pause(space):
c_pause()
return space.w_None
+
def check_signum_exists(space, signum):
if signum in signal_values:
return
raise OperationError(space.w_ValueError,
space.wrap("invalid signal value"))
+
def check_signum_in_range(space, signum):
if 1 <= signum < NSIG:
return
@@ -162,7 +198,7 @@
A signal handler function is called with two arguments:
the first is the signal number, the second is the interrupted stack frame.
"""
- ec = space.getexecutioncontext()
+ ec = space.getexecutioncontext()
main_ec = space.threadlocals.getmainthreadvalue()
old_handler = getsignal(space, signum)
@@ -185,13 +221,14 @@
action.handlers_w[signum] = w_handler
return old_handler
+
@jit.dont_look_inside
@unwrap_spec(fd=int)
def set_wakeup_fd(space, fd):
"""Sets the fd to be written to (with '\0') when a signal
comes in. Returns the old fd. A library can use this to
wakeup select or poll. The previous fd is returned.
-
+
The fd must be non-blocking.
"""
if space.config.objspace.usemodules.thread:
@@ -204,6 +241,7 @@
old_fd = pypysig_set_wakeup_fd(fd)
return space.wrap(intmask(old_fd))
+
@jit.dont_look_inside
@unwrap_spec(signum=int, flag=int)
def siginterrupt(space, signum, flag):
@@ -219,33 +257,38 @@
rffi.setintfield(timeval, 'c_tv_sec', int(d))
rffi.setintfield(timeval, 'c_tv_usec', int((d - int(d)) * 1000000))
+
def double_from_timeval(tv):
return rffi.getintfield(tv, 'c_tv_sec') + (
rffi.getintfield(tv, 'c_tv_usec') / 1000000.0)
+
def itimer_retval(space, val):
w_value = space.wrap(double_from_timeval(val.c_it_value))
w_interval = space.wrap(double_from_timeval(val.c_it_interval))
return space.newtuple([w_value, w_interval])
+
class Cache:
def __init__(self, space):
self.w_itimererror = space.new_exception_class("signal.ItimerError",
space.w_IOError)
+
def get_itimer_error(space):
return space.fromcache(Cache).w_itimererror
+
@jit.dont_look_inside
@unwrap_spec(which=int, first=float, interval=float)
def setitimer(space, which, first, interval=0):
"""setitimer(which, seconds[, interval])
-
Sets given itimer (one of ITIMER_REAL, ITIMER_VIRTUAL
+
or ITIMER_PROF) to fire after value seconds and after
that every interval seconds.
The itimer can be cleared by setting seconds to zero.
-
+
Returns old values as a tuple: (delay, interval).
"""
with lltype.scoped_alloc(itimervalP.TO, 1) as new:
@@ -259,14 +302,14 @@
if ret != 0:
raise exception_from_errno(space, get_itimer_error(space))
+ return itimer_retval(space, old[0])
- return itimer_retval(space, old[0])
@jit.dont_look_inside
@unwrap_spec(which=int)
def getitimer(space, which):
"""getitimer(which)
-
+
Returns current value of given itimer.
"""
with lltype.scoped_alloc(itimervalP.TO, 1) as old:
diff --git a/pypy/module/signal/test/test_interp_signal.py b/pypy/module/signal/test/test_interp_signal.py
deleted file mode 100644
--- a/pypy/module/signal/test/test_interp_signal.py
+++ /dev/null
@@ -1,39 +0,0 @@
-import os, py
-from pypy.translator.c.test.test_genc import compile
-from pypy.module.signal import interp_signal
-
-def setup_module(mod):
- if not hasattr(os, 'kill') or not hasattr(os, 'getpid'):
- py.test.skip("requires os.kill() and os.getpid()")
- if not hasattr(interp_signal, 'SIGUSR1'):
- py.test.skip("requires SIGUSR1 in signal")
-
-
-def check(expected):
- res = interp_signal.pypysig_poll()
- os.write(1, "poll() => %d, expected %d\n" % (res, expected))
- assert res == expected
-
-def test_simple():
- import os
- check(-1)
- check(-1)
- for i in range(3):
- interp_signal.pypysig_setflag(interp_signal.SIGUSR1)
- os.kill(os.getpid(), interp_signal.SIGUSR1)
- check(interp_signal.SIGUSR1)
- check(-1)
- check(-1)
-
- interp_signal.pypysig_ignore(interp_signal.SIGUSR1)
- os.kill(os.getpid(), interp_signal.SIGUSR1)
- check(-1)
- check(-1)
-
- interp_signal.pypysig_default(interp_signal.SIGUSR1)
- check(-1)
-
-
-def test_compile():
- fn = compile(test_simple, [])
- fn()
diff --git a/pypy/module/signal/test/test_signal.py b/pypy/module/signal/test/test_signal.py
--- a/pypy/module/signal/test/test_signal.py
+++ b/pypy/module/signal/test/test_signal.py
@@ -36,7 +36,7 @@
class AppTestSignal:
spaceconfig = {
- "usemodules": ['signal', 'rctime'],
+ "usemodules": ['signal', 'rctime'] + (['fcntl'] if os.name != 'nt' else []),
}
def setup_class(cls):
@@ -55,7 +55,7 @@
skip("requires os.kill() and os.getpid()")
signal = self.signal # the signal module to test
if not hasattr(signal, 'SIGUSR1'):
- py.test.skip("requires SIGUSR1 in signal")
+ skip("requires SIGUSR1 in signal")
signum = signal.SIGUSR1
received = []
@@ -156,6 +156,9 @@
import sys
if sys.platform == 'win32':
raises(ValueError, signal, 42, lambda *args: None)
+ raises(ValueError, signal, 7, lambda *args: None)
+ elif sys.platform == 'darwin':
+ raises(ValueError, signal, 42, lambda *args: None)
else:
signal(42, lambda *args: None)
signal(42, SIG_DFL)
More information about the pypy-commit
mailing list