Author: Armin Rigo <[email protected]>
Branch: signal-and-thread
Changeset: r61273:b869a617a78a
Date: 2013-02-15 17:21 +0100
http://bitbucket.org/pypy/pypy/changeset/b869a617a78a/

Log:    Add '__pypy__.enable_signals', a context manager.

diff --git a/pypy/interpreter/miscutils.py b/pypy/interpreter/miscutils.py
--- a/pypy/interpreter/miscutils.py
+++ b/pypy/interpreter/miscutils.py
@@ -20,5 +20,11 @@
     def signals_enabled(self):
         return True
 
+    def enable_signals(self):
+        pass
+
+    def disable_signals(self):
+        pass
+
     def getallvalues(self):
         return {0: self._value}
diff --git a/pypy/module/__pypy__/__init__.py b/pypy/module/__pypy__/__init__.py
--- a/pypy/module/__pypy__/__init__.py
+++ b/pypy/module/__pypy__/__init__.py
@@ -28,6 +28,7 @@
 
 class Module(MixedModule):
     appleveldefs = {
+        'signals_enabled'           : 'app_signal.signals_enabled',
     }
 
     interpleveldefs = {
@@ -47,6 +48,8 @@
         'newlist_hint'              : 'interp_magic.newlist_hint',
         'newdict'                   : 'interp_dict.newdict',
         'dictstrategy'              : 'interp_dict.dictstrategy',
+        '_signals_enter'            : 'interp_signal.signals_enter',
+        '_signals_exit'             : 'interp_signal.signals_exit',
     }
     if sys.platform == 'win32':
         interpleveldefs['get_console_cp'] = 'interp_magic.get_console_cp'
diff --git a/pypy/module/__pypy__/app_signal.py 
b/pypy/module/__pypy__/app_signal.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/__pypy__/app_signal.py
@@ -0,0 +1,14 @@
+import __pypy__
+
+class SignalsEnabled(object):
+    '''A context manager to use in non-main threads:
+enables receiving signals in a "with" statement.  More precisely, if a
+signal is received by the process, then the signal handler might be
+called either in the main thread (as usual) or within another thread
+that is within a "with signals_enabled:".  This other thread should be
+ready to handle unexpected exceptions that the signal handler might
+raise --- notably KeyboardInterrupt.'''
+    __enter__ = __pypy__._signals_enter
+    __exit__  = __pypy__._signals_exit
+
+signals_enabled = SignalsEnabled()
diff --git a/pypy/module/__pypy__/interp_signal.py 
b/pypy/module/__pypy__/interp_signal.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/__pypy__/interp_signal.py
@@ -0,0 +1,6 @@
+
+def signals_enter(space):
+    space.threadlocals.enable_signals()
+
+def signals_exit(space):
+    space.threadlocals.disable_signals()
diff --git a/pypy/module/thread/threadlocals.py 
b/pypy/module/thread/threadlocals.py
--- a/pypy/module/thread/threadlocals.py
+++ b/pypy/module/thread/threadlocals.py
@@ -9,7 +9,7 @@
 
     def __init__(self):
         self._valuedict = {}   # {thread_ident: ExecutionContext()}
-        self._signalsenabled = {}   # {thread_ident: None}
+        self._signalsenabled = {}   # {thread_ident: number-of-times}
         self._cleanup_()
 
     def _cleanup_(self):
@@ -34,7 +34,7 @@
         ident = rthread.get_ident()
         if value is not None:
             if len(self._valuedict) == 0:
-                self._signalsenabled[ident] = None
+                self._signalsenabled[ident] = 1    # the main thread is enabled
             self._valuedict[ident] = value
         else:
             try:
@@ -49,10 +49,20 @@
         return rthread.get_ident() in self._signalsenabled
 
     def enable_signals(self):
-        self._signalsenabled[rthread.get_ident()] = None
+        ident = rthread.get_ident()
+        old = self._signalsenabled.get(ident, 0)
+        self._signalsenabled[ident] = old + 1
 
     def disable_signals(self):
-        del self._signalsenabled[rthread.get_ident()]
+        ident = rthread.get_ident()
+        try:
+            new = self._signalsenabled[ident] - 1
+        except KeyError:
+            return
+        if new > 0:
+            self._signalsenabled[ident] = new
+        else:
+            del self._signalsenabled[ident]
 
     def getallvalues(self):
         return self._valuedict
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to