Source

lang-smalltalk / spyvm / interpreter.py

Diff from to

spyvm/interpreter.py

 import py
 import os
-from spyvm.shadow import ContextPartShadow, MethodContextShadow, BlockContextShadow, MethodNotFound
+import time
+
+from spyvm.shadow import ContextPartShadow, MethodContextShadow, BlockContextShadow, MethodNotFound, StmProcessShadow
 from spyvm import model, constants, primitives, conftest, wrapper
 from spyvm.tool.bitmanipulation import splitter
 
-from rpython.rlib import jit
+from rpython.rlib import jit, rstm
 from rpython.rlib import objectmodel, unroll
 
+from rpython.rlib import rthread
+
+class STMForkException(Exception):
+
+    def __init__(self, w_frame, w_stm_process):
+        self.w_frame = w_frame
+        self.w_stm_process = w_stm_process
+
+class MyLock():
+    def __init__(self):
+        self.LOCK = None
+        self.a = 0
+
+mylock = MyLock()
+
+
+def my_little_thread():
+    while True:
+        acquired = mylock.LOCK.acquire(False)
+        if acquired:
+            mylock.a = 2
+            #print "MY 2:", mylock.a
+            time.sleep(2.5)
+            mylock.LOCK.release()
+        else:
+            pass
+            #print "MY locked 10:", mylock.a
+
+def yours_little_thread():
+    while True:
+        acquired = mylock.LOCK.acquire(False)
+        if acquired:
+            mylock.a = 10
+            #print "YOURS 10:", mylock.a
+            mylock.LOCK.release()
+            time.sleep(4.0)
+        else:
+            pass
+            #print "YOURS locked 2:", mylock.a
+
+
+
 class MissingBytecode(Exception):
     """Bytecode not implemented yet."""
     def __init__(self, bytecodename):
         self.bytecodename = bytecodename
-        print "MissingBytecode:", bytecodename     # hack for debugging
+        #print "MissingBytecode:", bytecodename     # hack for debugging
 
 class IllegalStoreError(Exception):
     """Illegal Store."""
     name = method._w_self._likely_methodname
     return '%d: [%s]%s (%s)' % (pc, hex(bc), BYTECODE_NAMES[bc], name)
 
+class Bootstrapper(object):
+    """
+    Bootstrapper bootstrapping interpreters in some native thread.
+    It uses lock-guarded global state, as rpython does not pass arguments
+    to OS threads.
+    """
+
+    def __init__(self):
+        self.lock = None
+        # critical values, only modify under lock:
+        self.interp = None
+        self.w_frame = None
+        self.w_stm_process = None
+        self.num_threads = 0
+
+    def get_lock(self):
+        if self.lock is None:
+            self.lock = rthread.allocate_lock()
+        return self.lock
+
+    # wait for previous thread to start, then set global state
+    def acquire(interp, w_frame, w_stm_process):
+        bootstrapper.get_lock().acquire(True)
+        bootstrapper.interp = interp
+        bootstrapper.w_frame = w_frame
+        bootstrapper.w_stm_process = w_stm_process
+
+    acquire = staticmethod(acquire)
+
+    # lock is released once the new thread started
+    def release():
+        bootstrapper.interp = None
+        bootstrapper.w_frame = None
+        bootstrapper.w_stm_process = None
+        bootstrapper.get_lock().release()
+
+    release = staticmethod(release)
+
+    def bootstrap():
+        #print "New thread reporting"
+        interp = bootstrapper.interp
+        w_frame = bootstrapper.w_frame
+
+        w_stm_process = bootstrapper.w_stm_process
+
+        assert isinstance(interp, Interpreter)
+        assert isinstance(w_frame, model.W_PointersObject)
+        assert isinstance(w_stm_process, model.W_PointersObject)
+        bootstrapper.num_threads += 1
+        #print "Me is started", bootstrapper.num_threads
+        bootstrapper.release()
+
+        interp.interpret_with_w_frame(w_frame) #, may_context_switch=False
+
+        # cleanup
+        s_stm_process = w_stm_process.as_special_get_shadow(interp.space, StmProcessShadow)
+        s_stm_process.signal()
+
+        bootstrapper.num_threads -= 1
+
+    bootstrap = staticmethod(bootstrap)
+
+bootstrapper = Bootstrapper()
 
 class Interpreter(object):
     _immutable_fields_ = ["space", "image", "image_name",
                           "max_stack_depth", "interrupt_counter_size",
-                          "startup_time", "evented"]
+                          "startup_time", "evented",
+                          "vm_args", "smalltalk_args"]
     _w_last_active_context = None
     cnt = 0
     _last_indent = ""
         greens=['pc', 'self', 'method'],
         reds=['s_context'],
         virtualizables=['s_context'],
+        stm_do_transaction_breaks=True,
         get_printable_location=get_printable_location
     )
 
     def __init__(self, space, image=None, image_name="", trace=False,
-                 evented=True,
+                 evented=True, vm_args=['unknown'], smalltalk_args=[],
                  max_stack_depth=constants.MAX_LOOP_DEPTH):
         import time
         self.space = space
         self._loop = False
         self.next_wakeup_tick = 0
         self.evented = evented
+        self.vm_args = vm_args
+        self.smalltalk_args = smalltalk_args
         try:
             self.interrupt_counter_size = int(os.environ["SPY_ICS"])
         except KeyError:
         self.trace = trace
         self.trace_proxy = False
 
+    def fork_interpreter_thread(self, w_frame, w_stm_process):
+        new_interp = Interpreter(
+            self.space,
+            self.image,
+            self.image_name,
+            self.trace,
+            self.max_stack_depth)
+        new_interp.remaining_stack_depth = self.remaining_stack_depth
+        new_interp._loop = self._loop
+        new_interp.next_wakeup_tick = self.next_wakeup_tick
+        new_interp.interrupt_check_counter = self.interrupt_check_counter
+        new_interp.trace_proxy = self.trace_proxy
+
+        bootstrapper.acquire(new_interp, w_frame, w_stm_process)
+
+        rstm.set_transaction_length(1.0)
+
+        rthread.start_new_thread(bootstrapper.bootstrap, ())
+
     def interpret_with_w_frame(self, w_frame):
         try:
             self.loop(w_frame)
         self._loop = True
         s_new_context = w_active_context.as_context_get_shadow(self.space)
         while True:
-            assert self.remaining_stack_depth == self.max_stack_depth
+            #assert self.remaining_stack_depth == self.max_stack_depth
             # Need to save s_sender, c_loop will nil this on return
             s_sender = s_new_context.s_sender()
             try:
                     print "====== Switch from: %s to: %s ======" % (s_new_context.short_str(), p.s_new_context.short_str())
                 s_new_context = p.s_new_context
 
+    def _end_c_loop(self, s_context, pc, method):
+        if jit.we_are_jitted():
+            self.quick_check_for_interrupt(s_context,
+                            dec=self._get_adapted_tick_counter())
+            if rstm.jit_stm_should_break_transaction(True):
+                rstm.jit_stm_transaction_break_point()
+        self.jit_driver.can_enter_jit(
+            pc=pc, self=self, method=method,
+            s_context=s_context)
+    _end_c_loop._dont_inline_ = True
+
     def c_loop(self, s_context, may_context_switch=True):
         old_pc = 0
         if not jit.we_are_jitted() and may_context_switch:
         while True:
             pc = s_context.pc()
             if pc < old_pc:
-                if jit.we_are_jitted():
-                    self.quick_check_for_interrupt(s_context,
-                                    dec=self._get_adapted_tick_counter())
-                self.jit_driver.can_enter_jit(
-                    pc=pc, self=self, method=method,
-                    s_context=s_context)
-            old_pc = pc
+                self._end_c_loop(s_context, pc, method)
             self.jit_driver.jit_merge_point(
                 pc=pc, self=self, method=method,
                 s_context=s_context)
+            if rstm.jit_stm_should_break_transaction(False):
+                rstm.jit_stm_transaction_break_point()
+            old_pc = pc
             try:
                 self.step(s_context)
             except Return, nlr:
                     raise nlr
                 else:
                     s_context.push(nlr.value)
+            except STMForkException as fork_exception:
+                #print "Fork requested"
+                self.fork_interpreter_thread(fork_exception.w_frame, fork_exception.w_stm_process)
 
     def _get_adapted_tick_counter(self):
         # Normally, the tick counter is decremented by 1 for every message send.