Commits

Armin Rigo committed ff1b216

Split interp_signal in three. rlib/rsignal is like on trunk. sigaction.py is the non-stm action classes.

Comments (0)

Files changed (5)

pypy/interpreter/executioncontext.py

         assert isinstance(action, PeriodicAsyncAction)
         self._periodic_actions.append(action)
         if use_bytecode_counter:
+            assert not action.space.config.translation.stm, (
+                "Cannot use the bytecode counter with STM")
             self.has_bytecode_counter = True
         self._rebuild_action_dispatcher()
 

pypy/module/signal/__init__.py

     }
 
     def buildloaders(cls):
-        from pypy.module.signal import interp_signal
-        for name in interp_signal.signal_names:
-            signum = getattr(interp_signal, name)
+        from pypy.rlib import rsignal
+        for name in rsignal.signal_names:
+            signum = getattr(rsignal, name)
             if signum is not None:
                 Module.interpleveldefs[name] = 'space.wrap(%d)' % (signum,)
         super(Module, cls).buildloaders()
 
     def __init__(self, space, *args):
         "NOT_RPYTHON"
-        from pypy.module.signal import interp_signal
+        from pypy.module.signal import sigaction
         MixedModule.__init__(self, space, *args)
         # add the signal-checking callback as an action on the space
-        space.check_signal_action = interp_signal.CheckSignalAction(space)
+        space.check_signal_action = sigaction.CheckSignalAction(space)
         space.actionflag.register_periodic_action(space.check_signal_action,
                                                   use_bytecode_counter=False)
-        space.actionflag.__class__ = interp_signal.SignalActionFlag
+        space.actionflag.__class__ = sigaction.SignalActionFlag
         # xxx yes I know the previous line is a hack

pypy/module/signal/interp_signal.py

 from __future__ import with_statement
 from pypy.interpreter.error import OperationError, exception_from_errno
-from pypy.interpreter.executioncontext import AsyncAction, AbstractActionFlag
-from pypy.interpreter.executioncontext import PeriodicAsyncAction
 from pypy.interpreter.gateway import unwrap_spec
-import signal as cpy_signal
 from pypy.rpython.lltypesystem import lltype, rffi
-from pypy.rpython.tool import rffi_platform
-from pypy.translator.tool.cbuild import ExternalCompilationInfo
-import py
-import sys
-from pypy.tool import autopath
 from pypy.rlib import jit, rposix
-from pypy.rlib.rarithmetic import intmask, is_valid_int
-
-def setup():
-    for key, value in cpy_signal.__dict__.items():
-        if (key.startswith('SIG') or key.startswith('CTRL_')) and \
-                is_valid_int(value) and \
-                key != 'SIG_DFL' and key != 'SIG_IGN':
-            globals()[key] = value
-            yield key
-
-NSIG    = cpy_signal.NSIG
-SIG_DFL = cpy_signal.SIG_DFL
-SIG_IGN = cpy_signal.SIG_IGN
-signal_names = list(setup())
-signal_values = {}
-for key in signal_names:
-    signal_values[globals()[key]] = None
-if sys.platform == 'win32' and not hasattr(cpy_signal,'CTRL_C_EVENT'):
-    # XXX Hack to revive values that went missing,
-    #     Remove this once we are sure the host cpy module has them.
-    signal_values[0] = None
-    signal_values[1] = None
-    signal_names.append('CTRL_C_EVENT')
-    signal_names.append('CTRL_BREAK_EVENT')
-    CTRL_C_EVENT = 0
-    CTRL_BREAK_EVENT = 1
-includes = ['stdlib.h', 'src/signals.h']
-if sys.platform != 'win32':
-    includes.append('sys/time.h')
-
-cdir = py.path.local(autopath.pypydir).join('translator', 'c')
-
-eci = ExternalCompilationInfo(
-    includes = includes,
-    separate_module_files = [cdir / 'src' / 'signals.c'],
-    include_dirs = [str(cdir)],
-    export_symbols = ['pypysig_poll', 'pypysig_default',
-                      'pypysig_ignore', 'pypysig_setflag',
-                      'pypysig_reinstall',
-                      'pypysig_set_wakeup_fd',
-                      'pypysig_getaddr_occurred'],
-)
-
-class CConfig:
-    _compilation_info_ = eci
-
-if sys.platform != 'win32':
-    for name in """ITIMER_REAL ITIMER_VIRTUAL ITIMER_PROF""".split():
-        setattr(CConfig, name, rffi_platform.DefinedConstantInteger(name))
-
-    CConfig.timeval = rffi_platform.Struct(
-        'struct timeval',
-        [('tv_sec', rffi.LONG),
-         ('tv_usec', rffi.LONG)])
-
-    CConfig.itimerval = rffi_platform.Struct(
-        'struct itimerval',
-        [('it_value', CConfig.timeval),
-         ('it_interval', CConfig.timeval)])
-
-for k, v in rffi_platform.configure(CConfig).items():
-    globals()[k] = v
-
-def external(name, args, result, **kwds):
-    return rffi.llexternal(name, args, result, compilation_info=eci,
-                           sandboxsafe=True, **kwds)
-
-pypysig_ignore = external('pypysig_ignore', [rffi.INT], lltype.Void)
-pypysig_default = external('pypysig_default', [rffi.INT], lltype.Void)
-pypysig_setflag = external('pypysig_setflag', [rffi.INT], lltype.Void)
-pypysig_reinstall = external('pypysig_reinstall', [rffi.INT], lltype.Void)
-pypysig_set_wakeup_fd = external('pypysig_set_wakeup_fd', [rffi.INT], rffi.INT)
-pypysig_poll = external('pypysig_poll', [], rffi.INT, threadsafe=False)
-# don't bother releasing the GIL around a call to pypysig_poll: it's
-# pointless and a performance issue
-
-# don't use rffi.LONGP because the JIT doesn't support raw arrays so far
-struct_name = 'pypysig_long_struct'
-LONG_STRUCT = lltype.Struct(struct_name, ('c_value', lltype.Signed),
-                            hints={'c_name' : struct_name, 'external' : 'C'})
-del struct_name
-
-pypysig_getaddr_occurred = external('pypysig_getaddr_occurred', [],
-                                    lltype.Ptr(LONG_STRUCT), _nowrapper=True,
-                                    elidable_function=True)
-c_alarm = external('alarm', [rffi.INT], rffi.INT)
-c_pause = external('pause', [], rffi.INT, threadsafe=True)
-c_siginterrupt = external('siginterrupt', [rffi.INT, rffi.INT], rffi.INT)
-
-if sys.platform != 'win32':
-    itimervalP = rffi.CArrayPtr(itimerval)
-    c_setitimer = external('setitimer',
-                           [rffi.INT, itimervalP, itimervalP], rffi.INT)
-    c_getitimer = external('getitimer', [rffi.INT, itimervalP], rffi.INT)
-
-
-class SignalActionFlag(AbstractActionFlag):
-    # This class uses the C-level pypysig_counter variable as the tick
-    # counter.  The C-level signal handler will reset it to -1 whenever
-    # a signal is received.
-
-    def get_ticker(self):
-        p = pypysig_getaddr_occurred()
-        return p.c_value
-
-    def reset_ticker(self, value):
-        p = pypysig_getaddr_occurred()
-        p.c_value = value
-
-    def decrement_ticker(self, by):
-        p = pypysig_getaddr_occurred()
-        value = p.c_value
-        if self.has_bytecode_counter:    # this 'if' is constant-folded
-            if jit.isconstant(by) and by == 0:
-                pass     # normally constant-folded too
-            else:
-                value -= by
-                p.c_value = value
-        return value
-
-
-class CheckSignalAction(PeriodicAsyncAction):
-    """An action that is automatically invoked when a signal is received."""
-
-    def __init__(self, space):
-        AsyncAction.__init__(self, space)
-        self.handlers_w = {}
-        if space.config.objspace.usemodules.thread:
-            # need a helper action in case signals arrive in a non-main thread
-            self.pending_signals = {}
-            self.reissue_signal_action = ReissueSignalAction(space)
-        else:
-            self.reissue_signal_action = None
-
-    @jit.dont_look_inside
-    def perform(self, executioncontext, frame):
-        while True:
-            n = pypysig_poll()
-            if n < 0:
-                break
-            self.perform_signal(executioncontext, n)
-
-    @jit.dont_look_inside
-    def perform_signal(self, executioncontext, n):
-        if self.reissue_signal_action is None:
-            # no threads: we can report the signal immediately
-            self.report_signal(n)
-        else:
-            main_ec = self.space.threadlocals.getmainthreadvalue()
-            if executioncontext is main_ec:
-                # running in the main thread: we can report the
-                # signal immediately
-                self.report_signal(n)
-            else:
-                # running in another thread: we need to hack a bit
-                self.pending_signals[n] = None
-                self.reissue_signal_action.fire_after_thread_switch()
-
-    @jit.dont_look_inside
-    def set_interrupt(self):
-        "Simulates the effect of a SIGINT signal arriving"
-        ec = self.space.getexecutioncontext()
-        self.perform_signal(ec, cpy_signal.SIGINT)
-
-    @jit.dont_look_inside
-    def report_signal(self, n):
-        try:
-            w_handler = self.handlers_w[n]
-        except KeyError:
-            return    # no handler, ignore signal
-        space = self.space
-        if not space.is_true(space.callable(w_handler)):
-            return    # w_handler is SIG_IGN or SIG_DFL?
-        # re-install signal handler, for OSes that clear it
-        pypysig_reinstall(n)
-        # invoke the app-level handler
-        ec = space.getexecutioncontext()
-        w_frame = space.wrap(ec.gettopframe_nohidden())
-        space.call_function(w_handler, space.wrap(n), w_frame)
-
-    @jit.dont_look_inside
-    def report_pending_signals(self):
-        # XXX this logic isn't so complicated but I have no clue how
-        # to test it :-(
-        pending_signals = self.pending_signals.keys()
-        self.pending_signals.clear()
-        try:
-            while pending_signals:
-                self.report_signal(pending_signals.pop())
-        finally:
-            # in case of exception, put the undelivered signals back
-            # into the dict instead of silently swallowing them
-            if pending_signals:
-                for n in pending_signals:
-                    self.pending_signals[n] = None
-                self.reissue_signal_action.fire()
-
-
-class ReissueSignalAction(AsyncAction):
-    """A special action to help deliver signals to the main thread.  If
-    a non-main thread caught a signal, this action fires after every
-    thread switch until we land in the main thread.
-    """
-
-    def perform(self, executioncontext, frame):
-        main_ec = self.space.threadlocals.getmainthreadvalue()
-        if executioncontext is main_ec:
-            # now running in the main thread: we can really report the signals
-            self.space.check_signal_action.report_pending_signals()
-        else:
-            # still running in some other thread: try again later
-            self.fire_after_thread_switch()
+from pypy.rlib.rarithmetic import intmask
+from pypy.rlib.rsignal import *
 
 
 @unwrap_spec(signum=int)

pypy/module/signal/sigaction.py

+from pypy.interpreter.executioncontext import AsyncAction, AbstractActionFlag
+from pypy.interpreter.executioncontext import PeriodicAsyncAction
+from pypy.rlib import jit
+from pypy.rlib.rsignal import pypysig_getaddr_occurred
+from pypy.rlib.rsignal import pypysig_poll, pypysig_reinstall
+
+
+class SignalActionFlag(AbstractActionFlag):
+    # This class uses the C-level pypysig_counter variable as the tick
+    # counter.  The C-level signal handler will reset it to -1 whenever
+    # a signal is received.
+
+    def get_ticker(self):
+        p = pypysig_getaddr_occurred()
+        return p.c_value
+
+    def reset_ticker(self, value):
+        p = pypysig_getaddr_occurred()
+        p.c_value = value
+
+    def decrement_ticker(self, by):
+        p = pypysig_getaddr_occurred()
+        value = p.c_value
+        if self.has_bytecode_counter:    # this 'if' is constant-folded
+            if jit.isconstant(by) and by == 0:
+                pass     # normally constant-folded too
+            else:
+                value -= by
+                p.c_value = value
+        return value
+
+
+class CheckSignalAction(PeriodicAsyncAction):
+    """An action that is automatically invoked when a signal is received."""
+
+    def __init__(self, space):
+        AsyncAction.__init__(self, space)
+        self.handlers_w = {}
+        if space.config.objspace.usemodules.thread:
+            # need a helper action in case signals arrive in a non-main thread
+            self.pending_signals = {}
+            self.reissue_signal_action = ReissueSignalAction(space)
+        else:
+            self.reissue_signal_action = None
+
+    @jit.dont_look_inside
+    def perform(self, executioncontext, frame):
+        while True:
+            n = pypysig_poll()
+            if n < 0:
+                break
+            self.perform_signal(executioncontext, n)
+
+    @jit.dont_look_inside
+    def perform_signal(self, executioncontext, n):
+        if self.reissue_signal_action is None:
+            # no threads: we can report the signal immediately
+            self.report_signal(n)
+        else:
+            main_ec = self.space.threadlocals.getmainthreadvalue()
+            if executioncontext is main_ec:
+                # running in the main thread: we can report the
+                # signal immediately
+                self.report_signal(n)
+            else:
+                # running in another thread: we need to hack a bit
+                self.pending_signals[n] = None
+                self.reissue_signal_action.fire_after_thread_switch()
+
+    @jit.dont_look_inside
+    def set_interrupt(self):
+        "Simulates the effect of a SIGINT signal arriving"
+        ec = self.space.getexecutioncontext()
+        self.perform_signal(ec, cpy_signal.SIGINT)
+
+    @jit.dont_look_inside
+    def report_signal(self, n):
+        try:
+            w_handler = self.handlers_w[n]
+        except KeyError:
+            return    # no handler, ignore signal
+        space = self.space
+        if not space.is_true(space.callable(w_handler)):
+            return    # w_handler is SIG_IGN or SIG_DFL?
+        # re-install signal handler, for OSes that clear it
+        pypysig_reinstall(n)
+        # invoke the app-level handler
+        ec = space.getexecutioncontext()
+        w_frame = space.wrap(ec.gettopframe_nohidden())
+        space.call_function(w_handler, space.wrap(n), w_frame)
+
+    @jit.dont_look_inside
+    def report_pending_signals(self):
+        # XXX this logic isn't so complicated but I have no clue how
+        # to test it :-(
+        pending_signals = self.pending_signals.keys()
+        self.pending_signals.clear()
+        try:
+            while pending_signals:
+                self.report_signal(pending_signals.pop())
+        finally:
+            # in case of exception, put the undelivered signals back
+            # into the dict instead of silently swallowing them
+            if pending_signals:
+                for n in pending_signals:
+                    self.pending_signals[n] = None
+                self.reissue_signal_action.fire()
+
+
+class ReissueSignalAction(AsyncAction):
+    """A special action to help deliver signals to the main thread.  If
+    a non-main thread caught a signal, this action fires after every
+    thread switch until we land in the main thread.
+    """
+
+    def perform(self, executioncontext, frame):
+        main_ec = self.space.threadlocals.getmainthreadvalue()
+        if executioncontext is main_ec:
+            # now running in the main thread: we can really report the signals
+            self.space.check_signal_action.report_pending_signals()
+        else:
+            # still running in some other thread: try again later
+            self.fire_after_thread_switch()

pypy/rlib/rsignal.py

+import signal as cpy_signal
+import sys
+import py
+from pypy.tool import autopath
+from pypy.rpython.tool import rffi_platform
+from pypy.rpython.lltypesystem import lltype, rffi
+from pypy.translator.tool.cbuild import ExternalCompilationInfo
+from pypy.rlib.rarithmetic import is_valid_int
+
+def setup():
+    for key, value in cpy_signal.__dict__.items():
+        if (key.startswith('SIG') or key.startswith('CTRL_')) and \
+                is_valid_int(value) and \
+                key != 'SIG_DFL' and key != 'SIG_IGN':
+            globals()[key] = value
+            yield key
+
+NSIG    = cpy_signal.NSIG
+SIG_DFL = cpy_signal.SIG_DFL
+SIG_IGN = cpy_signal.SIG_IGN
+signal_names = list(setup())
+signal_values = {}
+for key in signal_names:
+    signal_values[globals()[key]] = None
+if sys.platform == 'win32' and not hasattr(cpy_signal,'CTRL_C_EVENT'):
+    # XXX Hack to revive values that went missing,
+    #     Remove this once we are sure the host cpy module has them.
+    signal_values[0] = None
+    signal_values[1] = None
+    signal_names.append('CTRL_C_EVENT')
+    signal_names.append('CTRL_BREAK_EVENT')
+    CTRL_C_EVENT = 0
+    CTRL_BREAK_EVENT = 1
+includes = ['stdlib.h', 'src/signals.h']
+if sys.platform != 'win32':
+    includes.append('sys/time.h')
+
+cdir = py.path.local(autopath.pypydir).join('translator', 'c')
+
+eci = ExternalCompilationInfo(
+    includes = includes,
+    separate_module_files = [cdir / 'src' / 'signals.c'],
+    include_dirs = [str(cdir)],
+    export_symbols = ['pypysig_poll', 'pypysig_default',
+                      'pypysig_ignore', 'pypysig_setflag',
+                      'pypysig_reinstall',
+                      'pypysig_set_wakeup_fd',
+                      'pypysig_getaddr_occurred'],
+)
+
+class CConfig:
+    _compilation_info_ = eci
+
+if sys.platform != 'win32':
+    for name in """ITIMER_REAL ITIMER_VIRTUAL ITIMER_PROF""".split():
+        setattr(CConfig, name, rffi_platform.DefinedConstantInteger(name))
+
+    CConfig.timeval = rffi_platform.Struct(
+        'struct timeval',
+        [('tv_sec', rffi.LONG),
+         ('tv_usec', rffi.LONG)])
+
+    CConfig.itimerval = rffi_platform.Struct(
+        'struct itimerval',
+        [('it_value', CConfig.timeval),
+         ('it_interval', CConfig.timeval)])
+
+for k, v in rffi_platform.configure(CConfig).items():
+    globals()[k] = v
+
+def external(name, args, result, **kwds):
+    return rffi.llexternal(name, args, result, compilation_info=eci,
+                           sandboxsafe=True, **kwds)
+
+pypysig_ignore = external('pypysig_ignore', [rffi.INT], lltype.Void)
+pypysig_default = external('pypysig_default', [rffi.INT], lltype.Void)
+pypysig_setflag = external('pypysig_setflag', [rffi.INT], lltype.Void)
+pypysig_reinstall = external('pypysig_reinstall', [rffi.INT], lltype.Void)
+pypysig_set_wakeup_fd = external('pypysig_set_wakeup_fd', [rffi.INT], rffi.INT)
+pypysig_poll = external('pypysig_poll', [], rffi.INT, threadsafe=False)
+# don't bother releasing the GIL around a call to pypysig_poll: it's
+# pointless and a performance issue
+
+# don't use rffi.LONGP because the JIT doesn't support raw arrays so far
+struct_name = 'pypysig_long_struct'
+LONG_STRUCT = lltype.Struct(struct_name, ('c_value', lltype.Signed),
+                            hints={'c_name' : struct_name, 'external' : 'C'})
+del struct_name
+
+pypysig_getaddr_occurred = external('pypysig_getaddr_occurred', [],
+                                    lltype.Ptr(LONG_STRUCT), _nowrapper=True,
+                                    elidable_function=True)
+c_alarm = external('alarm', [rffi.INT], rffi.INT)
+c_pause = external('pause', [], rffi.INT, threadsafe=True)
+c_siginterrupt = external('siginterrupt', [rffi.INT, rffi.INT], rffi.INT)
+
+if sys.platform != 'win32':
+    itimervalP = rffi.CArrayPtr(itimerval)
+    c_setitimer = external('setitimer',
+                           [rffi.INT, itimervalP, itimervalP], rffi.INT)
+    c_getitimer = external('getitimer', [rffi.INT, itimervalP], rffi.INT)