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 >
Wrap
Text File
|
1999-06-28
|
8KB
|
294 lines
#!/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: /units/arch/src/Fnorb/orb/RCS/SelectReactor.py,v $
# Version: @(#)$RCSfile: SelectReactor.py,v $ $Revision: 1.18 $
#
#############################################################################
""" A simple 'select' Reactor. """
# Standard/built-in modules.
import select
# Fnorb modules.
import Reactor
def SelectReactor_init():
""" Initialise the SelectReactor.
There can only be one instance of any concrete reactor class per process.
"""
try:
reactor = SelectReactor()
except Reactor.Reactor, reactor:
pass
return reactor
class SelectReactor(Reactor.Reactor):
""" The SelectReactor.
This reactor uses a standard 'select' event loop.
"""
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
# SelectReactor are actually just file descriptors.
self.__handlers = {} # {Handle: (EventHandler, Mask)}
return
#########################################################################
# Reactor interface.
#########################################################################
def register_handler(self, handler, mask):
""" Register an event handler. """
# Get the event handler's underlying I/O handle.
handle = handler.handle()
# If the handler is already registered then update the mask.
try:
# Find the event handler associated with the handle.
(handler, handler_mask) = self.__handlers[handle]
# Update the mask.
handler_mask = handler_mask | mask
# Otherwise, add the new handler.
except KeyError:
handler_mask = mask
# Do the add/update.
self.__handlers[handle] = (handler, handler_mask)
return
def unregister_handler(self, handler, mask):
""" Withdraw a handler's registration. """
# Get the event handler's underlying I/O handle.
handle = handler.handle()
try:
# Find the event handler associated with the handle.
(handler, handler_mask) = self.__handlers[handle]
# Update the mask.
handler_mask = handler_mask & ~mask
# If the mask is now zero (ie. the handler is no longer interested
# in *any* events), then delete the handler.
if handler_mask == 0:
del self.__handlers[handle]
# Otherwise, just update the handler's mask.
else:
self.__handlers[handle] = (handler, handler_mask)
# Ignore any attempts to un-register a handler that wasn't registerd!
except KeyError:
pass
return
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. """
# Get the read/write/exception handles for all registered handlers.
(iwtd, owtd, ewtd) = self.__get_handles()
# Blocking select (with timeout if specified).
if timeout is None:
(iwtd, owtd, ewtd) = select.select(iwtd, owtd, ewtd)
else:
(iwtd, owtd, ewtd) = select.select(iwtd, owtd, ewtd, timeout)
# Set up a 'try' block to catch 'KeyError' exceptions (sometimes
# handlers may remove themselves before we get to process them e.g
# if a handler has both a read and a write event then the processing
# of the read event could call 'unregister_handler' before the
# write event is processed).
try:
# Read events.
if len(iwtd) > 0:
for handle in iwtd:
# Find the event handler associated with the handle.
(handler, mask) = self.__handlers[handle]
# Handler callback.
handler.handle_event(Reactor.READ)
# Write events.
if len(owtd) > 0:
for handle in owtd:
# Find the event handler associated with the handle.
(handler, mask) = self.__handlers[handle]
# Handler callback.
handler.handle_event(Reactor.WRITE)
# Exceptional events.
if len(ewtd) > 0:
for handle in ewtd:
# Find the event handler associated with the handle.
(handler, mask) = self.__handlers[handle]
# Handler callback.
handler.handle_event(Reactor.EXCEPTION)
except KeyError:
pass
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.
(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.
(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.
(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.
(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 (handler, mask) in self.__handlers.values():
# Handler callback.
handler.handle_close()
return
#############################################################################