home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / fnb101.zip / Lib / site-packages / Fnorb / orb / SelectReactor.py < prev    next >
Text File  |  1999-06-28  |  8KB  |  294 lines

  1. #!/usr/bin/env python
  2. #############################################################################
  3. # Copyright (C) DSTC Pty Ltd (ACN 052 372 577) 1997, 1998, 1999
  4. # All Rights Reserved.
  5. #
  6. # The software contained on this media is the property of the DSTC Pty
  7. # Ltd.  Use of this software is strictly in accordance with the
  8. # license agreement in the accompanying LICENSE.HTML file.  If your
  9. # distribution of this software does not contain a LICENSE.HTML file
  10. # then you have no rights to use this software in any manner and
  11. # should contact DSTC at the address below to determine an appropriate
  12. # licensing arrangement.
  13. #      DSTC Pty Ltd
  14. #      Level 7, GP South
  15. #      Staff House Road
  16. #      University of Queensland
  17. #      St Lucia, 4072
  18. #      Australia
  19. #      Tel: +61 7 3365 4310
  20. #      Fax: +61 7 3365 4311
  21. #      Email: enquiries@dstc.edu.au
  22. # This software is being provided "AS IS" without warranty of any
  23. # kind.  In no event shall DSTC Pty Ltd be liable for damage of any
  24. # kind arising out of or in connection with the use or performance of
  25. # this software.
  26. #
  27. # Project:      Fnorb
  28. # File:         $Source: /units/arch/src/Fnorb/orb/RCS/SelectReactor.py,v $
  29. # Version:      @(#)$RCSfile: SelectReactor.py,v $ $Revision: 1.18 $
  30. #
  31. #############################################################################
  32. """ A simple 'select' Reactor. """
  33.  
  34.  
  35. # Standard/built-in modules.
  36. import select
  37.  
  38. # Fnorb modules.
  39. import Reactor
  40.  
  41.  
  42. def SelectReactor_init():
  43.     """ Initialise the SelectReactor.
  44.  
  45.     There can only be one instance of any concrete reactor class per process.
  46.  
  47.     """
  48.     try:
  49.     reactor = SelectReactor()
  50.  
  51.     except Reactor.Reactor, reactor:
  52.     pass
  53.  
  54.     return reactor
  55.  
  56.  
  57. class SelectReactor(Reactor.Reactor):
  58.     """ The SelectReactor.
  59.  
  60.     This reactor uses a standard 'select' event loop.
  61.  
  62.     """
  63.     def __init__(self):
  64.     """ Constructor. """
  65.  
  66.     # There can be at most one instance of any concrete reactor class per
  67.     # process
  68.     if Reactor.Reactor._instance is not None:
  69.         # A reactor already exists.
  70.         raise Reactor.Reactor._instance
  71.  
  72.     Reactor.Reactor._instance = self
  73.  
  74.     # A dictionary of all registered event handlers. All handles in the
  75.     # SelectReactor are actually just file descriptors.
  76.     self.__handlers = {} # {Handle: (EventHandler, Mask)}
  77.  
  78.     return
  79.  
  80.     #########################################################################
  81.     # Reactor interface.
  82.     #########################################################################
  83.  
  84.     def register_handler(self, handler, mask):
  85.     """ Register an event handler. """
  86.  
  87.     # Get the event handler's underlying I/O handle.
  88.     handle = handler.handle()
  89.  
  90.     # If the handler is already registered then update the mask.
  91.     try:
  92.         # Find the event handler associated with the handle.
  93.         (handler, handler_mask) = self.__handlers[handle]
  94.  
  95.         # Update the mask.
  96.         handler_mask = handler_mask | mask
  97.  
  98.     # Otherwise, add the new handler.
  99.     except KeyError:
  100.         handler_mask = mask
  101.  
  102.     # Do the add/update.
  103.     self.__handlers[handle] = (handler, handler_mask)
  104.  
  105.     return
  106.  
  107.     def unregister_handler(self, handler, mask):
  108.     """ Withdraw a handler's registration. """
  109.  
  110.     # Get the event handler's underlying I/O handle.
  111.     handle = handler.handle()
  112.  
  113.     try:
  114.         # Find the event handler associated with the handle.
  115.         (handler, handler_mask) = self.__handlers[handle]
  116.  
  117.         # Update the mask.
  118.         handler_mask = handler_mask & ~mask
  119.  
  120.         # If the mask is now zero (ie. the handler is no longer interested
  121.         # in *any* events), then delete the handler.
  122.         if handler_mask == 0:
  123.         del self.__handlers[handle]
  124.  
  125.         # Otherwise, just update the handler's mask.
  126.         else:
  127.         self.__handlers[handle] = (handler, handler_mask)
  128.  
  129.     # Ignore any attempts to un-register a handler that wasn't registerd!
  130.     except KeyError:
  131.         pass
  132.  
  133.     return
  134.  
  135.     def start_event_loop(self, timeout=None):
  136.     """ Start the event loop. """
  137.  
  138.     self.__is_alive = 1
  139.     while self.__is_alive:
  140.         # Wait for and process a single event.
  141.         self.do_one_event(timeout)
  142.  
  143.     # Close all registered handlers.
  144.     self.__close_all_handlers()
  145.         
  146.     return
  147.  
  148.     def stop_event_loop(self):
  149.     """ Stop the event loop. """
  150.  
  151.     # This variable is checked before each call to 'do_one_event'.
  152.     self.__is_alive = 0
  153.  
  154.     return
  155.  
  156.     def do_one_event(self, timeout=None):
  157.     """ Dispatch a single event. """
  158.  
  159.     # Get the read/write/exception handles for all registered handlers.
  160.     (iwtd, owtd, ewtd) = self.__get_handles()
  161.  
  162.     # Blocking select (with timeout if specified).
  163.     if timeout is None:
  164.         (iwtd, owtd, ewtd) = select.select(iwtd, owtd, ewtd)
  165.         
  166.     else:
  167.         (iwtd, owtd, ewtd) = select.select(iwtd, owtd, ewtd, timeout)
  168.  
  169.     # Set up a 'try' block to catch 'KeyError' exceptions (sometimes
  170.     # handlers may remove themselves before we get to process them e.g
  171.     # if a handler has both a read and a write event then the processing
  172.     # of the read event could call 'unregister_handler' before the
  173.     # write event is processed).
  174.     try:
  175.         # Read events.
  176.         if len(iwtd) > 0:
  177.         for handle in iwtd:
  178.             # Find the event handler associated with the handle.
  179.             (handler, mask) = self.__handlers[handle]
  180.             
  181.             # Handler callback.
  182.             handler.handle_event(Reactor.READ)
  183.  
  184.         # Write events.
  185.         if len(owtd) > 0:
  186.         for handle in owtd:
  187.             # Find the event handler associated with the handle.
  188.             (handler, mask) = self.__handlers[handle]
  189.  
  190.             # Handler callback.
  191.             handler.handle_event(Reactor.WRITE)
  192.  
  193.         # Exceptional events.
  194.         if len(ewtd) > 0:
  195.         for handle in ewtd:
  196.             # Find the event handler associated with the handle.
  197.             (handler, mask) = self.__handlers[handle]
  198.  
  199.             # Handler callback.
  200.             handler.handle_event(Reactor.EXCEPTION)
  201.  
  202.     except KeyError:
  203.         pass
  204.  
  205.     return
  206.  
  207.     # The following two methods are provided to allow Fnorb events to be
  208.     # handled in other event loops.
  209.     def handles(self):
  210.     """ Return the read/write/exception handles for registered handlers.
  211.  
  212.     The return value is a tuple in the form:-
  213.  
  214.     ([ReadHandles], [WriteHandles], [ExceptionHandles])
  215.  
  216.     """
  217.     return self.__get_handles()
  218.  
  219.     def handle_one_event(self, handle, mask):
  220.     """ Handle a single event. """
  221.  
  222.     # Read event.
  223.     if mask & Reactor.READ:
  224.         # Find the event handler associated with the handle.
  225.         (handler, handler_mask) = self.__handlers[handle]
  226.         
  227.         # Handler callback.
  228.         handler.handle_event(Reactor.READ)
  229.  
  230.     # Write event.
  231.     if mask & Reactor.WRITE:
  232.         # Find the event handler associated with the handle.
  233.         (handler, handler_mask) = self.__handlers[handle]
  234.  
  235.         # Handler callback.
  236.         handler.handle_event(Reactor.WRITE)
  237.  
  238.     # Exception event.
  239.     if mask & Reactor.EXCEPTION:
  240.         # Find the event handler associated with the handle.
  241.         (handler, handler_mask) = self.__handlers[handle]
  242.  
  243.         # Handler callback.
  244.         handler.handle_event(Reactor.EXCEPTION)
  245.  
  246.     return
  247.  
  248.     #########################################################################
  249.     # Private interface.
  250.     #########################################################################
  251.  
  252.     def __get_handles(self):
  253.     """ Return the read/write/exception handles for registered handlers.
  254.  
  255.     The return value is a tuple in the form:-
  256.  
  257.     ([ReadHandles], [WriteHandles], [ExceptionHandles])
  258.  
  259.     """
  260.     iwtd = {}
  261.     owtd = {}
  262.     ewtd = {}
  263.  
  264.     for handle in self.__handlers.keys():
  265.         # Find the event handler associated with the handle.
  266.         (handler, mask) = self.__handlers[handle]
  267.  
  268.         if mask & Reactor.READ:
  269.         iwtd[handle] = None
  270.  
  271.         if mask & Reactor.WRITE:
  272.         owtd[handle] = None
  273.  
  274.         # Listen for errors on all handles.
  275.         ewtd[handle] = None
  276.  
  277.     return (iwtd.keys(), owtd.keys(), ewtd.keys())
  278.  
  279.     def __close_all_handlers(self):
  280.     """ Close all registered handlers. """
  281.  
  282.     # We work on a copy of the list, 'cos the handlers will most likely
  283.     # call 'unregister_handler' in their 'close' method which can cause
  284.     # them to be deleted from the handler dictionary, 'self.__handlers'.
  285.     for (handler, mask) in self.__handlers.values():
  286.         # Handler callback.
  287.         handler.handle_close()
  288.  
  289.     return
  290.  
  291. #############################################################################
  292.