[pypy-svn] r34068 - in pypy/dist/pypy: interpreter interpreter/test module/thread
arigo at codespeak.net
arigo at codespeak.net
Thu Nov 2 17:49:06 CET 2006
Author: arigo
Date: Thu Nov 2 17:49:02 2006
New Revision: 34068
Added:
pypy/dist/pypy/interpreter/test/test_executioncontext.py (contents, props changed)
Modified:
pypy/dist/pypy/interpreter/baseobjspace.py
pypy/dist/pypy/interpreter/executioncontext.py
pypy/dist/pypy/interpreter/miscutils.py
pypy/dist/pypy/module/thread/__init__.py
pypy/dist/pypy/module/thread/gil.py
pypy/dist/pypy/module/thread/threadlocals.py
Log:
Add generic support for global or per-thread "actions" in the
interpreter, executed every sys.setcheckinterval() bytecode
instructions.
Adapted the GIL-releasing code to use such an "action".
Should be usable for things like soft preemptive threading (for the
logic object space), and maybe for signal handlers (e.g. Ctrl-C =>
KeyboardInterrupt).
Modified: pypy/dist/pypy/interpreter/baseobjspace.py
==============================================================================
--- pypy/dist/pypy/interpreter/baseobjspace.py (original)
+++ pypy/dist/pypy/interpreter/baseobjspace.py Thu Nov 2 17:49:02 2006
@@ -148,6 +148,7 @@
config = Config(pypy_optiondescription)
self.config = config
self.interned_strings = {}
+ self.pending_actions = []
self.setoptions(**kw)
if self.config.objspace.logbytecodes:
Modified: pypy/dist/pypy/interpreter/executioncontext.py
==============================================================================
--- pypy/dist/pypy/interpreter/executioncontext.py (original)
+++ pypy/dist/pypy/interpreter/executioncontext.py Thu Nov 2 17:49:02 2006
@@ -1,5 +1,5 @@
import sys
-from pypy.interpreter.miscutils import Stack
+from pypy.interpreter.miscutils import Stack, Action
from pypy.interpreter.error import OperationError
def new_framestack():
@@ -16,6 +16,7 @@
self.w_profilefunc = None
self.is_tracing = 0
self.ticker = 0
+ self.pending_actions = []
self.compiler = space.createcompiler()
def enter(self, frame):
@@ -106,7 +107,8 @@
# as selected by sys.setcheckinterval()
ticker = self.ticker
if ticker <= 0:
- self.space.threadlocals.yield_thread()
+ Action.perform_actions(self.pending_actions)
+ Action.perform_actions(self.space.pending_actions)
ticker = self.space.sys.checkinterval
self.ticker = ticker - 1
if frame.w_f_trace is None or self.is_tracing:
@@ -254,3 +256,6 @@
frame.last_exception = last_exception
self.is_tracing -= 1
+ def add_pending_action(self, action):
+ self.pending_actions.append(action)
+ self.ticker = 0
Modified: pypy/dist/pypy/interpreter/miscutils.py
==============================================================================
--- pypy/dist/pypy/interpreter/miscutils.py (original)
+++ pypy/dist/pypy/interpreter/miscutils.py Thu Nov 2 17:49:02 2006
@@ -165,9 +165,28 @@
def setvalue(self, value):
self._value = value
- def yield_thread(self):
- """Called from time to time between the interpretation of bytecodes.
- Hook for threading models that require it."""
-
def getGIL(self):
return None # XXX temporary hack!
+
+
+class Action(object):
+ """Abstract base class for actions that must be performed regularly,
+ every Nth bytecode (as selected by sys.setcheckinterval())."""
+
+ # set repeat to True for actions that must be kept around and
+ # re-performed regularly
+ repeat = False
+
+ def perform(self):
+ """To be overridden."""
+
+ def perform_actions(actionlist):
+ i = 0
+ while i < len(actionlist):
+ a = actionlist[i]
+ if a.repeat:
+ i += 1 # keep action
+ else:
+ del actionlist[i]
+ a.perform()
+ perform_actions = staticmethod(perform_actions)
Added: pypy/dist/pypy/interpreter/test/test_executioncontext.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/interpreter/test/test_executioncontext.py Thu Nov 2 17:49:02 2006
@@ -0,0 +1,36 @@
+import py
+from pypy.interpreter import miscutils
+
+
+class TestExecutionContext:
+
+ def test_action(self):
+ class Finished(Exception):
+ pass
+
+ class DemoAction(miscutils.Action):
+ def __init__(self, repeat):
+ self.repeat = repeat
+ self.counter = 0
+ def perform(self):
+ self.counter += 1
+ if self.counter == 10:
+ raise Finished
+
+ a1 = DemoAction(False)
+ a2 = DemoAction(True)
+ a3 = DemoAction(False)
+
+ space = self.space
+ space.pending_actions.append(a1)
+ space.getexecutioncontext().add_pending_action(a2)
+ space.getexecutioncontext().add_pending_action(a3)
+
+ py.test.raises(Finished, space.appexec, [], """():
+ n = 50000
+ while n > 0:
+ n -= 1
+ """)
+ assert a1.counter == 1
+ assert a2.counter == 10
+ assert a3.counter == 1
Modified: pypy/dist/pypy/module/thread/__init__.py
==============================================================================
--- pypy/dist/pypy/module/thread/__init__.py (original)
+++ pypy/dist/pypy/module/thread/__init__.py Thu Nov 2 17:49:02 2006
@@ -27,6 +27,8 @@
space.threadlocals = gil.GILThreadLocals()
space.threadlocals.setvalue(prev)
space.threadlocals.enter_thread(space) # setup the main thread
+ # add the GIL-releasing callback as an action on the space
+ space.pending_actions.append(gil.GILReleaseAction(space.threadlocals))
def setup_after_space_initialization(self):
# the import lock is in imp.py. Import it after the space is fully
Modified: pypy/dist/pypy/module/thread/gil.py
==============================================================================
--- pypy/dist/pypy/module/thread/gil.py (original)
+++ pypy/dist/pypy/module/thread/gil.py Thu Nov 2 17:49:02 2006
@@ -8,6 +8,7 @@
# from time to time, using the executioncontext's XXX
import thread
+from pypy.interpreter.miscutils import Action
from pypy.module.thread.threadlocals import OSThreadLocals
@@ -39,3 +40,16 @@
def getGIL(self):
return self.GIL # XXX temporary hack!
+
+
+class GILReleaseAction(Action):
+ """An action called when the current thread is between two bytecodes
+ (so that it's a good time to yield some time to other threads).
+ """
+ repeat = True
+
+ def __init__(self, threadlocals):
+ self.threadlocals = threadlocals
+
+ def perform(self):
+ self.threadlocals.yield_thread()
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 17:49:02 2006
@@ -40,10 +40,6 @@
except KeyError:
pass
- def yield_thread(self):
- """Notification that the current thread is between two bytecodes
- (so that it's a good time to yield some time to other threads)."""
-
def atthreadexit(self, space, exit_func, w_obj):
ec = space.getexecutioncontext()
ec.thread_exit_funcs.append((exit_func, w_obj))
More information about the Pypy-commit
mailing list