The Design and Use of the ACE Reactor an Object-Oriented Framework for Event Demultiplexing
Total Page:16
File Type:pdf, Size:1020Kb
The Design and Use of the ACE Reactor An Object-Oriented Framework for Event Demultiplexing Douglas C. Schmidt and Irfan Pyarali g fschmidt,irfan @cs.wustl.edu Department of Computer Science Washington University, St. Louis 631301 1 Introduction create concrete event handlers by inheriting from the ACE Event Handler base class. This class specifies vir- This article describes the design and implementation of the tual methods that handle various types of events, such as Reactor pattern [1] contained in the ACE framework [2]. The I/O events, timer events, signals, and synchronization events. Reactor pattern handles service requests that are delivered Applications that use the Reactor framework create concrete concurrently to an application by one or more clients. Each event handlers and register them with the ACE Reactor. service of the application is implemented by a separate event Figure 1 shows the key components in the ACE Reactor. handler that contains one or more methods responsible for This figure depicts concrete event handlers that implement processing service-specific requests. In the implementation of the Reactor pattern described in this paper, event handler dispatching is performed REGISTERED 2: accept() by an ACE Reactor.TheACE Reactor combines OBJECTS 5: recv(request) 3: make_handler() the demultiplexing of input and output (I/O) events with 6: process(request) other types of events, such as timers and signals. At Logging Logging Logging Logging Handler Acceptor LEVEL thecoreoftheACE Reactor implementation is a syn- LEVEL Handler Handler chronous event demultiplexer, such as select [3] or APPLICATION APPLICATION Event Event WaitForMultipleObjects [4]. When the demulti- Event Event Handler Handler Handler plexer indicates the occurrence of designated events, the Handler ACE Reactor automatically dispatches the method(s) of 4: handle_input() 1: handle_input() pre-registered event handlers, which perform application- specified services in response to the events. Timer Handle LEVEL This paper is organized as follows: Section 2 describes LEVEL Signal Queue Table Handlers FRAMEWORK the primary features in the ACE Reactor framework; Sec- FRAMEWORK Initiation Dispatcher tion 3 outlines the OO design of the ACE Reactor im- plementation [2]; Section 4 examines several examples that Reactor demonstrate how the ACE Reactor simplifies the devel- OS EVENT DEMULTIPLEXING INTERFACE opment of concurrent, event-driven network applications; LEVEL LEVEL KERNEL Section 5 describes design rules to follow when using the KERNEL ACE Reactor to develop event-driven applications; and Section 6 presents concluding remarks. Figure 1: The Reactor Components 2 Features of the ACE Reactor the logging server described in Section 4. The ACE Reactor provides an OO demultiplexing and Automate event handler dispatching: When activity oc- dispatching framework that simplifies the development of curs on handles managed by an ACE Reactor, it auto- event-driven applications by providing the following fea- matically invokes the appropriate virtual methods on the tures: pre-registered concrete event handlers. C++ event handler objects are registered with the ACE Reactor, rather than Uniform OO demultiplexing and dispatching interface: stand-alone functions. Registering objects as event handlers Applications that use the ACE Reactor do not directly allows state to be retained between hook method invocations call low-level OS event demultiplexing APIs, such as on concrete event handlers. This style of OO programming select or WaitForMultipleObjects. Instead, they is useful for developing event handlers that hold state across 1 This work was supported in part by Siemens SCR. multiple callbacks by the ACE Reactor dispatcher. 1 Support transparent extensibility: The functionality of interface to applications, regardless of the native OS the ACE Reactor and its registered event handlers can be APIs. Moreover, the ACE Reactor uses design pat- extended transparently without modifying or recompiling ex- terns like Bridge [6] to enhance its internal portabil- isting code. To support this degree of extensibility, the Reac- ity. Thus, porting the ACE Reactor from select tor framework employs inheritance and dynamic binding to to WaitForMultipleObjects required only localized decouple the following two responsibilities: changes to the framework [7]. 1. Lower-level event demultiplexing and dispatching Thread-safety: The Reactor framework is fully thread- mechanisms – Low-level mechanisms managed by the safe. Therefore multiple threads can safely share a single ACE Reactor include detecting events on multiple ACE Reactor. Likewise, multiple ACE Reactors can I/O handles, expiring timers, and dispatching the appro- run in separate threads within a process. The Reactor frame- priate event handler methods to process these events. work provides the necessary synchronization mechanisms to prevent race conditions and intra-class method deadlock [8]. 2. Higher-level policies defined by applications to pro- cess events – Higher-level policies performed by Efficient demultiplexing: The ACE Reactor performs application-specified concrete event handlers include its event demultiplexing and dispatching logic efficiently. connection establishment strategies, data encoding and For instance, the select-based ACE Reactor uses the decoding, and processing of service requests from ACE Handle Set class described in Section 3.2 to avoid clients. For instance, the TAO [5] CORBA ORB uses examining fd set bitmasks one bit at a time. This op- the Reactor framework to separate its low-level event timization is based on a sophisticated algorithm that uses demultiplexing mechanisms from its higher-level poli- the C++ exclusive-or operator to reduce run-time complexity cies for GIOP connection management and protocol from O(number of total bits) to O(number of enabled bits), processing [5]. which can substantially reduce run-time overhead. Increase reuse: The ACE Reactor’s demultiplexing and dispatching mechanisms can be reused by many net- 3 The OO Design of the Reactor work applications. By reusing, rather than reinventing, Framework these mechanisms, developers can concentrate on higher- level application-specific event handler policies, rather than This section describes the OO design of the ACE Reactor wrestling repeatedly with low-level event demultiplexing framework. We focus on the structure of its components and dispatching mechanisms. and key design decisions. Where appropriate, implemen- Developers who write programs using low-level event de- tation details are also discussed. Section 3.1 outlines the multiplexing operations OS platform-independent components and Section 3.2 cov- like select and WaitForMultipleObjects directly ers the platform-dependent components. must reimplement, debug, and tune the same demultiplex- ing and dispatching code for every application. In contrast, 3.1 Platform-Independent Class Components all applications that utilize the ACE Reactor automatically reuse its features, as well as future enhancements and opti- This subsection summarizes the platform-independent mizations. classes in the Reactor framework, which include the Eliminate common error-prone programming details: ACE Reactor, ACE Time Value, ACE Timer Queue, The ACE Reactor shields application developers from and ACE Event Handler. error-prone details associated with programming low-level OS event demultiplexing APIs like select. These error- 3.1.1 The ACE Reactor Class prone details involve setting and clearing bitmasks, detect- The ACE Reactor defines the public interface for the ing and responding to interrupts, managing internal locks, Reactor framework. Figure 2 illustrates the key public and dispatching hook methods for I/O and timeout process- methods in the ACE Reactor class. The methods in the ing. For instance, the ACE Reactor eliminates several sub- ACE Reactor can be grouped into the following general tle causes of errors with select involving the misuse of categories: fd set bitmasks. Improve portability: The ACE Reactor runs atop sev- Manager methods: The constructor and open methods eral event demultiplexing mech- create and initialize objects of the ACE Reactor by dy- anisms, including WaitForMultipleObjects,which namically allocating various implementation objects de- is available on Win32, and select, which is avail- scribed in Section 3.2.1 and 3.2.2. The ACE Reactor’s able on Win32 and UNIX. The ACE Reactor shields destructor and close methods deallocate these objects. In applications from portability differences between the un- addition, to support the common use-case of one event loop derlying event demultiplexing mechanisms. As illus- per application process, there is a static instance method trated in Figure 6, the ACE Reactor exports the same that returns a pointer to a singleton ACE Reactor,which is created and managed by the Singleton pattern [6]. 2 I/O-related methods: Applications can register concrete class ACE_Reactor { event handlers that derive from ACE Event Handler with public: an ACE Reactor via its register handler method. enum { DEFAULT_SIZE = FD_SETSIZE }; Likewise, concrete event handlers can be removed via its // = Singleton access point. remove handler method. static ACE_Reactor *instance (void); Timer-related methods: The ACE Reactor’s timer // = Initialization and termination methods. strategy orders the event handlers that are scheduled with it // Initialize a Reactor instance that may according to their timeout deadlines. The methods provided // contain <size>