[pypy-svn] r78641 - in pypy/branch/fast-forward/pypy: config module/_multiprocessing module/rctime rlib

afa at codespeak.net afa at codespeak.net
Tue Nov 2 17:16:14 CET 2010


Author: afa
Date: Tue Nov  2 17:16:11 2010
New Revision: 78641

Modified:
   pypy/branch/fast-forward/pypy/config/pypyoption.py
   pypy/branch/fast-forward/pypy/module/_multiprocessing/__init__.py
   pypy/branch/fast-forward/pypy/module/_multiprocessing/interp_semaphore.py
   pypy/branch/fast-forward/pypy/module/rctime/__init__.py
   pypy/branch/fast-forward/pypy/module/rctime/interp_time.py
   pypy/branch/fast-forward/pypy/rlib/rwin32.py
Log:
Implement interruptible time.sleep() on Windows.

+ _multiprocessing uses the same ConsoleCtrlHandler handler


Modified: pypy/branch/fast-forward/pypy/config/pypyoption.py
==============================================================================
--- pypy/branch/fast-forward/pypy/config/pypyoption.py	(original)
+++ pypy/branch/fast-forward/pypy/config/pypyoption.py	Tue Nov  2 17:16:11 2010
@@ -62,7 +62,10 @@
 
 
 
-module_dependencies = {}
+module_dependencies = {
+    '_multiprocessing': [('objspace.usemodules.rctime', True),
+                         ('objspace.usemodules.thread', True)],
+    }
 module_suggests = {
     # the reason you want _rawffi is for ctypes, which
     # itself needs the interp-level struct module

Modified: pypy/branch/fast-forward/pypy/module/_multiprocessing/__init__.py
==============================================================================
--- pypy/branch/fast-forward/pypy/module/_multiprocessing/__init__.py	(original)
+++ pypy/branch/fast-forward/pypy/module/_multiprocessing/__init__.py	Tue Nov  2 17:16:11 2010
@@ -16,7 +16,3 @@
 
     if sys.platform == 'win32':
         interpleveldefs['win32'] = 'interp_win32.win32_namespace(space)'
-
-    def startup(self, space):
-        from pypy.module._multiprocessing.interp_semaphore import CounterState
-        space.fromcache(CounterState).startup(space)

Modified: pypy/branch/fast-forward/pypy/module/_multiprocessing/interp_semaphore.py
==============================================================================
--- pypy/branch/fast-forward/pypy/module/_multiprocessing/interp_semaphore.py	(original)
+++ pypy/branch/fast-forward/pypy/module/_multiprocessing/interp_semaphore.py	Tue Nov  2 17:16:11 2010
@@ -27,67 +27,6 @@
         'ReleaseSemaphore', [rwin32.HANDLE, rffi.LONG, rffi.LONGP],
         rwin32.BOOL)
 
-    CtrlHandler_type = lltype.Ptr(lltype.FuncType([], rwin32.BOOL))
-    _CreateEvent = rwin32.winexternal(
-        'CreateEventA', [rffi.VOIDP, rwin32.BOOL, rwin32.BOOL, rwin32.LPCSTR],
-        rwin32.HANDLE)
-    _SetEvent = rwin32.winexternal(
-        'SetEvent', [rwin32.HANDLE], rwin32.BOOL)
-    _ResetEvent = rwin32.winexternal(
-        'ResetEvent', [rwin32.HANDLE], rwin32.BOOL)
-
-    # This is needed because the handler function must have the "WINAPI"
-    # calling convention, which is not supported by lltype.Ptr.
-    eci = ExternalCompilationInfo(
-        separate_module_sources=['''
-            #include <windows.h>
-
-            static BOOL (*CtrlHandlerRoutine)(
-                DWORD dwCtrlType);
-
-            static BOOL WINAPI winapi_CtrlHandlerRoutine(
-              DWORD dwCtrlType)
-            {
-                return CtrlHandlerRoutine(dwCtrlType);
-            }
-
-            BOOL pypy_multiprocessing_setCtrlHandlerRoutine(BOOL (*f)(DWORD))
-            {
-                CtrlHandlerRoutine = f;
-                SetConsoleCtrlHandler(winapi_CtrlHandlerRoutine, TRUE);
-            }
-
-        '''],
-        export_symbols=['pypy_multiprocessing_setCtrlHandlerRoutine'],
-        )
-    _setCtrlHandlerRoutine = rffi.llexternal(
-        'pypy_multiprocessing_setCtrlHandlerRoutine',
-        [CtrlHandler_type], rwin32.BOOL,
-        compilation_info=eci)
-
-    def ProcessingCtrlHandler():
-        _SetEvent(globalState.sigint_event)
-        return 0
-
-    class GlobalState:
-        def __init__(self):
-            self.init()
-
-        def init(self):
-            self.sigint_event = rwin32.NULL_HANDLE
-
-        def startup(self, space):
-            # Initialize the event handle used to signal Ctrl-C
-            globalState.sigint_event = _CreateEvent(
-                rffi.NULL, True, False, rffi.NULL)
-            if globalState.sigint_event == rwin32.NULL_HANDLE:
-                raise wrap_windowserror(
-                    space, rwin32.lastWindowsError("CreateEvent"))
-            if not _setCtrlHandlerRoutine(ProcessingCtrlHandler):
-                raise wrap_windowserror(
-                    space, rwin32.lastWindowsError("SetConsoleCtrlHandler"))
-
-
 else:
     from pypy.rlib import rposix
 
@@ -187,25 +126,12 @@
     def handle_w(space, w_handle):
         return rffi.cast(SEM_T, space.uint_w(w_handle))
 
-    class GlobalState:
-        def init(self):
-            pass
-
-        def startup(self, space):
-            pass
-
-globalState = GlobalState()
-
 class CounterState:
     def __init__(self, space):
         self.counter = 0
 
     def _freeze_(self):
         self.counter = 0
-        globalState.init()
-
-    def startup(self, space):
-        globalState.startup(space)
 
     def getCount(self):
         value = self.counter
@@ -250,10 +176,12 @@
         start = _GetTickCount()
 
         while True:
-            handles = [self.handle, globalState.sigint_event]
+            from pypy.module.rctime.interp_time import State
+            interrupt_event = space.fromcache(State).get_interrupt_event()
+            handles = [self.handle, interrupt_event]
 
             # do the wait
-            _ResetEvent(globalState.sigint_event)
+            rwin32.ResetEvent(interrupt_event)
             res = rwin32.WaitForMultipleObjects(handles, timeout=msecs)
 
             if res != rwin32.WAIT_OBJECT_0 + 1:

Modified: pypy/branch/fast-forward/pypy/module/rctime/__init__.py
==============================================================================
--- pypy/branch/fast-forward/pypy/module/rctime/__init__.py	(original)
+++ pypy/branch/fast-forward/pypy/module/rctime/__init__.py	Tue Nov  2 17:16:11 2010
@@ -2,6 +2,8 @@
 from pypy.interpreter.mixedmodule import MixedModule
 import os
 
+_WIN = os.name == "nt"
+
 class Module(MixedModule):
     applevel_name = 'time'
 
@@ -27,6 +29,10 @@
     }
 
     def startup(self, space):
+        if _WIN:
+            from pypy.module.rctime.interp_time import State
+            space.fromcache(State).startup(space)
+
         # this machinery is needed to expose constants
         # that have to be initialized one time only
         from pypy.module.rctime import interp_time

Modified: pypy/branch/fast-forward/pypy/module/rctime/interp_time.py
==============================================================================
--- pypy/branch/fast-forward/pypy/module/rctime/interp_time.py	(original)
+++ pypy/branch/fast-forward/pypy/module/rctime/interp_time.py	Tue Nov  2 17:16:11 2010
@@ -14,6 +14,89 @@
 _POSIX = os.name == "posix"
 _WIN = os.name == "nt"
 
+if _WIN:
+    # Interruptible sleeps on Windows:
+    # We install a specific Console Ctrl Handler which sets an 'event'.
+    # time.sleep() will actually call WaitForSingleObject with the desired
+    # timeout.  On Ctrl-C, the signal handler is called, the event is set,
+    # and the wait function exits.
+    from pypy.rlib import rwin32
+    from pypy.interpreter.error import wrap_windowserror, wrap_oserror
+    from pypy.module.thread import ll_thread as thread
+
+    # This is needed because the handler function must have the "WINAPI"
+    # calling convention, which is not supported by lltype.Ptr.
+    CtrlHandler_type = lltype.Ptr(lltype.FuncType([], rwin32.BOOL))
+    eci = ExternalCompilationInfo(
+        separate_module_sources=['''
+            #include <windows.h>
+
+            static BOOL (*CtrlHandlerRoutine)(
+                DWORD dwCtrlType);
+
+            static BOOL WINAPI winapi_CtrlHandlerRoutine(
+              DWORD dwCtrlType)
+            {
+                return CtrlHandlerRoutine(dwCtrlType);
+            }
+
+            BOOL pypy_timemodule_setCtrlHandlerRoutine(BOOL (*f)(DWORD))
+            {
+                CtrlHandlerRoutine = f;
+                SetConsoleCtrlHandler(winapi_CtrlHandlerRoutine, TRUE);
+            }
+
+        '''],
+        export_symbols=['pypy_timemodule_setCtrlHandlerRoutine'],
+        )
+    _setCtrlHandlerRoutine = rffi.llexternal(
+        'pypy_timemodule_setCtrlHandlerRoutine',
+        [CtrlHandler_type], rwin32.BOOL,
+        compilation_info=eci)
+
+    def ProcessingCtrlHandler():
+        rwin32.SetEvent(globalState.interrupt_event)
+        # allow other default handlers to be called.
+        # Default Python handler will setup the
+        # KeyboardInterrupt exception.
+        return 0
+
+    class GlobalState:
+        def __init__(self):
+            self.init()
+
+        def init(self):
+            self.interrupt_event = rwin32.NULL_HANDLE
+
+        def startup(self, space):
+            # Initialize the event handle used to signal Ctrl-C
+            try:
+                globalState.interrupt_event = rwin32.CreateEvent(
+                    rffi.NULL, True, False, rffi.NULL)
+            except WindowsError, e:
+                raise wrap_windowserror(space, e)
+            if not _setCtrlHandlerRoutine(ProcessingCtrlHandler):
+                raise wrap_windowserror(
+                    space, rwin32.lastWindowsError("SetConsoleCtrlHandler"))
+
+    globalState = GlobalState()
+
+    class State:
+        def __init__(self, space):
+            self.main_thread = 0
+
+        def _freeze_(self):
+            self.main_thread = 0
+            globalState.init()
+
+        def startup(self, space):
+            self.main_thread = thread.get_ident()
+            globalState.startup(space)
+
+        def get_interrupt_event(self):
+            return globalState.interrupt_event
+
+
 _includes = ["time.h"]
 if _POSIX:
     _includes.append('sys/time.h')
@@ -166,9 +249,37 @@
     errno = rposix.get_errno()
     return os.strerror(errno)
 
-def sleep(secs):
-    pytime.sleep(secs)
-sleep.unwrap_spec = [float]
+if sys.platform != 'win32':
+    def sleep(space, secs):
+        pytime.sleep(secs)
+else:
+    from pypy.rlib import rwin32
+    from errno import EINTR
+    def _simple_sleep(space, secs, interruptible):
+        if secs == 0.0 or not interruptible:
+            pytime.sleep(secs)
+        else:
+            millisecs = int(secs * 1000)
+            interrupt_event = space.fromcache(State).get_interrupt_event()
+            rwin32.ResetEvent(interrupt_event)
+            rc = rwin32.WaitForSingleObject(interrupt_event, millisecs)
+            if rc == rwin32.WAIT_OBJECT_0:
+                # Yield to make sure real Python signal handler
+                # called.
+                pytime.sleep(0.001)
+                raise wrap_oserror(space,
+                                   OSError(EINTR, "sleep() interrupted"))
+    def sleep(space, secs):
+        # as decreed by Guido, only the main thread can be
+        # interrupted.
+        main_thread = space.fromcache(State).main_thread
+        interruptible = (main_thread == thread.get_ident())
+        MAX = sys.maxint / 1000.0 # > 24 days
+        while secs > MAX:
+            _simple_sleep(space, MAX, interruptible)
+            secs -= MAX
+        _simple_sleep(space, secs, interruptible)
+sleep.unwrap_spec = [ObjSpace, float]
 
 def _get_module_object(space, obj_name):
     w_module = space.getbuiltinmodule('time')

Modified: pypy/branch/fast-forward/pypy/rlib/rwin32.py
==============================================================================
--- pypy/branch/fast-forward/pypy/rlib/rwin32.py	(original)
+++ pypy/branch/fast-forward/pypy/rlib/rwin32.py	Tue Nov  2 17:16:11 2010
@@ -275,3 +275,16 @@
             return res
         finally:
             lltype.free(handle_array, flavor='raw')
+
+    _CreateEvent = winexternal(
+        'CreateEventA', [rffi.VOIDP, BOOL, BOOL, LPCSTR], HANDLE)
+    def CreateEvent(*args):
+        handle = _CreateEvent(*args)
+        if handle == NULL_HANDLE:
+            raise lastWindowsError("CreateEvent")
+        return handle
+    SetEvent = winexternal(
+        'SetEvent', [HANDLE], BOOL)
+    ResetEvent = winexternal(
+        'ResetEvent', [HANDLE], BOOL)
+



More information about the Pypy-commit mailing list