Ejemplo n.º 1
0
    def __init__(self, verbose=0, queue_params=None):

        # Whether or not to write status information
        self._verbose = verbose

        # Store queue parameters
        if queue_params is None:
            queue_params = BUF_MAX_LEN, 'old'
        if not (isinstance(queue_params, tuple) and len(queue_params) == 2):
            raise ValueError('queue_params should be a 2-element tuple.')
        self._queue_params = queue_params

        # Create unique key to identify this context
        self._id = UID().get_int()

        # Channels currently registered. Maps slots to channel instance.
        self._sending_channels = {}
        self._receiving_channels = {}

        # The list of connections
        self._connections = []
        self._connections_lock = threading.RLock()

        # Queue used during startup to collect packages
        # This queue is also subject to the _connections_lock
        self._startupQueue = PackageQueue(*queue_params)

        # For numbering and routing the packages
        self._send_seq = 0
        self._recv_seq = 0
        self._source_map = {}
Ejemplo n.º 2
0
    def __init__(self, context, slot_base, message_type=None):

        # Store context
        if not isinstance(context, Context):
            raise ValueError("Context not valid.")
        self._context = context

        # Check message type
        if message_type is None:
            message_type = TEXT
        if isinstance(message_type, type) and issubclass(
                message_type, MessageType):
            message_type = message_type()
        if isinstance(message_type, MessageType):
            message_type = message_type
        else:
            raise ValueError("message_type should be a MessageType instance.")

        # Store message type and conversion methods
        self._message_type_instance = message_type
        self.message_from_bytes = message_type.message_from_bytes
        self.message_to_bytes = message_type.message_to_bytes

        # Queue for incoming trafic (not used for pure sending channels)
        self._q_in = PackageQueue(*context._queue_params)

        # For sending channels: to lock the channel for sending
        self._send_condition = threading.Condition()
        self._is_send_locked = 0  # "True" is the timeout time

        # Signal for receiving data
        self._received_signal = yoton.events.Signal()
        self._posted_received_event = False

        # Channels can be closed
        self._closed = False

        # Event driven mode
        self._run_mode = 0

        # Init slots
        self._init_slots(slot_base)
Ejemplo n.º 3
0
class YotonApplication(object):
    """ YotonApplication
    
    Represents the yoton application and contains functions for
    the event system. Multiple instances can be created, they will
    all operate on the same event queue and share attributes
    (because these are on the class, not on the instance).
    
    One instance of this class is always accesible via yoton.app.
    For convenience, several of its methods are also accessible
    directly from the yoton module namespace.
    
    """

    # Event queues
    _event_queue = PackageQueue(10000, 'new')

    # Flag to stop event loop
    _stop_event_loop = False

    # Flag to signal whether we are in an event loop
    # Can be set externally if the event loop is hijacked.
    _in_event_loop = False

    # To allow other event loops to embed the yoton event loop
    _embedding_callback1 = None  # The reference
    _embedding_callback2 = None  # Used in post_event

    def call_later(self, func, timeout=0.0, *args, **kwargs):
        """ call_later(func, timeout=0.0, *args, **kwargs)
        
        Call the given function after the specified timeout.
        
        Parameters
        ----------
        func : callable
            The function to call.
        timeout : number
            The time to wait in seconds. If zero, the event is put on the event
            queue. If negative, the event will be put at the front of the event
            queue, so that it's processed asap.
        args : arguments
            The arguments to call func with.
        kwargs: keyword arguments.
            The keyword arguments to call func with.
        
        """

        # Wrap the object in an event
        event = Event(func, *args, **kwargs)

        # Put it in the queue
        if timeout > 0:
            self.post_event_later(event, timeout)
        elif timeout < 0:
            self.post_event_asap(event)  # priority event
        else:
            self.post_event(event)

    def post_event(self, event):
        """ post_event(events)
        
        Post an event to the event queue.
        
        """
        YotonApplication._event_queue.push(event)
        #
        if YotonApplication._embedding_callback2 is not None:
            YotonApplication._embedding_callback2 = None
            YotonApplication._embedding_callback1()

    def post_event_asap(self, event):
        """ post_event_asap(event)
        
        Post an event to the event queue. Handle as soon as possible;
        putting it in front of the queue.
        
        """
        YotonApplication._event_queue.insert(event)
        #
        if YotonApplication._embedding_callback2 is not None:
            YotonApplication._embedding_callback2 = None
            YotonApplication._embedding_callback1()

    def post_event_later(self, event, delay):
        """ post_event_later(event, delay)
        
        Post an event to the event queue, but with a certain delay.
        
        """
        event._timeout = time.time() + delay
        theTimerThread.add(event)
        # Calls post_event in due time

    def process_events(self, block=False):
        """ process_events(block=False)
        
        Process all yoton events currently in the queue.
        This function should be called periodically
        in order to keep the yoton event system running.
        
        block can be False (no blocking), True (block), or a float
        blocking for maximally 'block' seconds.
        
        """
        # Reset callback for the embedding event loop
        YotonApplication._embedding_callback2 = YotonApplication._embedding_callback1

        # Process events
        try:
            while True:
                event = YotonApplication._event_queue.pop(block)
                event.dispatch()
                block = False  # Proceed until there are now more events
        except PackageQueue.Empty:
            pass

    def start_event_loop(self):
        """ start_event_loop()
        
        Enter an event loop that keeps calling yoton.process_events().
        The event loop can be stopped using stop_event_loop().
        
        """

        # Dont go if we are in an event loop
        if YotonApplication._in_event_loop:
            return

        # Set flags
        YotonApplication._stop_event_loop = False
        YotonApplication._in_event_loop = True

        try:
            # Keep blocking for 3 seconds so a keyboardinterrupt still works
            while not YotonApplication._stop_event_loop:
                self.process_events(3.0)
        finally:
            # Unset flag
            YotonApplication._in_event_loop = False

    def stop_event_loop(self):
        """ stop_event_loop()
        
        Stops the event loop if it is running.
        
        """
        if not YotonApplication._stop_event_loop:
            # Signal stop
            YotonApplication._stop_event_loop = True

            # Push an event so that process_events() unblocks
            def dummy():
                pass

            self.post_event(Event(dummy))

    def embed_event_loop(self, callback):
        """ embed_event_loop(callback)
        
        Embed the yoton event loop in another event loop. The given callback
        is called whenever a new yoton event is created. The callback
        should create an event in the other event-loop, which should
        lead to a call to the process_events() method. The given callback
        should be thread safe.
        
        Use None as an argument to disable the embedding.
        
        """
        YotonApplication._embedding_callback1 = callback
        YotonApplication._embedding_callback2 = callback