[pypy-svn] r34072 - in pypy/dist/pypy: interpreter module/signal module/signal/test module/thread translator/goal

arigo at codespeak.net arigo at codespeak.net
Thu Nov 2 19:06:49 CET 2006


Author: arigo
Date: Thu Nov  2 19:06:46 2006
New Revision: 34072

Added:
   pypy/dist/pypy/module/signal/   (props changed)
   pypy/dist/pypy/module/signal/__init__.py   (contents, props changed)
   pypy/dist/pypy/module/signal/ctypes_signal.py   (contents, props changed)
   pypy/dist/pypy/module/signal/interp_signal.py   (contents, props changed)
   pypy/dist/pypy/module/signal/test/   (props changed)
   pypy/dist/pypy/module/signal/test/test_signal.py   (contents, props changed)
Modified:
   pypy/dist/pypy/interpreter/executioncontext.py
   pypy/dist/pypy/interpreter/miscutils.py
   pypy/dist/pypy/module/thread/threadlocals.py
   pypy/dist/pypy/translator/goal/app_main.py
Log:
Rough sketch of the 'signal' module.  Work in progress.

When pypy-c finds it, i.e. when translated --withmod-signal, 
it should install a handler for Ctrl-C.


Modified: pypy/dist/pypy/interpreter/executioncontext.py
==============================================================================
--- pypy/dist/pypy/interpreter/executioncontext.py	(original)
+++ pypy/dist/pypy/interpreter/executioncontext.py	Thu Nov  2 19:06:46 2006
@@ -107,8 +107,8 @@
         #     as selected by sys.setcheckinterval()
         ticker = self.ticker
         if ticker <= 0:
-            Action.perform_actions(self.pending_actions)
             Action.perform_actions(self.space.pending_actions)
+            Action.perform_actions(self.pending_actions)
             ticker = self.space.sys.checkinterval
         self.ticker = ticker - 1
         if frame.w_f_trace is None or self.is_tracing:

Modified: pypy/dist/pypy/interpreter/miscutils.py
==============================================================================
--- pypy/dist/pypy/interpreter/miscutils.py	(original)
+++ pypy/dist/pypy/interpreter/miscutils.py	Thu Nov  2 19:06:46 2006
@@ -165,6 +165,9 @@
     def setvalue(self, value):
         self._value = value
 
+    def getmainthreadvalue(self):
+        return self._value
+
     def getGIL(self):
         return None    # XXX temporary hack!
 

Added: pypy/dist/pypy/module/signal/__init__.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/module/signal/__init__.py	Thu Nov  2 19:06:46 2006
@@ -0,0 +1,26 @@
+
+from pypy.interpreter.mixedmodule import MixedModule
+
+class Module(MixedModule):
+    interpleveldefs = {
+        'signal': 'interp_signal.signal',
+    }
+
+    appleveldefs = {
+    }
+
+    def buildloaders(cls):
+        from pypy.module.signal import ctypes_signal
+        for name in ctypes_signal.signal_names:
+            signum = getattr(ctypes_signal, name)
+            if signum is not None:
+                Module.interpleveldefs[name] = 'space.wrap(%d)' % (signum,)
+        super(Module, cls).buildloaders()
+    buildloaders = classmethod(buildloaders)
+
+    def __init__(self, space, *args):
+        "NOT_RPYTHON"
+        from pypy.module.signal.interp_signal import CheckSignalAction
+        MixedModule.__init__(self, space, *args)
+        # add the signal-checking callback as an action on the space
+        space.pending_actions.append(CheckSignalAction(space))

Added: pypy/dist/pypy/module/signal/ctypes_signal.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/module/signal/ctypes_signal.py	Thu Nov  2 19:06:46 2006
@@ -0,0 +1,33 @@
+from pypy.rpython.rctypes.tool import ctypes_platform
+from pypy.rpython.rctypes.tool.libc import libc
+from ctypes import *
+
+
+signal_names = ['SIGINT', 'SIGTERM', 'SIGKILL',
+                # ...
+                ]
+
+
+sighandler_t = CFUNCTYPE(None, c_int)
+
+signal = libc.signal
+signal.restype = sighandler_t
+signal.argtypes = [c_int, sighandler_t]
+
+
+class CConfig:
+    _includes_ = ('signal.h',)
+
+##    struct_sigaction = ctypes_platform.Struct('struct sigaction',
+##                                              [('sa_handler', sighandler_t)])
+
+for name in signal_names:
+    setattr(CConfig, name, ctypes_platform.DefinedConstantInteger(name))
+
+globals().update(ctypes_platform.configure(CConfig))
+
+
+##sigaction = libc.sigaction
+##sigaction.restype = c_int
+##sigaction.argtypes = [c_int, POINTER(struct_sigaction),
+##                      POINTER(struct_sigaction)]

Added: pypy/dist/pypy/module/signal/interp_signal.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/module/signal/interp_signal.py	Thu Nov  2 19:06:46 2006
@@ -0,0 +1,105 @@
+from pypy.interpreter.baseobjspace import W_Root, ObjSpace
+from pypy.interpreter.miscutils import Action
+from pypy.module.signal import ctypes_signal
+
+
+class CheckSignalAction(Action):
+    """A repeatitive action at the space level, checking if the
+    signal_occurred flag is set and if so, scheduling ReportSignal actions.
+    """
+    repeat = True
+
+    def __init__(self, space):
+        self.space = space
+
+    def perform(self):
+        if flag_queue.signal_occurred:
+            flag_queue.signal_occurred = 0
+            node = flag_queue.head
+            signum = 0
+            while node is not None:
+                if node.flag:
+                    node.flag = 0
+                    main_ec = self.space.threadlocals.getmainthreadvalue()
+                    main_ec.add_pending_action(ReportSignal(self.space,
+                                                            node, signum))
+                node = node.next
+                signum += 1
+
+
+class ReportSignal(Action):
+    """A one-shot action for the main thread's execution context."""
+
+    def __init__(self, space, node, signum):
+        self.space = space
+        self.node = node
+        self.signum = signum
+
+    def perform(self):
+        w_handler = self.node.w_handler
+        if w_handler is not None:
+            space = self.space
+            ec = space.getexecutioncontext()
+            try:
+                w_frame = ec.framestack.top()
+            except IndexError:
+                w_frame = space.w_None
+            space.call_function(w_handler, space.wrap(self.signum), w_frame)
+
+
+# ____________________________________________________________
+# Global flags set by the signal handler
+
+# XXX some of these data structures may need to
+#     use the "volatile" keyword in the generated C code
+
+class FlagQueueNode(object):
+    def __init__(self):
+        self.flag = 0
+        self.next = None
+        self.w_handler = None
+
+class FlagQueue(object):
+    signal_occurred = 0
+    head = FlagQueueNode()
+
+flag_queue = FlagQueue()
+
+def get_flag_queue_signum(signum):
+    node = flag_queue.head
+    while signum > 0:
+        if node.next is None:
+            node.next = FlagQueueNode()
+        node = node.next
+        signum -= 1
+    return node
+
+def generic_signal_handler(signum):
+    node = flag_queue.head
+    index = 0
+    while index < signum:
+        node = node.next
+        index += 1
+    node.flag = 1
+    flag_queue.signal_occurred = 1
+    # XXX may need to set the handler again, in case the OS clears it
+
+def os_setsig(signum, handler):
+    return ctypes_signal.signal(signum, handler)
+
+# ____________________________________________________________
+
+def signal(space, signum, w_handler):
+    ec      = space.getexecutioncontext()
+    main_ec = space.threadlocals.getmainthreadvalue()
+    if ec is not main_ec:
+        raise OperationError(space.w_ValueError,
+                             space.wrap("signal() must be called from the "
+                                        "main thread"))
+    node = get_flag_queue_signum(signum)
+    node.w_handler = w_handler
+    # XXX special values SIG_IGN, SIG_DFL
+    handler = ctypes_signal.sighandler_t(generic_signal_handler)
+    os_setsig(signum, handler)
+    # XXX return value
+signal.unwrap_spec = [ObjSpace, int, W_Root]

Added: pypy/dist/pypy/module/signal/test/test_signal.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/module/signal/test/test_signal.py	Thu Nov  2 19:06:46 2006
@@ -0,0 +1,13 @@
+
+##import signal
+
+##def ya(*args):
+##    print "ya", args
+ 
+##signal.signal(signal.SIGINT, ya)
+
+##i = 0
+##while 1:
+##    i += 1
+##    if i%1000 == 0:
+##        print i

Modified: pypy/dist/pypy/module/thread/threadlocals.py
==============================================================================
--- pypy/dist/pypy/module/thread/threadlocals.py	(original)
+++ pypy/dist/pypy/module/thread/threadlocals.py	Thu Nov  2 19:06:46 2006
@@ -12,6 +12,7 @@
 
     def __init__(self):
         self._valuedict = {}   # {thread_ident: ExecutionContext()}
+        self._mainthreadident = 0
 
     def getvalue(self):
         ident = thread.get_ident()
@@ -19,7 +20,19 @@
 
     def setvalue(self, value):
         ident = thread.get_ident()
-        self._valuedict[ident] = value
+        if value is not None:
+            if len(self._valuedict) == 0:
+                self._mainthreadident = ident
+            self._valuedict[ident] = value
+        else:
+            try:
+                del self._valuedict[ident]
+            except KeyError:
+                pass
+
+    def getmainthreadvalue(self):
+        ident = self._mainthreadident
+        return self._valuedict.get(ident, None)
 
     def enter_thread(self, space):
         "Notification that the current thread is just starting."

Modified: pypy/dist/pypy/translator/goal/app_main.py
==============================================================================
--- pypy/dist/pypy/translator/goal/app_main.py	(original)
+++ pypy/dist/pypy/translator/goal/app_main.py	Thu Nov  2 19:06:46 2006
@@ -198,6 +198,17 @@
     mainmodule = type(sys)('__main__')
     sys.modules['__main__'] = mainmodule
 
+    # set up the Ctrl-C => KeyboardInterrupt signal handler, if the
+    # signal module is available
+    try:
+        import signal
+    except ImportError:
+        pass
+    else:
+        def keyboard_interrupt_handler(*args):
+            raise KeyboardInterrupt
+        signal.signal(signal.SIGINT, keyboard_interrupt_handler)
+
     try:
         if sys.argv:
             if sys.argv[0] == '-c':



More information about the Pypy-commit mailing list