1. Pypy
  2. Untitled project
  3. lang-smalltalk

Commits

Lars Wassermann  committed 1330f5e

added SIGNAL_AT_MILLISECONDS primitive and code which checks whether to signal

  • Participants
  • Parent commits 76bfdbc
  • Branches default

Comments (0)

Files changed (6)

File spyvm/constants.py

View file
  • Ignore whitespace
 SO_BYTEARRAY_CLASS = 26
 SO_PROCESS_CLASS = 27
 SO_COMPACT_CLASSES_ARRAY = 28
-SO_DELAY_SEMAPHORE = 29
+SO_TIMER_SEMAPHORE = 29
 SO_USER_INTERRUPT_SEMAPHORE = 30
 SO_FLOAT_ZERO = 31
 SO_LARGEPOSITIVEINTEGER_ZERO = 32
     "display" : SO_DISPLAY_OBJECT,
     "doesNotUnderstand" : SO_DOES_NOT_UNDERSTAND,
     "interrupt_semaphore" : SO_USER_INTERRUPT_SEMAPHORE,
+    "timerSemaphore" : SO_TIMER_SEMAPHORE,
 }
 
 LONG_BIT = 32
     primitive = primitive + (highbit << 10) ##XXX todo, check this
     assert tempsize >= numargs
     return primitive, literalsize, islarge, tempsize, numargs
+
+#___________________________________________________________________________
+# Interpreter constants
+#
+
+MAX_LOOP_DEPTH = 100
+INTERRUPT_COUNTER_SIZE = 1000

File spyvm/interpreter.py

View file
  • Ignore whitespace
         self.max_stack_depth = max_stack_depth
         self.remaining_stack_depth = max_stack_depth
         self._loop = False
+        self.next_wakeup_tick = 0
+        self.interrupt_check_counter = constants.INTERRUPT_COUNTER_SIZE
 
     def interpret_with_w_frame(self, w_frame):
         try:
         # padding = ' ' * (self.max_stack_depth - self.remaining_stack_depth)
         # print padding + s_context.short_str()
         old_pc = 0
+        if not jit.we_are_jitted():
+            self.quick_check_for_interrupt(s_context)
         while True:
             pc = s_context._pc
             method = s_context.s_method()
             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)
                 else:
                     s_context.push(nlr.value)
 
+    def _get_adapted_tick_counter(self):
+        # Normally, the tick counter is decremented by 1 for every message send.
+        # Since we don't know how many messages are called during this trace, we
+        # just decrement by 10th of the trace length (num of bytecodes).
+        trace_length = jit.current_trace_length()
+        decr_by = int(trace_length // 10)
+        return max(decr_by, 1)
+
     def stack_frame(self, s_new_frame):
         if not self._loop:
             return s_new_frame # this test is done to not loop in test,
         except ReturnFromTopLevel, e:
             return e.object
 
+    def quick_check_for_interrupt(self, s_frame, dec=1):
+        self.interrupt_check_counter -= dec
+        if self.interrupt_check_counter <= 0:
+            self.interrupt_check_counter = constants.INTERRUPT_COUNTER_SIZE
+            self.check_for_interrupts(s_frame)
+
+    def check_for_interrupts(self, s_frame):
+        # parallel to Interpreter>>#checkForInterrupts
+        import time, math
+
+        # Profiling is skipped
+        # We don't adjust the check counter size
+
+        # use the same time value as the primitive MILLISECOND_CLOCK
+        now = int(math.fmod(time.time()*1000, constants.TAGGED_MAXINT/2))
+
+        # XXX the low space semaphore may be signaled here
+        # Process inputs
+        # Process User Interrupt?
+        if not self.next_wakeup_tick == 0 and now >= self.next_wakeup_tick:
+            self.next_wakeup_tick = 0
+            semaphore = self.space.objtable["w_timerSemaphore"]
+            if not semaphore.is_same_object(self.space.w_nil):
+                wrapper.SemaphoreWrapper(self.space, semaphore).signal(s_frame.w_self())
+        # We have no finalization process, so far.
+        # We do not support external semaphores.
+            # In cog, the method to add such a semaphore is only called in GC.
+
+
+
 class ReturnFromTopLevel(Exception):
     def __init__(self, object):
         self.object = object

File spyvm/primitives.py

View file
  • Ignore whitespace
 #____________________________________________________________________________
 # Time Primitives (135 - 137)
 MILLISECOND_CLOCK = 135
+SIGNAL_AT_MILLISECONDS = 136
 SECONDS_CLOCK = 137
 
 @expose_primitive(MILLISECOND_CLOCK, unwrap_spec=[object])
 def func(interp, s_frame, w_arg):
-    import time
-    import math
+    import time, math
     return interp.space.wrap_int(int(math.fmod(time.time()*1000, constants.TAGGED_MAXINT/2)))
 
+@expose_primitive(SIGNAL_AT_MILLISECONDS, unwrap_spec=[object, object, int])
+def func(interp, s_frame, w_delay, w_semaphore, timestamp):
+    if not w_semaphore.getclass(interp.space).is_same_object(
+            interp.space.w_Semaphore):
+        interp.space.objtable["w_timerSemaphore"] = interp.space.w_nil
+        interp.next_wakeup_tick = timestamp
+    else:
+        interp.space.objtable["w_timerSemaphore"] = w_semaphore
+        interp.next_wakeup_tick = timestamp
+    return w_delay
+
+
 
 secs_between_1901_and_1970 = rarithmetic.r_uint((69 * 365 + 17) * 24 * 3600)
 
     return wrapper.SemaphoreWrapper(interp.space, w_rcvr).wait(s_frame.w_self())
 
 @expose_primitive(RESUME, unwrap_spec=[object], result_is_new_frame=True)
-def func(interp, s_frame, w_rcvr,):
+def func(interp, s_frame, w_rcvr):
     # XXX we might want to disable this check
     if not w_rcvr.getclass(interp.space).is_same_object(
         interp.space.w_Process):
     return w_frame.as_context_get_shadow(interp.space)
 
 @expose_primitive(SUSPEND, unwrap_spec=[object], result_is_new_frame=True)
-def func(interp, s_frame, w_rcvr, result_is_new_frame=True):
+def func(interp, s_frame, w_rcvr):
     # XXX we might want to disable this check
     if not w_rcvr.getclass(interp.space).is_same_object(
         interp.space.w_Process):

File spyvm/test/test_miniimage.py

View file
  • Ignore whitespace
     SO_BYTEARRAY_CLASS = 26
     SO_PROCESS_CLASS = 27
     SO_COMPACT_CLASSES_ARRAY = 28
-    SO_DELAY_SEMAPHORE = 29
+    SO_TIMER_SEMAPHORE = 29
     SO_USER_INTERRUPT_SEMAPHORE = 30
     SO_FLOAT_ZERO = 31
     SO_LARGEPOSITIVEINTEGER_ZERO = 32

File spyvm/test/test_primitives.py

View file
  • Ignore whitespace
     stop = prim(primitives.MILLISECOND_CLOCK, [0]).value
     assert start + 250 <= stop
 
+def test_signal_at_milliseconds():
+    import time
+    future = prim(primitives.MILLISECOND_CLOCK, [0]).value + 400
+    sema = space.w_Semaphore.as_class_get_shadow(space).new()
+    prim(primitives.SIGNAL_AT_MILLISECONDS, [space.w_nil, sema, future])
+    assert space.objtable["w_timerSemaphore"] is sema
+
 def test_inc_gc():
     # Should not fail :-)
     prim(primitives.INC_GC, [42]) # Dummy arg

File spyvm/todo.txt

View file
  • Ignore whitespace
 [ ] Implement image writer
 
 Shadows:
-[ ] Fix invalidation of methoddictshadow when the w_self of its values array changes
+[ ] What to do with shadows when their w_self changes class?
+[ ] Weak references for subclasses
 
 
 Optimizations:
             return model.W_SmallInteger(rerased.erase_int(val))
         except OverflowError:
             raise WrappingError("integer too large to fit into a tagged pointer")
+
+use special class for 1WordLargeIntegers