#!/usr/bin/env python ############################################################################# # Copyright (C) DSTC Pty Ltd (ACN 052 372 577) 1997, 1998, 1999 # All Rights Reserved. # # The software contained on this media is the property of the DSTC Pty # Ltd. Use of this software is strictly in accordance with the # license agreement in the accompanying LICENSE.HTML file. If your # distribution of this software does not contain a LICENSE.HTML file # then you have no rights to use this software in any manner and # should contact DSTC at the address below to determine an appropriate # licensing arrangement. # # DSTC Pty Ltd # Level 7, GP South # Staff House Road # University of Queensland # St Lucia, 4072 # Australia # Tel: +61 7 3365 4310 # Fax: +61 7 3365 4311 # Email: enquiries@dstc.edu.au # # This software is being provided "AS IS" without warranty of any # kind. In no event shall DSTC Pty Ltd be liable for damage of any # kind arising out of or in connection with the use or performance of # this software. # # Project: Fnorb # File: $Source: /cvsroot/fnorb/fnorb/orb/ThreadedReactor.py,v $ # Version: @(#)$RCSfile: ThreadedReactor.py,v $ $Revision: 1.2 $ # ############################################################################# """ A simple threaded Reactor. """ # Standard/built-in modules. import thread # Fnorb modules. import Reactor def ThreadedReactor_init(): """ Initialise the ThreadedReactor. There can only be one instance of any concrete reactor class per process. """ try: reactor = ThreadedReactor() except Reactor.Reactor, reactor: pass return reactor class ThreadActive: def __init__(self): self.active = 1 def is_active(self): return self.active def deactivate(self): self.active = 0 class ThreadedReactor(Reactor.Reactor): """ The ThreadedReactor. """ def __init__(self): """ Constructor. """ # There can be at most one instance of any concrete reactor class per # process if Reactor.Reactor._instance is not None: # A reactor already exists. raise Reactor.Reactor._instance Reactor.Reactor._instance = self # A dictionary of all registered event handlers. All handles in the # ThreadedReactor are actually just file descriptors. self.__handlers = {} # {Handle: (ThreadActive, Handler, Mask)} return ######################################################################### # Reactor interface. ######################################################################### def __read(self, handler, thread_active): while thread_active.is_active(): handler.handle_event(Reactor.READ) def register_handler(self, handler, mask): """ Register an event handler. """ thread_active = ThreadActive() thread.start_new_thread(self.__read, (handler, thread_active)) self.__handlers[handler] = (thread_active, handler, mask) def unregister_handler(self, handler, mask): """ Withdraw a handler's registration. """ # Cleanly shut down the handling thread (thread_active, handler, mask) = self.__handlers[handler] thread_active.deactivate() def start_event_loop(self, timeout=None): """ Start the event loop. """ self.__is_alive = 1 while self.__is_alive: # Wait for and process a single event. self.do_one_event(timeout) # Close all registered handlers. self.__close_all_handlers() return def stop_event_loop(self): """ Stop the event loop. """ # This variable is checked before each call to 'do_one_event'. self.__is_alive = 0 return def do_one_event(self, timeout=None): """ Dispatch a single event. """ # Do nothing for the time being return # The following two methods are provided to allow Fnorb events to be # handled in other event loops. def handles(self): """ Return the read/write/exception handles for registered handlers. The return value is a tuple in the form:- ([ReadHandles], [WriteHandles], [ExceptionHandles]) """ return self.__get_handles() def handle_one_event(self, handle, mask): """ Handle a single event. """ # Read event. if mask & Reactor.READ: # Find the event handler associated with the handle. (thread_active, handler, handler_mask) = self.__handlers[handle] # Handler callback. handler.handle_event(Reactor.READ) # Write event. if mask & Reactor.WRITE: # Find the event handler associated with the handle. (thread_active, handler, handler_mask) = self.__handlers[handle] # Handler callback. handler.handle_event(Reactor.WRITE) # Exception event. if mask & Reactor.EXCEPTION: # Find the event handler associated with the handle. (thread_active, handler, handler_mask) = self.__handlers[handle] # Handler callback. handler.handle_event(Reactor.EXCEPTION) return ######################################################################### # Private interface. ######################################################################### def __get_handles(self): """ Return the read/write/exception handles for registered handlers. The return value is a tuple in the form:- ([ReadHandles], [WriteHandles], [ExceptionHandles]) """ iwtd = {} owtd = {} ewtd = {} for handle in self.__handlers.keys(): # Find the event handler associated with the handle. (thread_active, handler, mask) = self.__handlers[handle] if mask & Reactor.READ: iwtd[handle] = None if mask & Reactor.WRITE: owtd[handle] = None # Listen for errors on all handles. ewtd[handle] = None return (iwtd.keys(), owtd.keys(), ewtd.keys()) def __close_all_handlers(self): """ Close all registered handlers. """ # We work on a copy of the list, 'cos the handlers will most likely # call 'unregister_handler' in their 'close' method which can cause # them to be deleted from the handler dictionary, 'self.__handlers'. for (thread_active, handler, mask) in self.__handlers.values(): # Handler callback. handler.handle_close() return #############################################################################