Exemplo n.º 1
0
def would_block(function):
    """
    Run the specified function in a nested transaction, abort the nested
    transaction to avoid any side effects being persisted, then return True if
    the function attempted to retry.
    """
    try:
        # Create a function to pass to or_else that runs the function, then
        # raises an exception to abort the nested transaction.
        def run_and_raise():
            function()
            # We need to abort this nested transaction to avoid the function's
            # side effects being persisted, and we don't differentiate between
            # a function that runs successfully and a function that raises an
            # exception (neither would retry), so just raise Exception here.
            raise Exception()
        # The call to stm.atomically isn't strictly necessary right now, but
        # I'm considering changing or_else to not revert the effects of a
        # function that ends up throwing an exception, in which case it would
        # be necessary.
        stm.atomically(lambda: stm.or_else(run_and_raise, lambda: None))
        # Function tried to retry
        return True
    except Exception:
        # Function didn't retry (either it threw an exception itself or it
        # succeeded, in which case we threw the exception for it)
        return False
Exemplo n.º 2
0
 def run(self):
     # There's no platform agnostic way to sleep in such a way that one can
     # be interrupted half-way through (indeed, threading.Condition
     # basically uses a busywait with exponentially increasing delays), so
     # we'll do the next best thing: check every second to see if we've lost
     # our reference to the variable to change and return if we did.
     # 
     # The main upside of this is that we guarantee that the transaction
     # will be interrupted precisely when the timeout expires, not up to
     # 50 milliseconds later as is possible with threading.Condition, but it
     # does mean that spare threads can hang around for up to a second if
     # a transaction returns on its own without a timeout happening.
     # 
     # At some point I'd like to write a ctypes wrapper around pthread,
     # which is used on every platform except Windows and which does have
     # proper timeout support, that's used on platforms that support it to
     # get rid of this delay, but it's not top priority right now.
     while time.time() < self.stop_time:
         # Sleep up to 1 second or the amount of time remaining until we're
         # supposed to time out, whichever is less
         time.sleep(min(1, max(0, self.stop_time - time.time())))
         if not self.var_ref():
             # Variable was garbage collected since a second ago, so return
             return
     var = self.var_ref()
     if var:
         # Still have a reference to the variable, so set it to True.
         stm.atomically(lambda: var.set(True))
Exemplo n.º 3
0
def main():
    with Bus() as bus:
        server = atomically(Server)
        ConsoleSink(server).start()
        autobus_service = SixjetService()
        atomically(lambda: server.provider_list.append(autobus_service))
        bus.create_service({"type": "sixjet"}, autobus_service)
        wait_for_interrupt()
    @atomically
    def _():
        server.running = False
Exemplo n.º 4
0
def with_timeout(stop_time, function):
    """
    A variant of with_delay that accepts its timeout as a number of seconds
    since the epoch at which the transaction should raise Timeout. 
    """
    var = make_timeout(stop_time)
    return stm.atomically(lambda: stm.or_else(function, lambda: wait_then_raise(var)))
Exemplo n.º 5
0
 def run(self):
     while True:
         try:
             new_state = atomically(self.wait_for_new_state)
             self.write(new_state)
         except StopException:
             self.write({})
             return
Exemplo n.º 6
0
 def __init__(self, server, map=default_map,
              names=[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16],
              levels=".123456789^"):
     self.server = server
     self.map = map
     self.names = names
     self.levels = levels
     self.last_state = atomically(TDict)
Exemplo n.º 7
0
 def run(self):
     self.write([[0 for _ in g] for g in self.state_names])
     while True:
         try:
             new_state = atomically(self.wait_for_new_state)
             self.write(new_state)
         except StopException:
             self.write([[0 for _ in g] for g in self.state_names])
             return
Exemplo n.º 8
0
 def flash(self, *jets):
     """
     Turns the specified jets on, then turns them off after the number of
     seconds specified by the flash_time object on this service. The flash
     time can be adjusted by calling set_flash_time or update_flash_time.
     I'll probably add a mechanism later for specifying a custom flash time
     when calling flash.
     """
     flasher = atomically(lambda: Flasher(jets, self.flash_time, self.provider_list))
     flasher.schedule()
Exemplo n.º 9
0
def make_timeout(stop_time):
    """
    A variant of make_delay that sets the returned TVar to True when
    time.time() becomes greater than stop_time.
    """
    if stm._stm_state.current:
        raise Exception("Timeout vars cannot be created inside a transaction")
    var = stm.atomically(lambda: stm.TVar(False))
    _TimeoutThread(var, stop_time).start()
    return var
Exemplo n.º 10
0
 def __init__(self, server,
              state_names=[[1, 2, 3, 4, 5, 6, 7, 8], [9, 10, 11, 12, 13, 14, 15, 16]],
              data_pins=[DATA_A, DATA_B], strobe_pin=STROBE, clock_pin=CLOCK):
     self.server = server
     self.state_names = state_names
     self.flat_state_names = [name for l in state_names for name in l]
     self.data_pins = data_pins
     self.strobe_pin = strobe_pin
     self.clock_pin = clock_pin
     self.port = Parallel()
     self.write_function = self.port.setData
     self.last_state = atomically(TDict)
Exemplo n.º 11
0
def atomically_watch(function, callback=None):
    """
    A wrapper around stm.watch that automatically runs the call inside a
    transaction. This is essentially equivalent to::
    
        stm.atomically(lambda: stm.watch(function, callback))
    
    but, as with stm.watch, atomically_watch can be used as a decorator by
    omitting the callback parameter. For example, the following could be used
    outside of a transaction to place a new watch::
    
        @atomically_watch(some_tvar.get)
        def _(result):
            ...do something...
    
    This would be equivalent to:
    
        @stm.atomically
        def _():
            @stm.watch(some_tvar.get)
            def _(result):
                ..do something..
    
    Note that the callback will (as callbacks always are) still be run inside
    a transaction. If you need to perform I/O in the callback, use
    stm.eventloop.scheduled_function to decorate the callback such that it will
    be run by the event loop outside of the scope of STM::
    
        @atomically_watch(some_tvar.get)
        @stm.eventloop.scheduled_function
        def _(result):
            print "Changed to " + str(result) # Or any other I/O
        
    """
    if callback is None:
        def decorator(actual_callback):
            atomically_watch(function, actual_callback)
        return decorator
    stm.atomically(lambda: stm.watch(function, callback))
Exemplo n.º 12
0
 def __init__(self):
     """
     Creates a new sixjet server. backend is the instance of backends.Backend
     that will be used to write jets. service_extra is an optionally-empty
     set of values that will be added to the Autobus 2's service info
     dictionary. (Keys such as type will be added automatically, but such
     keys present in service_extra will override the ones added
     automatically.)
     
     bus is the Autobus bus to use. You can usually just use:
     
     from autobus2 import Bus
     with Bus() as bus:
         server = SixjetServer(..., bus, ...)
         ...
     
     and things will work.
     """
     PyServiceProvider.__init__(self, True)
     ComplexProvider.__init__(self)
     self.flash_time = 0.25
     self.fixed_provider = atomically(FixedProvider)
     atomically(lambda: self.provider_list.append(self.fixed_provider))
Exemplo n.º 13
0
 def run(self):
     # Outside of STM only
     if stm._stm_state.current:
         raise Exception("This must be called outside of a transaction.")
     while True:
         next_event = stm.atomically(self._endpoint.get)
         if next_event is None:
             print "Event loop exiting"
             return
         try:
             next_event()
         except:
             print "Event threw an exception, which will be ignored."
             print "For reference, the exception is:"
             traceback.print_exc()
Exemplo n.º 14
0
 def state(self):
     """
     The state this thread is currently in. This will be one of:
     
      * NEW: This thread has been created but start() has not yet been
        called
     
      * STARTED: start() has been called but the thread has not yet
        commenced execution. Threads started from within a transaction will
        remain in STARTED until shortly after the transaction commits.
     
      * RUNNING: The thread has commenced execution.
      
      * FINISHED: The thread has died.
     """
     return stm.atomically(lambda: self._state)
Exemplo n.º 15
0
def changes_only(callback=None, according_to=None):
    """
    A decorator that can be used to decorate callbacks that are to be passed to
    stm.watch to filter out duplicate invocations with the same result value.
    It can be used either as::
    
        @changes_only
        def callback(result):
            ...
    
    or as::
    
        @changes_only(according_to=some_predicate)
        def callback(result):
            ...
    
    with the latter allowing a custom two-argument function to be used to
    compare the equality of the value passed to a given invocation with the
    value passed to the previous invocation; the former compares values using
    the "is" operator.
    
    Note that the resulting callback will keep a reference around to the last
    value with which it was called, so make sure you're not counting on this
    value's being garbage collected immediately after the callback is invoked.
    """
    if callback and according_to:
        last = stm.atomically(lambda: stm.TVar((False, None)))
        @functools.wraps(callback)
        def actual_callback(*args):
            # We use *args here to permit @changes_only to be used to decorate
            # methods on objects; in such cases, we'll be passed two arguments,
            # self and the actual result.
            result = args[-1]
            has_run, last_value = last.value
            if not has_run or not according_to(last_value, result):
                last.value = True, result
                callback(*args)
        return actual_callback
    elif callback:
        return changes_only(callback, operator.is_)
    elif according_to:
        def decorator(callback):
            return changes_only(callback, according_to)
        return decorator
    else:
        raise ValueError("Either callback or according_to must be specified")
Exemplo n.º 16
0
 def run(self):
     # Outside of STM only
     if stm._stm_state.current:
         raise Exception("This must be called outside of a transaction.")
     while True:
         next_event = stm.atomically(self._endpoint.get)
         if next_event is None:
             print "Event loop exiting"
             return
         try:
             next_event()
         except Exception:
             print "Event threw an exception, which will be ignored."
             print "For reference, the exception is:"
             traceback.print_exc()
         except:
             print "Event threw a non-standard exception:"
             traceback.print_exc()
             raise
Exemplo n.º 17
0
 def schedule(self, function):
     # In or out of STM
     if function is None:
         raise ValueError("function cannot be None")
     stm.atomically(lambda: self._queue.put(function))
Exemplo n.º 18
0
        if stm._stm_state.current:
            raise Exception("This must be called outside of a transaction.")
        while True:
            next_event = stm.atomically(self._endpoint.get)
            if next_event is None:
                print "Event loop exiting"
                return
            try:
                next_event()
            except:
                print "Event threw an exception, which will be ignored."
                print "For reference, the exception is:"
                traceback.print_exc()


default_event_loop = stm.atomically(EventLoop)
default_event_loop.start()

def schedule(function):
    """
    Schedule a function to be run later.
    
    This can be used from within a transaction to schedule a function to be
    called outside of the transaction, after it commits. The specified function
    will be run outside of the context of a transaction, so it can do things
    like I/O that transactions normally aren't allowed to do.
    
    Note that such functions are run synchronously and in the order they were
    scheduled. They should therefore complete quickly, or spawn a new thread
    (or make use of a stm.threadutils.ThreadPool) to do their work.
    """
Exemplo n.º 19
0
 def __str__(self):
     return "TDict(%r)" % stm.atomically(lambda: dict(self))
Exemplo n.º 20
0
 def __str__(self):
     return "TList(%r)" % stm.atomically(lambda: list(self))
Exemplo n.º 21
0
 def run(self):
     target = stm.atomically(lambda: self._target)
     target()
Exemplo n.º 22
0
 def wrapper(*args, **kwargs):
     return stm.atomically(lambda: function(*args, **kwargs))
Exemplo n.º 23
0
 def stop(self):
     # In or out of STM
     stm.atomically(lambda: self._queue.put(None))
Exemplo n.º 24
0
 def schedule(self, function):
     # In or out of STM
     if function is None:
         raise ValueError("function cannot be None")
     stm.atomically(lambda: self._queue.put(function))
Exemplo n.º 25
0
 def __str__(self):
     return "TDict(%r)" % stm.atomically(lambda: dict(self))
Exemplo n.º 26
0
 def stop(self):
     # In or out of STM
     stm.atomically(lambda: self._queue.put(None))
Exemplo n.º 27
0
 def wrapper(*args, **kwargs):
     return stm.atomically(lambda: function(*args, **kwargs))
Exemplo n.º 28
0
 def __str__(self):
     return "TList(%r)" % stm.atomically(lambda: list(self))