diff options
author | cdgill <cdgill@ae88bc3d-4319-0410-8dbf-d08b4c9d3795> | 1998-12-23 21:17:07 +0000 |
---|---|---|
committer | cdgill <cdgill@ae88bc3d-4319-0410-8dbf-d08b4c9d3795> | 1998-12-23 21:17:07 +0000 |
commit | 640c2bf479cdf36e71ec249787990fda36555ffd (patch) | |
tree | 7808136215b3a4b9c2d82c69d89e7d0d38511544 | |
parent | 09c60748098e06b7e752635a4d514db74a90830f (diff) | |
download | ATCD-640c2bf479cdf36e71ec249787990fda36555ffd.tar.gz |
changes related to new events tutorial
-rw-r--r-- | TAO/ChangeLog-98c | 12 | ||||
-rw-r--r-- | TAO/docs/events_tutorial.html | 1819 | ||||
-rw-r--r-- | TAO/orbsvcs/tests/EC_Throughput/ECT_Consumer.cpp | 14 | ||||
-rw-r--r-- | TAO/orbsvcs/tests/EC_Throughput/ECT_Consumer_Driver.cpp | 4 | ||||
-rw-r--r-- | TAO/orbsvcs/tests/EC_Throughput/ECT_Supplier_Driver.cpp | 4 |
5 files changed, 1842 insertions, 11 deletions
diff --git a/TAO/ChangeLog-98c b/TAO/ChangeLog-98c index 95d96a8ff7b..df7559b0006 100644 --- a/TAO/ChangeLog-98c +++ b/TAO/ChangeLog-98c @@ -1,3 +1,15 @@ +Wed Dec 23 15:16:00 CST 1998 Chris Gill <cdgill@cs.wustl.edu> + + * TAO/docs/events_tutorial.html: added tutorial on event channel. + Thanks to Carlos O'Ryan for ongoing help maintaining this, and to + Tim Harrison for providing the original version. + + * TAO/orbsvs/tests/EC_Throughput/ECT_Consumer.cpp + TAO/orbsvs/tests/EC_Throughput/ECT_Consumer_Driver.cpp + TAO/orbsvs/tests/EC_Throughput/ECT_Supplier_Driver.cpp: + converted a number of places to use the TAO_CHECK_ENV_RETURN_VOID + macro consistently, added comments, etc. + Wed Dec 23 14:44:04 EST 1998 Aniruddha Gokhale <gokhale@sahyadri.research.bell-labs.com> * TAO_IDL/be/be_visitor_sequence/gen_bounded_obj_sequence_ch.cpp: diff --git a/TAO/docs/events_tutorial.html b/TAO/docs/events_tutorial.html new file mode 100644 index 00000000000..c07ae139d88 --- /dev/null +++ b/TAO/docs/events_tutorial.html @@ -0,0 +1,1819 @@ +<html> +<head> +<title>Using the Real-Time Event Service</title> +</head> + +<BODY text = "#000000" +link="#000fff" +vlink="#ff0f0f" +bgcolor="#ffffff"> + +<br> +<br> + +<center> +<h1>Using the Real-Time Event Service</h1><P> + +<A HREF="http://www.cs.wustl.edu/~cdgill/">Chris Gill</a>, +<A HREF="http://www.cs.wustl.edu/~harrison/">Tim Harrison</a>, and +<A HREF="http://www.cs.wustl.edu/~coryan/">Carlos O'Ryan</a><br><br> + +<A HREF="mailto:cdgill@cs.wustl.edu">cdgill@cs.wustl.edu</a>, +<A HREF="mailto:harrison@cs.wustl.edu">harrison@cs.wustl.edu</a>, and +<A HREF="mailto:coryan@cs.wustl.edu">coryan@cs.wustl.edu</a><br> +</center> + +<br> +<br> + +<P><HR><P> +<!-- ************************************************************ --> + +<center> +<table cellpadding=10 border=0 cellspacing=4> +<tr><td> +<h2><a name="Section0">Overview</a></h2> +<BR> +<BR> +<tr><td> +<h3>Contents</h3> +<BR> +<ol> + <li> <a href="events_tutorial.html#Section0">Overview</a> + <li> <a href="events_tutorial.html#Section1">The COS Event Model</a> + <li> <a href="events_tutorial.html#Section2">Real-Time Event Service Enhancements</a> + <li> <a href="events_tutorial.html#Section3">The Real-Time Event Service</a> + <li> <a href="events_tutorial.html#Section4">Developing Consumers</a> + <li> <a href="events_tutorial.html#Section5">Developing Suppliers</a> + <li> <a href="events_tutorial.html#Section6">Caring For Your Event Channel</a> + <li> <a href="events_tutorial.html#Section7">Sample Applications</a> + <li> <a href="events_tutorial.html#Section8">Reference Materials</a> +</ol> + +<P><HR><P> +<tr><td> +<h3>Introduction</h3> +<BR> +This material is intended to provide an introduction to the COS Event Model, +the Real-Time extensions to that model in TAO, and a set of examples that +illustrate the techniques used to build systems using these models. The CORBA +Event Service provides a flexible model for asynchronous communication among +objects. However, the standard CORBAEvent Service specification lacks +important features required by real-time applications. These features include +event filtering, event correlation, and periodic event processing.<P> + +The standard CORBA operation invocation model supports twoway, oneway, +and deferred synchronous interactions between clients and servers. +The primary strength of the twoway model is its intuitive mapping onto +the <code>object->operation()</code> paradigm supported by OO languages. +In principle, twoway invocations simplify the development of +distributed applications by supporting an implicit request/response +protocol that makes remote operation invocations transparent to the +client. <P> + +In practice, however, the standard CORBA operation invocation models +are too restrictive for real-time applications. In particular, these +models lack asynchronous message delivery, do not support timed +invocations or group communication, and can lead to excessive polling +by clients. Moreover, standard oneway invocations might not implement +reliable delivery and deferred synchronous invocations require the use +of the CORBA Dynamic Invocation Interface (DII), which yields +<A HREF="http://www.cs.wustl.edu/~schmidt/GLOBECOM-96.ps.gz">excessive +overhead</A> for most real-time applications. <P> + +The Event Service is a CORBA Object Service (COS) that is designed to +alleviate some of the restrictions with standard CORBA invocation +models. In particular, the COS Event Service supports asynchronous +message delivery and allows one or more suppliers to send messages to +one or more consumers. Event data can be delivered from suppliers to +consumers without requiring these participants to know about each +other explicitly. <P> + +There are two models (<EM>i.e.</EM>, <EM>push</EM> vs. <EM>pull</EM>) +of participant collaborations in the COS Event Service architecture. +This material focuses on real-time enhancements to the push model, which +allows suppliers of events to initiate the transfer of event data to +consumers. Suppliers push events to the Event Channel, which in turn +pushes the events to consumers. <P> + +Suppliers use Event Channels to push data to consumers. Likewise, +consumers can explicitly pull data from suppliers. The push and pull +semantics of event propagation help to free consumers and suppliers +from the overly restrictive synchronous semantics of the standard +CORBA twoway communication model. In addition, Event Channels can +implement group communication by serving as a replicator, broadcaster, +or multicaster that forward events from one or more suppliers to +multiple consumers.<p> + +</table> +</center> + +<hr><P> +<!-- ************************************************************ --> + +<center><table cellpadding=1 border=0 cellspacing=4> +<tr><td align=center> +<center><h2><a name="Section1">The COS Event Model</a></h2></center> +</table></center> + +<table cellpadding=1 border=0 cellspacing=4> +<h3>Relationships Between Modules</h3> + +The role of each component in the COS Event Model is outlined +below:<P> + +<ul> + <li> <b><i>EventChannel</i></b> -- The EventChannel interface provides + two factory methods, which allow applications to obtain consumer and + supplier administration objects, respectively, and use them to create + the other objects described below, to connect to the event channel. <P> + + <li> <b><i>SupplierAdmin</i></b> -- The SupplierAdmin interface provides + factory methods which create the appropriate supplier proxy objects. <P> + + <li> <b><i>ConsumerAdmin</i></b> -- The ConsumerAdmin interface provides + factory methods which create the appropriate consumer proxy objects. <P> + + <li> <b><i>ProxyPullSupplier</i></b> -- The ProxyPullSupplier + interface is used by consumers in the pull model to connect and + disconnect from the channel. This interface inherits from the + PullSupplier interface, and acts as a proxy for the suppliers + from which the channel will pull events. <P> + + <li> <b><i>ProxyPushSupplier</i></b> -- The ProxyPushSupplier + interface is used by consumers in the push model to connect and + disconnect from the channel. This interface inherits from the + PushSupplier interface, and acts as a proxy for the suppliers + which will push events to the channel. <P> + + <li> <b><i>ProxyPullConsumer</i></b> -- The ProxyPullConsumer + interface is used by suppliers in the pull model to connect and + disconnect from the channel. This interface inherits from the + PullConsumer interface, and acts as a proxy for the consumers + on whose behalf the channel will pull events. <P> + + <li> <b><i>ProxyPushConsumer</i></b> -- The ProxyPushConsumer + interface is used by suppliers in the push model to connect and + disconnect from the channel. This interface inherits from the + PushConsumer interface, and acts as a proxy for the consumers + to which the channel will push events. <P> + + <li> <b><i>PullSupplier</i></b> -- The PullSupplier interface provides + the necessary methods of a supplier of events in the pull model. <P> + + <li> <b><i>PushSupplier</i></b> -- The PushSupplier interface provides + the necessary methods of a supplier of events in the push model. <P> + + <li> <b><i>PullConsumer</i></b> -- The PullConsumer interface provides + the necessary methods of a consumer of events in the pull model. <P> + + <li> <b><i>PushConsumer</i></b> -- The PushConsumer interface provides + the necessary methods of a consumer of events in the push model. <P> +</ul> + +<tr><td> +</table> +<br> +<br> +<center><table cellpadding=1 border=0 cellspacing=4> +<tr><td align=center> +<center><IMG SRC="http://www.cs.wustl.edu/~schmidt/gifs/ec_participants2.gif"></center> +</table></center> + +<P><hr width="75%"><P> <!-- intra-section separator --> + +<center><table cellpadding=1 border=0 cellspacing=4> +<h3>The Push Model</h3> +<tr><td> +<center><IMG SRC="http://www.cs.wustl.edu/~schmidt/gifs/ec_push.gif"></center> + +<tr><td> +<UL> + <LI> Consumers - Ultimate targets of events + <LI> Suppliers - Generate events + <LI> Event Channel - Decouple consumers and suppliers by propagating + events to consumers on behalf of suppliers +</UL> +</table></center> + +<P><HR><P> +<!-- ************************************************************ --> + +<center><table cellpadding=1 border=0 cellspacing=4> +<tr><td> + +<h2><a name="Section2">Real-Time Event Service Enhancements</a></h2> + +<tr><td> +<ul> + <li> <b><i>Prioritized dispatching within preemption + classes</i></b> -- The current implementation can dispatch + events in the same queue by their order of importance, which is + necessary to support priorities within a rate group. <p> + + <li> <b><i>Suspend/resume</i></b> -- If a consumer's event + dependencies change at run-time, it can utilize the + suspend/resume functionality through the new + <code>ProxyPushSupplier::suspend</code> and + <code>ProxyPushSupplier::resume</code> methods. When a + consumer invokes <code>ProxyPushSupplier::suspend</code>, the + dependencies registered with that proxy will be disabled until + the <code>resume</code> methods is called. These enhancements + allow run-time flexibility of event dependencies, but maintains + the determinism required by the system scheduling policy (i.e., + consumers can not add and remove dependencies at run-time - + just suspend and resume them).<p> + + <LI> <B><I>Event data model</I></B> -- The data model may use + unions, untyped buffers, or type anys.<P> + +<LI> <B><I>Event filtering</I></B> -- Consumers may register for +events based on event type, or supplier id. The event channel filters events +based on these registrations, to ensure efficient event delivery.<P> + +<LI> <B><I>Event correlation</I></B> -- Consumers may register +for event delivery based on conjunctive or disjunctive sets of events. Conjunctive +registrations cause the event channel to notify the consumer when <I>all</I> +events in the set have arrived. Disjunctive registrations cause the event channel +to notify the consumer when <I>any</I> event in the set has arrived.<P> + +<LI> <B><I>Periodic event processing</I></B> -- Consumers +may register for suppliers based on timed events. Periodic suppliers push events +into the channel at well defined intervals.<P> + + <LI> <B><I>Active consumers and suppliers</I></B> -- See + <a href="events_tutorial.html#Section3">The Real-Time Event Service</a><P>. + +</ul> +</table> +</center> + +<P><HR><P> +<!-- ************************************************************ --> + +<center><table cellpadding=1 border=0 cellspacing=4> +<tr><td align=center> +<h2><a name="Section3">The Real-Time Event Service</a></h2> +</table></center> + +<center><table cellpadding=1 border=0 cellspacing=4> +<h3>Real-Time ORB and Services</h3> +<tr><td> +<center><IMG SRC="http://www.cs.wustl.edu/~schmidt/gifs/corbaopt10.gif"></center> + +<br> +<center><tr><td> +<ul> + <li> Real-time event dispatching<P> + <UL> + <LI> Priority-based queueing and preemption mechanisms<P> + </UL> + <li> Centralized event filtering and correlation<P> + <ul> + <LI> Source/type-based filtering<P> + <LI> Conjunction/Disjunction (AND/OR) correlations<P> + </ul> + + <li> Periodic and Aperiodic processing <P> + <UL> + <LI> Canonical timeouts<P> + <LI> Dependency timeouts + </UL> +</ul> +</center> +</table></center> +<br> + +<P><hr width="75%"><P> <!-- intra-section separator --> + +<center><table cellpadding=1 border=0 cellspacing=4> +<tr><td align=center> +<h3>Real-Time Event Service Internals</h3> +<BR> +<tr><td> +<center><IMG SRC="http://www.cs.wustl.edu/~schmidt/gifs/ec_dispatching.gif"></center> +</table></center> +<br> + +<P><hr width="75%"><P> <!-- intra-section separator --> + +<center><table cellpadding=1 border=0 cellspacing=4> +<h3>Characteristics of Real-Time Push Event Service Participants</h3> + +<tr><td> +Two major roles are played by the participants in a real-time push event +service.<P> + +<tr><td> +The first role is that of an event consumer, which receives events from the +event channel. A consumer specifies the type and/or source id for each event +it is interested in receiving.<P> + +In hard real-time applications, a consumer must also specify RT_Info data for +each event it is interested in receiving, and any other events on which that +event depends. The RT_Info structure resides in the Scheduler, and is +accessed through the scheduler interface. A unique handle is returned to the +consumer when an RT_Info is created, which can then be used to set the +information in the RT_Info. An RT_Info handle may also be obtained via the +Scheduler's lookup method.<P> + +<tr><td> +The second role is that of an event supplier, which generates events and +passes them into the event channel. A supplier must specify its source id, +and the type of each event it will generate. + +<tr><td> +In hard real-time applications, a supplier must also specify RT_Info data for +the events it will generate. In particular, it must specify the maximum rate +at which it will generate each event. This information is used by a real-time +scheduler to assign appropriate dispatch priorities.<P> + +<tr><td> +Note that the event channel may also be configured to use a null scheduling service. This will +cause all operations to be dispatched at the same priority, and will not require the application +to specify worst case execution times, periods, etc. + +<tr><td> +The consumer and supplier roles may be combined, as illustrated in the tables below. There are +two main cases in which the roles are combined: a passive one termed Consumer/Supplier which +borrows a thread of execution to produce events, and an active one termed Supplier/Consumer +which produces events in its own thread. Both consume events and produce events.<P> +</table></center> + +<br> +<br> +<center><table cellpadding=4 border=1 cellspacing=4> +<h4>EC Roles and Specified RT_Info Contents</h4> + +<tr> +<th>EC Roles +<th>RT_Info Contents +<th>Domain Examples +</tr> + +<tr> +<td> Consumer +<td> dependencies (and optionally, importance) +<td> Display, Exception & Maintenance Logs +</tr> + +<tr> +<td> Consumer/Supplier +<td> dependencies (and optionally, importance) +<td> Navigation Component (NAV) +</tr> + +<tr> +<td> Supplier/Consumer +<td> rate, dependencies (and optionally, importance) +<td> Kalman Filter +</tr> + +<tr> +<td> Supplier +<td> rate +<td> Operator Control Panel, EC Reactor Threads +</tr> + +</table></center> +<BR> +<BR> + + +<center><table cellpadding=1 border=1 cellspacing=4> +<h4>EC Roles and Scheduler Dependency Chain</h4> + +<tr> +<th> EC Roles +<th> Scheduler Dependency Chain +</tr> + +<tr> +<td> Pure Consumer +<td> root node +</tr> + +<tr> +<td> Consumer/Supplier +<td> internal node +</tr> + +<tr> +<td> Supplier/Consumer +<td> internal node +</tr> + +<tr> +<td> Pure Supplier +<td> leaf node +</tr> + +</table></center> +<BR> +<BR> + +<center><table cellpadding=1 border=1 cellspacing=4> +<h4>EC Roles, Threading, and CORBA Roles</h4> + +<tr> +<th> EC Roles +<th> Activity +<th> Thread Behavior +<th> CORBA Roles +</tr> + +<tr> +<td> Pure Consumer +<td> Passive +<td> Threads optional, "internal", wait for an event to occur +<td> Servant +</tr> + +<tr> +<td> Consumer/Supplier +<td> Passive +<td> Threads optional, "internal", wait for an event to occur +<td> Client and/or Servant +</tr> + +<tr> +<td> Supplier/Consumer +<td> Active +<td> Threads required and visible to EC: consume events and actively produce other events +<td> Client and/or Servant +</tr> + +<tr> +<td> Pure Supplier +<td> Active +<td> Threads required and visible to EC: actively produce events +<td> Client +</tr> +</table></center> + +<P><hr width="75%"><P> <!-- intra-section separator --> + +<center><table cellpadding=1 border=0 cellspacing=4> +<tr><td> +<center><IMG SRC="http://www.cs.wustl.edu/~cdgill/ec_roles.GIF"></center> +</table></center> + +<P><hr width="75%"><P> <!-- intra-section separator --> + +<center><table cellpadding=1 border=0 cellspacing=4> +<tr><td> +<center><IMG SRC="http://www.cs.wustl.edu/~cdgill/ec_roles2.GIF"></center> +</table></center> + +<P><hr width="75%"><P> <!-- intra-section separator --> + +<center><table cellpadding=1 border=0 cellspacing=4> +<tr><td> +<center><IMG SRC="http://www.cs.wustl.edu/~cdgill/ec_backbone.GIF"></center> +</table></center> + +<P><hr width="75%"><P> <!-- intra-section separator --> + +<center><table cellpadding=1 border=0 cellspacing=4> +<tr><td> +<center><IMG SRC="http://www.cs.wustl.edu/~cdgill/distributed_ec_roles.GIF"></center> +</table></center> + +<P><hr width="75%"><P> <!-- intra-section separator --> + +<center><table cellpadding=1 border=0 cellspacing=4> +<tr><td> +<center><IMG SRC="http://www.cs.wustl.edu/~cdgill/ec_orb_view.GIF"></center> +</table></center> + +<P><HR><P> +<!-- ************************************************************ --> + +<center><table cellpadding=1 border=0 cellspacing=4> +<tr><td> +<center><h2><a name="Section4">Developing Consumers</a></h2></center> +<br> +<ul> + <li> <a href="events_tutorial.html#Section4_1">Providing QoS Information</a> + <li> <a href="events_tutorial.html#Section4_2">Connecting Consumers to the Event Channel</a> + <li> <a href="events_tutorial.html#Section4_3">Receiving Events</a> + <li> <a href="events_tutorial.html#Section4_4">Disconnecting Consumers from the Event Channel</a> +</ul> +</table></center> + +<P><hr width="75%"><P> <!-- intra-section separator --> +<center><table cellpadding=1 border=0 cellspacing=4> +<center><h3><a name="Section4_1">Providing QoS Information</a><h3></center><p> + +<tr><td> +The following steps are only necessary for applications that make use of the +Event Service's hard real-time features. Applications that do not need these +features and are configured with a null scheduler may skip the following +operations on the scheduling server. + +<tr><td> +For each operation, a Consumer should provide the worst case, expected, and +cached execution time for that operation. It must also specify criticality and +importance values for each operation. A real-time scheduler uses this information +to order dispatches within a set of operations whose dependencies have been met. + +<tr><td> +If it is a Consumer/Supplier (one which consumes an event and passively generates +one or more events from the thread in which it was called, as illustrated in the +tables above), it must provide dependencies on one or more other events to the +scheduler. + +<tr><td> +If it is a Supplier/Consumer (one which consumes an event and actively generates +one or more events from its own thread, as illustrated in the tables above), it +must also specify the rate at which it will generate the new events by passing a +positive value in the period argument to the scheduler set method. It may also +indicate a positive number of threads in which the dispatch will be made. If the +number of threads given is zero, but a period is specified, the number of threads +defaults to 1. + +</table> +</center> + + +<center><table cellpadding=1 border=0 cellspacing=4> + +<tr><td> +<pre> + + // Obtain a reference to the scheduler server. + RtecScheduler::Scheduler_ptr server = + ACE_Scheduler_Factory::server (); + + // Create new RT_Info descriptors for three events. + + RtecScheduler::handle_t handle1 = + server->create ("event_1", // Name of entry point + TAO_TRY_ENV // Environment + ); + + RtecScheduler::handle_t handle2 = + server->create ("event_2", // Name of entry point + TAO_TRY_ENV // Environment + ); + + RtecScheduler::handle_t handle3 = + server->create ("event_3", // Name of entry point + TAO_TRY_ENV // Environment + ); + + + // Register as a consumer/supplier: act as a supplier of event_1 but with + // a consumer dependency on event_3. Therefore, the actual period and + // number of threads for event_1 depends on the characteristics of event_3. + server->set (handle1, // RT_Info handle + RtecScheduler::HIGH_CRITICALITY, // Criticality + 500, // Worst case time (in 100 nanosecs) + 500, // Typical time (in 100 nanosecs) + 500, // Cached time (in 100 nanosecs) + 0, // Period - will depend on event_3 + RtecScheduler::LOW_IMPORTANCE, // Importance + 0, // Quantum (unused) + 0, // Threads - will depend on event_3 + RtecScheduler::OPERATION, // Info type + TAO_TRY_ENV); + + // Register as a producer of event_2. + server->set (handle2, // RT_Info handle + RtecScheduler::HIGH_CRITICALITY, // Criticality + 500, // Worst case time (in 100 nanosecs) + 500, // Typical time (in 100 nanosecs) + 500, // Cached time (in 100 nanosecs) + 50000 * 10, // Period in 100 nsec (= 20 Hz) + RtecScheduler::LOW_IMPORTANCE, // Importance + 0, // Quantum (unused) + 1, // Threads + RtecScheduler::OPERATION, // Info type + TAO_TRY_ENV); + + // Register as a consumer of event_3. + server->set (handle3, // RT_Info handle + RtecScheduler::HIGH_CRITICALITY, // Criticality + 500, // Worst case time (in 100 nanosecs) + 500, // Typical time (in 100 nanosecs) + 500, // Cached time (in 100 nanosecs) + 0, // Period - will depend on supplier + RtecScheduler::LOW_IMPORTANCE, // Importance + 0, // Quantum (unused) + 0, // Threads - will depend on supplier + RtecScheduler::OPERATION, // Info type + TAO_TRY_ENV); + + + // Establish a dependency of event_1 on event_3. + server->add_dependency (handle1, // handle that depends + handle3, // handle that is depended on + 1, // number of calls per event occurance + TAO_TRY_ENV // environment + ); + + +</pre> +</table> +</center> + +<P><hr width="75%"><P> <!-- intra-section separator --> + +<center><table cellpadding=1 border=0 cellspacing=4> +<h3> +<a name="Section4_2">Connecting Consumers to the Event Channel</a> +</h3> + +<tr><td> +The following code is derived from the EC_Throughput consumer code, which can be +found in TAO in the file: +<A HREF="http://www.cs.wustl.edu/~schmidt/ACE_wrappers/TAO/orbsvcs/tests/EC_Throughput/ECT_Consumer.cpp"> +$TAO_ROOT/orbsvcs/tests/EC_Throughput/ECT_Consumer.cpp</a> + +<tr><td> +<pre> + +void +Test_Consumer::connect (const char* name, + int event_a, int event_b, + RtecEventChannelAdmin::EventChannel_ptr ec, + CORBA::Environment& _env) +{ + + // Register operations with the scheduling service. The following steps are + // only necessary for applications that make use of the Event Service's hard + // real-time features. Applications that do not need these features and are + // configured with a null scheduler may skip the following operations on the + // scheduling server. + + // Obtain a reference to the scheduler from the ACE_Scheduler_Factory. + RtecScheduler::Scheduler_ptr server = + ACE_Scheduler_Factory::server (); + + // Create a new RT_Info entry for the function identifier + // we were passed, and hang onto the handle to the RT_Info. + RtecScheduler::handle_t rt_info = + server->create (name, _env); + TAO_CHECK_ENV_RETURN_VOID(_env); + + // Set the attributes for the RT_Info. + ACE_Time_Value tv (0, 2000); + TimeBase::TimeT time; + ORBSVCS_Time::Time_Value_to_TimeT (time, tv); + server->set (rt_info, + RtecScheduler::VERY_HIGH_CRITICALITY, + time, time, time, + 0, + RtecScheduler::VERY_LOW_IMPORTANCE, + time, + 0, + RtecScheduler::OPERATION, + _env); + TAO_CHECK_ENV_RETURN_VOID(_env); + + // Specify a disjunctive dependency on the arrival of event_a, the arrival + // of event b, OR the arrival of an event service shutdown event. Note that + // the same RT_Info is used for each event. This can be used to simplify + // code in applications using a null scheduler, or to consolidate events + // with identical characteristics in hard real-time applications. + ACE_ConsumerQOS_Factory qos; + qos.start_disjunction_group (); + qos.insert_type (ACE_ES_EVENT_SHUTDOWN, rt_info); + qos.insert_type (event_a, rt_info); + qos.insert_type (event_b, rt_info); + + // = Connect as a consumer. + + // Obtain a reference to the consumer administration object. + RtecEventChannelAdmin::ConsumerAdmin_var consumer_admin = + ec->for_consumers (_env); + TAO_CHECK_ENV_RETURN_VOID(_env); + + // Obtain a reference to the push supplier proxy. + this->supplier_proxy_ = + consumer_admin->obtain_push_supplier (_env); + TAO_CHECK_ENV_RETURN_VOID(_env); + + // Obtain a reference to this object. + RtecEventComm::PushConsumer_var objref = this->_this (_env); + TAO_CHECK_ENV_RETURN_VOID(_env); + + // Connect as a consumer. + this->supplier_proxy_->connect_push_consumer (objref.in (), + qos.get_ConsumerQOS (), + _env); + TAO_CHECK_ENV_RETURN_VOID(_env); +} + +</pre> + +<tr><td> +The following code is derived from the EC_Throughput consumer driver code, which +can be found in TAO in the file: +<A HREF="http://www.cs.wustl.edu/~schmidt/ACE_wrappers/TAO/orbsvcs/tests/EC_Throughput/ECT_Consumer_Driver.cpp"> +$TAO_ROOT/orbsvcs/tests/EC_Throughput/ECT_Consumer_Driver.cpp</a> + +<tr><td> +<pre> + +int +ECT_Consumer_Driver::run (int argc, char* argv[]) +{ + // argc/argv are used to initialize the ORB and the options + // for this particular test. Other applications may hard-code + // the ORB options, obtain them from another source, etc. + + TAO_TRY + { + // The use of TAO_TRY macros isolate us from the differences + // between platforms with and without native C++ exceptions. + // This is work in progress and may change in the future! + + // Below is some boiler plate code to initialize the ORB and + // the POA. Notice that applications that connect to the Event + // Channel play the server role in some instances, because + // they receive push() requests (as Consumers) or + // disconnect_push_supplier() requests (as Suppliers). + + // Initialize the ORB reference. + this->orb_ = + CORBA::ORB_init (argc, argv, "", TAO_TRY_ENV); + TAO_CHECK_ENV; + + // Initialize the root POA reference. + CORBA::Object_var poa_object = + this->orb_->resolve_initial_references("RootPOA"); + if (CORBA::is_nil (poa_object.in ())) + ACE_ERROR_RETURN ((LM_ERROR, + " (%P|%t) Unable to initialize the POA.\n"), + 1); + + // Obtain the narrowed root POA reference. + PortableServer::POA_var root_poa = + PortableServer::POA::_narrow (poa_object.in (), TAO_TRY_ENV); + TAO_CHECK_ENV; + + // Obtain a reference to the POA manager. + PortableServer::POAManager_var poa_manager = + root_poa->the_POAManager (TAO_TRY_ENV); + TAO_CHECK_ENV; + + // Now some boiler plate code to obtain a reference to the + // naming service..... + + // Resolve a reference to the naming service. + CORBA::Object_var naming_obj = + this->orb_->resolve_initial_references ("NameService"); + if (CORBA::is_nil (naming_obj.in ())) + ACE_ERROR_RETURN ((LM_ERROR, + " (%P|%t) Unable to get the Naming Service.\n"), + 1); + + // Narrow the naming service reference. + CosNaming::NamingContext_var naming_context = + CosNaming::NamingContext::_narrow (naming_obj.in (), TAO_TRY_ENV); + TAO_CHECK_ENV; + + // Use the Naming Service to locate the Scheduling Service and + // use the Scheduler_Factory to keep a global pointer to the + // latter. + + // Initialize the scheduler factory to operate in configuration mode. + if (ACE_Scheduler_Factory::use_config (naming_context.in ()) == -1) + return -1; + + // Use the Naming Service to locate the Event Service.... + + // Set up the event service lookup name. + CosNaming::Name name (1); + name.length (1); + name[0].id = CORBA::string_dup ("EventService"); + + // Resolve a reference to the event service. + CORBA::Object_var ec_obj = + naming_context->resolve (name, TAO_TRY_ENV); + TAO_CHECK_ENV; + + // Narrow the reference to the event service. + RtecEventChannelAdmin::EventChannel_var channel; + if (CORBA::is_nil (ec_obj.in ())) + channel = RtecEventChannelAdmin::EventChannel::_nil (); + else + channel = RtecEventChannelAdmin::EventChannel::_narrow (ec_obj.in (), + TAO_TRY_ENV); + TAO_CHECK_ENV; + + // Activate the POA so we can start receiving requests... + + // Activate the POA manager. + poa_manager->activate (TAO_TRY_ENV); + TAO_CHECK_ENV; + + // Connect consumers to the event service. + this->connect_consumers (channel.in (), TAO_TRY_ENV); + TAO_CHECK_ENV; + + ACE_DEBUG ((LM_DEBUG, "connected consumer(s)\n")); + ACE_DEBUG ((LM_DEBUG, "running the test\n")); + + // Run the event loop. + if (this->orb_->run () == -1) + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "orb->run"), -1); + ACE_DEBUG ((LM_DEBUG, "event loop finished\n")); + + this->dump_results (); + + // Disconnect consumers from the event service. + this->disconnect_consumers (TAO_TRY_ENV); + TAO_CHECK_ENV; + + // Destroy the event service. + channel->destroy (TAO_TRY_ENV); + TAO_CHECK_ENV; + } + TAO_CATCH (CORBA::SystemException, sys_ex) + { + TAO_TRY_ENV.print_exception ("SYS_EX"); + } + TAO_CATCHANY + { + TAO_TRY_ENV.print_exception ("NON SYS EX"); + } + TAO_ENDTRY; + return 0; +} + +</pre> +</table> +</center> + +<P><hr width="75%"><P> <!-- intra-section separator --> + +<!-- Must be after suppliers connect. --> + +<center><table cellpadding=1 border=0 cellspacing=4> +<h3><a name="Section4_3">Receiving Events</a></h3><p> + +<tr><td> +The following code is derived from the EC_Throughput consumer code, which +can be found in TAO in the file: +<A HREF="http://www.cs.wustl.edu/~schmidt/ACE_wrappers/TAO/orbsvcs/tests/EC_Throughput/ECT_Consumer.cpp"> +$TAO_ROOT/orbsvcs/tests/EC_Throughput/ECT_Consumer.cpp</a> + +<tr><td> +<pre> + +void +Test_Consumer::push (const RtecEventComm::EventSet& events, + CORBA::Environment &_env) +{ + // Make sure at least one event was pushed. + if (events.length () == 0) + { + // ACE_DEBUG ((LM_DEBUG, "no events\n")); + return; + } + + // Make sure only one thread has access. + ACE_GUARD (ACE_SYNCH_MUTEX, ace_mon, this->lock_); + + // We start the timer as soon as we receive the first event. + if (this->recv_count_ == 0) + this->timer_.start (); + + // Update the count of received events. + this->recv_count_ += events.length (); + + if (TAO_debug_level > 0 + && this->recv_count_ % 1000 == 0) + { + ACE_DEBUG ((LM_DEBUG, + "ECT_Consumer (%P|%t): %d events received\n", + this->recv_count_)); + } + + // Loop through the events, looking for shutdown events. + for (u_int i = 0; i < events.length (); ++i) + { + if (events[i].header.type == ACE_ES_EVENT_SHUTDOWN) + { + this->shutdown_count_++; + if (this->shutdown_count_ >= this->n_suppliers_) + { + // We stop the timer as soon as we realize it is time to + // do so. + this->timer_.stop (); + this->driver_->shutdown_consumer (this->cookie_, _env); + } + } + } +} + +</pre> +</table> +</center> + +<P><hr width="75%"><P> <!-- intra-section separator --> + +<center><table cellpadding=1 border=0 cellspacing=4> +<h3> +<a name="Section4_4">Disconnecting Consumers from the Event Channel</a> +</h3> + +<tr><td> +The following code is derived from the EC_Throughput consumer code, which can be +found in TAO in the file: +<A HREF="http://www.cs.wustl.edu/~schmidt/ACE_wrappers/TAO/orbsvcs/tests/EC_Throughput/ECT_Consumer.cpp"> +$TAO_ROOT/orbsvcs/tests/EC_Throughput/ECT_Consumer.cpp</a> + +<tr><td> +<pre> + +void +Test_Consumer::disconnect (CORBA::Environment &_env) +{ + // Make sure the supplier proxy reference is valid. + if (CORBA::is_nil (this->supplier_proxy_.in ())) + return; + + // Disconnect from further communication with the push + // supplier(s). Each consumer is represented by a unique + // ACE_ES_ConsumerModule instance. Which connection to + // disconnect is determined by the instance for the consumer. + this->supplier_proxy_->disconnect_push_supplier (_env); + TAO_CHECK_ENV_RETURN_VOID(_env); + + // Mark the supplier proxy reference invalid. + this->supplier_proxy_ = + RtecEventChannelAdmin::ProxyPushSupplier::_nil (); + + // We want to stop processing events for this consumer. Above, + // we disconnected the consumer from the Event Channel, so no + // more events will be sent, but we could have some events in + // transit. + + // Without a flushing protocol we need to deactivate the + // servant to stop accepting push () requests for any + // incoming events. + + // Deactivate the servant + PortableServer::POA_var poa = + this->_default_POA (_env); + TAO_CHECK_ENV_RETURN_VOID (_env); + PortableServer::ObjectId_var id = + poa->servant_to_id (this, _env); + TAO_CHECK_ENV_RETURN_VOID (_env); + poa->deactivate_object (id.in (), _env); + TAO_CHECK_ENV_RETURN_VOID (_env); +} + +</pre> +</table> +</center> + + +<P><HR><P> +<!-- ************************************************************ --> + +<center><table cellpadding=1 border=0 cellspacing=4> +<td> +<h2><a name="Section5">Developing Suppliers</a></h2> + +<ul> + <li> <a href="events_tutorial.html#Section5_1">Providing QoS Information</a> + <li> <a href="events_tutorial.html#Section5_2">Connecting Suppliers to the Event Channel</a> + <li> <a href="events_tutorial.html#Section5_3">Generating Events</a> + <li> <a href="events_tutorial.html#Section5_4">Disconnecting Suppliers from the Event Channel</a> +</ul> +</table> +</center> + + +<center><table cellpadding=1 border=0 cellspacing=4> +<h3><a name="Section5_1">Providing QoS Information</a></h3><p> +<tr><td> +In applications that use hard real-time scheduling, a Supplier should provide +the worst case, expected, and cached execution time for each operation on the +supplier side. Even if these values are small and highly deterministic, it is +generally better to specify them in the supplier's RT_Info rather than folding +them into the RT_Info of each consumer. + +<tr><td> +Such a supplier must also specify criticality and importance values, a period, +and the number of threads for each operation. A real-time scheduler propagates +this information to consumer RT_Infos along the graph of dependencies. The +scheduler then uses the propagated information to order dispatches within a +set of operations whose dependencies have been met. + +<tr><td> +The Event Service matches supplier publications with consumer subscriptions to +provide efficient event filtering. Providing incorrect publications or +subscriptions will result in missed events. The Event Service also uses the +subscription information to create additional dependencies between registered +RT_Infos. Thus, providing correct supplier publication and consumer +subscription information is also critical for correct scheduling in hard +real-time applications. + + +<tr><td> +As noted before in the discussion of consumers, the following steps are only +necessary for applications that make use of the Event Service's hard real-time +features. Applications that do not need these features and are configured +with a null scheduler may skip the following operations on the scheduling +server. + +</table> +</center> + +<center><table cellpadding=1 border=0 cellspacing=4> + +<tr><td> +<pre> + + // Obtain a reference to the scheduler server. + RtecScheduler::Scheduler_ptr server = + ACE_Scheduler_Factory::server (); + + // Create new RT_Info descriptors for two events. + + RtecScheduler::handle_t handle0 = + server->create ("event_0", // Name of entry point + TAO_TRY_ENV // Environment + ); + + RtecScheduler::handle_t handle1 = + server->create ("event_1", // Name of entry point + TAO_TRY_ENV // Environment + ); + + // Register as a producer of event_0. + server->set (handle0, // RT_Info handle + RtecScheduler::HIGH_CRITICALITY, // Criticality + 10, // Worst case time (in 100 nanosecs) + 10, // Typical time (in 100 nanosecs) + 10, // Cached time (in 100 nanosecs) + 50000 * 10, // Period in 100 nanosecs (= 20 Hz) + RtecScheduler::LOW_IMPORTANCE, // Importance + 0, // Quantum (unused) + 1, // Threads + RtecScheduler::OPERATION, // Info type + TAO_TRY_ENV); + + // Register as a producer of event_1. + server->set (handle1, // RT_Info handle + RtecScheduler::HIGH_CRITICALITY, // Criticality + 10, // Worst case time (in 100 nanosecs) + 10, // Typical time (in 100 nanosecs) + 10, // Cached time (in 100 nanosecs) + 50000 * 10, // Period in 100 nanosecs (= 20 Hz) + RtecScheduler::LOW_IMPORTANCE, // Importance + 0, // Quantum (unused) + 1, // Threads + RtecScheduler::OPERATION, // Info type + TAO_TRY_ENV); + +</pre> +</table> +</center> + +<P><hr width="75%"><P> <!-- intra-section separator --> + +<center><table cellpadding=1 border=0 cellspacing=4> +<td> +<h3><a name="Section5_2">Connecting Suppliers to Event Channel</a></h3><P> +<p> + +<tr><td> +The following code is derived from the EC_Throughput supplier code, which +can be found in TAO in the file: +<A HREF="http://www.cs.wustl.edu/~schmidt/ACE_wrappers/TAO/orbsvcs/tests/EC_Throughput/ECT_Supplier.cpp"> +$TAO_ROOT/orbsvcs/tests/EC_Throughput/ECT_Supplier.cpp</a> + + +<tr><td> +<pre> + +void +Test_Supplier::connect (const char* name, + int burst_count, + int burst_size, + int event_size, + int burst_pause, + int event_a, + int event_b, + RtecEventChannelAdmin::EventChannel_ptr ec, + CORBA::Environment &_env) +{ + // Some application-specific setup code. + + // Store the passed parameters in the object. + this->burst_count_ = burst_count; + this->burst_size_ = burst_size; + this->event_size_ = event_size; + this->burst_pause_ = burst_pause; + this->event_a_ = event_a; + this->event_b_ = event_b; + + // Register operations with the scheduling service. The following steps are + // only necessary for applications that make use of the Event Service's hard + // real-time features. Applications that do not need these features and are + // configured with a null scheduler may skip the following operations on the + // scheduling server. + + // Obtain a reference to the scheduling service. + RtecScheduler::Scheduler_ptr server = + ACE_Scheduler_Factory::server (); + + // Create an RT_Info descriptor for the passed operation name. + RtecScheduler::handle_t rt_info = + server->create (name, _env); + TAO_CHECK_ENV_RETURN_VOID (_env); + + // Calculate the period at which to supply events. + ACE_Time_Value tv (0, burst_pause); + RtecScheduler::Period_t rate = tv.usec () * 10; + + // Set the information in the RT_Info descriptor. + tv.set (0, 2000); + TimeBase::TimeT time; + ORBSVCS_Time::Time_Value_to_TimeT (time, tv); + server->set (rt_info, + RtecScheduler::VERY_HIGH_CRITICALITY, + time, time, time, + rate, + RtecScheduler::VERY_LOW_IMPORTANCE, + time, + 1, + RtecScheduler::OPERATION, + _env); + TAO_CHECK_ENV_RETURN_VOID (_env); + + // Now, create a supplier id, and publish the events + // that will be supplied under this id. + + // Create a supplier id from the passed name + this->supplier_id_ = ACE::crc32 (name); + ACE_DEBUG ((LM_DEBUG, "ID for <%s> is %04.4x\n", name, + this->supplier_id_)); + + // Publish the events the supplier provides. + ACE_SupplierQOS_Factory qos; + qos.insert (this->supplier_id_, + event_a, + rt_info, 1); + qos.insert (this->supplier_id_, + event_b, + rt_info, 1); + qos.insert (this->supplier_id_, + ACE_ES_EVENT_SHUTDOWN, + rt_info, 1); + + // And finally, some boiler plate code to connect a supplier + // to the Event Service. This is where the connection is + // actually made. + + // Obtain a reference to the supplier administration object. + RtecEventChannelAdmin::SupplierAdmin_var supplier_admin = + ec->for_suppliers (_env); + TAO_CHECK_ENV_RETURN_VOID (_env); + + // Obtain a reference to the consumer proxy object. + this->consumer_proxy_ = + supplier_admin->obtain_push_consumer (_env); + TAO_CHECK_ENV_RETURN_VOID (_env); + + // Obtain a reference to this supplier object. + RtecEventComm::PushSupplier_var objref = + this->supplier_._this (_env); + TAO_CHECK_ENV_RETURN_VOID (_env); + + // Connect as a supplier of the published events. + this->consumer_proxy_->connect_push_supplier (objref.in (), + qos.get_SupplierQOS (), + _env); + TAO_CHECK_ENV_RETURN_VOID (_env); +} + +</pre> + + +<tr><td> +The following code is derived from the EC_Throughput supplier driver code, which +can be found in TAO in the file: +<A HREF="http://www.cs.wustl.edu/~schmidt/ACE_wrappers/TAO/orbsvcs/tests/EC_Throughput/ECT_Supplier_Driver.cpp"> +$TAO_ROOT/orbsvcs/tests/EC_Throughput/ECT_Supplier_Driver.cpp</a> + +<tr><td> +<pre> + +int +ECT_Supplier_Driver::run (int argc, char* argv[]) +{ + // argc/argv are used to initialize the ORB and the options + // for this particular test. Other applications may hard-code + // the ORB options, obtain them from another source, etc. + + TAO_TRY + { + // The use of TAO_TRY macros isolate us from the differences + // between platforms with and without native C++ exceptions. + // This is work in progress and may change in the future! + + // Below is some boiler plate code to initialize the ORB and + // the POA. Notice that applications that connect to the Event + // Channel play the server role in some instances, because + // they receive push() requests (as Consumers) or + // disconnect_push_supplier() requests (as Suppliers). + + // Initialize the ORB reference. + CORBA::ORB_var orb = + CORBA::ORB_init (argc, argv, "", TAO_TRY_ENV); + TAO_CHECK_ENV; + + // Initialize the root POA reference. + CORBA::Object_var poa_object = + orb->resolve_initial_references("RootPOA"); + if (CORBA::is_nil (poa_object.in ())) + ACE_ERROR_RETURN ((LM_ERROR, + " (%P|%t) Unable to initialize the POA.\n"), + 1); + + // Obtain the narrowed root POA reference. + PortableServer::POA_var root_poa = + PortableServer::POA::_narrow (poa_object.in (), TAO_TRY_ENV); + TAO_CHECK_ENV; + + // Obtain a reference to the POA manager. + PortableServer::POAManager_var poa_manager = + root_poa->the_POAManager (TAO_TRY_ENV); + TAO_CHECK_ENV; + + + // Now some boiler plate code to obtain a reference to the + // naming service..... + + // Resolve a reference to the naming service. + CORBA::Object_var naming_obj = + orb->resolve_initial_references ("NameService"); + if (CORBA::is_nil (naming_obj.in ())) + ACE_ERROR_RETURN ((LM_ERROR, + " (%P|%t) Unable to get the Naming Service.\n"), + 1); + + // Narrow the naming service reference. + CosNaming::NamingContext_var naming_context = + CosNaming::NamingContext::_narrow (naming_obj.in (), TAO_TRY_ENV); + TAO_CHECK_ENV; + + // Use the Naming Service to locate the Scheduling Service and + // use the Scheduler_Factory to keep a global pointer to the + // latter. + + // Initialize the scheduler factory to operate in configuration mode. + if (ACE_Scheduler_Factory::use_config (naming_context.in ()) == -1) + return -1; + + // Use the Naming Service to locate the Event Service.... + + // Set up the event service lookup name. + CosNaming::Name name (1); + name.length (1); + name[0].id = CORBA::string_dup ("EventService"); + + // Resolve a reference to the event service. + CORBA::Object_var ec_obj = + naming_context->resolve (name, TAO_TRY_ENV); + TAO_CHECK_ENV; + + // Narrow the reference to the event service. + RtecEventChannelAdmin::EventChannel_var channel; + if (CORBA::is_nil (ec_obj.in ())) + channel = RtecEventChannelAdmin::EventChannel::_nil (); + else + channel = RtecEventChannelAdmin::EventChannel::_narrow (ec_obj.in (), + TAO_TRY_ENV); + TAO_CHECK_ENV; + + // Activate the POA so we can start receiving requests... + + // Activate the POA manager. + poa_manager->activate (TAO_TRY_ENV); + TAO_CHECK_ENV; + + // Connect suppliers to the event service. + this->connect_suppliers (channel.in (), TAO_TRY_ENV); + TAO_CHECK_ENV; + + ACE_DEBUG ((LM_DEBUG, "connected supplier(s)\n")); + + // Activate the supplier objects + this->activate_suppliers (TAO_TRY_ENV); + TAO_CHECK_ENV; + + ACE_DEBUG ((LM_DEBUG, "suppliers are active\n")); + + // Wait for the supplier threads. + if (ACE_Thread_Manager::instance ()->wait () == -1) + { + ACE_ERROR ((LM_ERROR, "Thread_Manager wait failed\n")); + return 1; + } + + ACE_DEBUG ((LM_DEBUG, "suppliers finished\n")); + + this->dump_results (); + + // Disconnect suppliers from the event service. + this->disconnect_suppliers (TAO_TRY_ENV); + TAO_CHECK_ENV; + } + TAO_CATCH (CORBA::SystemException, sys_ex) + { + TAO_TRY_ENV.print_exception ("SYS_EX"); + } + TAO_CATCHANY + { + TAO_TRY_ENV.print_exception ("NON SYS EX"); + } + TAO_ENDTRY; + return 0; +} + +</pre> +</table> +</center> + +<P><hr width="75%"><P> <!-- intra-section separator --> + +<center><table cellpadding=1 border=0 cellspacing=4> +<h3><a name="Section5_3">Generating Events</a></h3><P><p> + +<tr><td> +The following code is derived from the EC_Throughput supplier code, which +can be found in TAO in the file: +<A HREF="http://www.cs.wustl.edu/~schmidt/ACE_wrappers/TAO/orbsvcs/tests/EC_Throughput/ECT_Supplier.cpp"> +$TAO_ROOT/orbsvcs/tests/EC_Throughput/ECT_Supplier.cpp</a> + +<tr><td> +<pre> + +int +Test_Supplier::svc () +{ + TAO_TRY + { + // First, a bunch of code that is specific to this test. + + // Set pause (sleep) value between message bursts. + ACE_Time_Value tv (0, this->burst_pause_); + + // Set up message block for event data. + ACE_Message_Block mb (this->event_size_); + mb.wr_ptr (this->event_size_); + + // Create an event set for one event, initialize event header. + RtecEventComm::EventSet event (1); + event.length (1); + event[0].header.source = this->supplier_id (); + event[0].header.ttl = 1; + + // Set up time stamps in event header. This is for performance + // measurements, so this step can be omitted at will. + ACE_hrtime_t t = ACE_OS::gethrtime (); + ORBSVCS_Time::hrtime_to_TimeT (event[0].header.creation_time, t); + event[0].header.ec_recv_time = ORBSVCS_Time::zero; + event[0].header.ec_send_time = ORBSVCS_Time::zero; + + // Initialize data fields in event. + event[0].data.x = 0; + event[0].data.y = 0; + + // We use replace to minimize the copies. This should result + // in just one memory allocation; + event[0].data.payload.replace (this->event_size_, + &mb); + + // This is where the events are actually pushed into + // the event channel. The test pushes bursts of events, + // pausing a specified interval between bursts. + + // Start the timer, and begin pushing events. + this->timer_.start (); + for (int i = 0; i < this->burst_count_; ++i) + { + // Send a burst of events. + for (int j = 0; j < this->burst_size_; ++j) + { + if (j % 2 == 0) + event[0].header.type = this->event_a_; + else + event[0].header.type = this->event_b_; + + // ACE_DEBUG ((LM_DEBUG, "(%t) supplier push event\n")); + this->consumer_proxy ()->push (event, TAO_TRY_ENV); + + TAO_CHECK_ENV; + } + + // Sleep until it's time to send the next burst. + ACE_OS::sleep (tv); + } + + // Send a "magic" type of event to inform the consumer that we are + // not sending anything else... + + // Send one event shutdown from each supplier + event[0].header.type = ACE_ES_EVENT_SHUTDOWN; + this->consumer_proxy ()->push(event, TAO_TRY_ENV); + TAO_CHECK_ENV; + this->timer_.stop (); + + } + TAO_CATCH (CORBA::SystemException, sys_ex) + { + TAO_TRY_ENV.print_exception ("SYS_EX"); + } + TAO_CATCHANY + { + TAO_TRY_ENV.print_exception ("NON SYS EX"); + } + TAO_ENDTRY; + return 0; +} + +</pre> +</table> +</center> + +<P><hr width="75%"><P> <!-- intra-section separator --> + +<center><table cellpadding=1 border=0 cellspacing=4> +<td> +<h3><a name="Section5_4">Disconnecting Suppliers from the Event Channel</a></h3><P> +<p> + +<tr><td> +The following code is derived from the EC_Throughput supplier code, which +can be found in TAO in the file: +<A HREF="http://www.cs.wustl.edu/~schmidt/ACE_wrappers/TAO/orbsvcs/tests/EC_Throughput/ECT_Supplier.cpp"> +$TAO_ROOT/orbsvcs/tests/EC_Throughput/ECT_Supplier.cpp</a> + + +<tr><td> +<pre> + +void +Test_Supplier::disconnect (CORBA::Environment &_env) +{ + // Make sure the consumer proxy reference is valid. + if (CORBA::is_nil (this->consumer_proxy_.in ())) + return; + + // Disconnect communication with the push consumer(s). + this->consumer_proxy_->disconnect_push_consumer (_env); + TAO_CHECK_ENV_RETURN_VOID (_env); + + // Mark the consumer proxy reference invalid. + this->consumer_proxy_ = + RtecEventChannelAdmin::ProxyPushConsumer::_nil (); + + // We need to stop accepting disconnect_push_supplier () requests + // for this supplier, before it is safe to destroy the supplier. + // As required by the CORBA spec, you must explicitly deactivate + // a servant before destroying it. + + // Deactivate the servant + PortableServer::POA_var poa = + this->supplier_._default_POA (_env); + TAO_CHECK_ENV_RETURN_VOID (_env); + PortableServer::ObjectId_var id = + poa->servant_to_id (&this->supplier_, _env); + TAO_CHECK_ENV_RETURN_VOID (_env); + poa->deactivate_object (id.in (), _env); + TAO_CHECK_ENV_RETURN_VOID (_env); + RtecEventChannelAdmin::ProxyPushConsumer::_nil (); +} + +</pre> + +</table> +</center> + +<P><HR><P> +<!-- ************************************************************ --> + +<center><table cellpadding=1 border=0 cellspacing=4> +<td> +<h2><a name="Section6">Caring for your Event Channel</a></h2> + + +<BR> + +<ul> + <li> <a href="events_tutorial.html#Section6_1">Creation and Name Service Registration</a> + <li> <a href="events_tutorial.html#Section6_2">Register Suppliers Before Consumers</a> +</ul> +</table> +</center> + +<center><table cellpadding=1 border=0 cellspacing=4> +<h3><a name="Section6_1">Creation and Name Service Registration</a><h3><p> + +<tr><td> +The following code is derived from the Event_Service executable, which can be +found in TAO in the file: +<A HREF="http://www.cs.wustl.edu/~schmidt/ACE_wrappers/TAO/orbsvcs/Event_Service/Event_Service.cpp"> +$TAO_ROOT/orbsvcs/Event_Service/Event_Service.cpp</a> + +<tr><td> +<pre> + +int main (int argc, char *argv[]) +{ + TAO_TRY + { + // argc/argv are used to initialize the ORB and the options + // for the Event Service executable. Other applications may + // hard code the ORB options, obtain them from another source, etc. + + // Again the boiler plate code for ORB and POA initialization. + + // Initialize ORB. + CORBA::ORB_var orb = + CORBA::ORB_init (argc, argv, "internet", TAO_TRY_ENV); + TAO_CHECK_ENV; + + if (parse_args (argc, argv) == -1) + return 1; + + CORBA::Object_var poa_object = + orb->resolve_initial_references("RootPOA"); + if (CORBA::is_nil (poa_object.in ())) + ACE_ERROR_RETURN ((LM_ERROR, + " (%P|%t) Unable to initialize the POA.\n"), + 1); + + PortableServer::POA_var root_poa = + PortableServer::POA::_narrow (poa_object.in (), TAO_TRY_ENV); + TAO_CHECK_ENV; + + PortableServer::POAManager_var poa_manager = + root_poa->the_POAManager (TAO_TRY_ENV); + TAO_CHECK_ENV; + + CORBA::Object_var naming_obj = + orb->resolve_initial_references ("NameService"); + if (CORBA::is_nil (naming_obj.in ())) + ACE_ERROR_RETURN ((LM_ERROR, + " (%P|%t) Unable to initialize the Naming Service.\n"), + 1); + + CosNaming::NamingContext_var naming_context = + CosNaming::NamingContext::_narrow (naming_obj.in (), TAO_TRY_ENV); + TAO_CHECK_ENV; + + // Notice the use of auto_ptr<> to automagically manage the + // destruction of the servant. When the auto_ptr goes out + // of scope, its destructor is called, which in turn destroys + // the servant. + + auto_ptr<POA_RtecScheduler::Scheduler> scheduler_impl; + RtecScheduler::Scheduler_var scheduler; + + + // Create a new servant to implement the Scheduling Service, + // register it with the Naming Service, and use the + // Scheduler_Factory to keep a global pointer to the new + // Scheduling Service. + + // This is the name we (potentially) use to register the Scheduling + // Service in the Naming Service. + CosNaming::Name schedule_name (1); + schedule_name.length (1); + schedule_name[0].id = CORBA::string_dup ("ScheduleService"); + + if (global_scheduler == 0) + { + scheduler_impl = + auto_ptr<POA_RtecScheduler::Scheduler>(new ACE_Config_Scheduler); + if (scheduler_impl.get () == 0) + return 1; + scheduler = scheduler_impl->_this (TAO_TRY_ENV); + TAO_CHECK_ENV; + + CORBA::String_var str = + orb->object_to_string (scheduler.in (), TAO_TRY_ENV); + TAO_CHECK_ENV; + ACE_DEBUG ((LM_DEBUG, "The (local) scheduler IOR is <%s>\n", + str.in ())); + + // Register the servant with the Naming Context.... + naming_context->bind (schedule_name, scheduler.in (), TAO_TRY_ENV); + TAO_CHECK_ENV; + } + + ACE_Scheduler_Factory::use_config (naming_context.in ()); + + // The Event Service can be configured to support priority based + // dispatching (the "default_Module_Factory") or best effort (the + // "Reactive_Module_Factory"). We pick the right module factory + // according to the command line options processed above. + + TAO_Default_Module_Factory default_module_factory; + TAO_Reactive_Module_Factory reactive_module_factory; + + TAO_Module_Factory* module_factory = &default_module_factory; + if (reactive) + module_factory = &reactive_module_factory; + + // Now, create a new event channel servant to implement the + // Event Service, and register it with Naming Service. + + // Construct the event channel using the given module factory. + ACE_EventChannel ec_impl (1, + ACE_DEFAULT_EVENT_CHANNEL_TYPE, + module_factory); + + // Obtain an object reference to the new channel. + RtecEventChannelAdmin::EventChannel_var ec = + ec_impl._this (TAO_TRY_ENV); + TAO_CHECK_ENV; + + // Convert the EC object reference to a string. + CORBA::String_var str = + orb->object_to_string (ec.in (), TAO_TRY_ENV); + + // Output the EC object reference string (debug only). + ACE_DEBUG ((LM_DEBUG, + "The EC IOR is <%s>\n", str.in ())); + + // Register the EC with the Naming Service. + CosNaming::Name channel_name (1); + channel_name.length (1); + channel_name[0].id = CORBA::string_dup (service_name); + naming_context->bind (channel_name, ec.in (), TAO_TRY_ENV); + TAO_CHECK_ENV; + + // Activate the POA so we can start receiving requests... + + // Activate the POA manager. + poa_manager->activate (TAO_TRY_ENV); + TAO_CHECK_ENV; + + // Run the ORB event loop + ACE_DEBUG ((LM_DEBUG, "%s; running event service\n", __FILE__)); + if (orb->run () == -1) + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "run"), 1); + + // Now the Event Service is finished. We could deactivate the + // EC and SS here, but we don't need to, as the server is + // going down anyway. + + + // Remove the event service and the scheduling service from + // the Naming Service. + + naming_context->unbind (channel_name, TAO_TRY_ENV); + TAO_CHECK_ENV; + + if (global_scheduler == 0) + { + naming_context->unbind (schedule_name, TAO_TRY_ENV); + TAO_CHECK_ENV; + } + + } + TAO_CATCHANY + { + TAO_TRY_ENV.print_exception ("EC"); + } + TAO_ENDTRY; + + + return 0; +} + +</pre> +</table> +</center> + +<P><hr width="75%"><P> <!-- intra-section separator --> + +<center><table cellpadding=1 border=0 cellspacing=4> +<h3><a name="Section6_2">Register Suppliers before Consumers</a></h3><p> +<BR> +<BR> +<tr><td> +<center> +<IMG SRC="http://www.cs.wustl.edu/~schmidt/gifs/ec_registration.gif"> +</center> +</table></center> + +<P><HR><P> +<!-- ************************************************************ --> + +<center><table cellpadding=1 border=0 cellspacing=4> +<tr><td> +<h2><a name="Section7">Sample Applications</a></h2> + +<tr><td> +A number of sample applications are available in the directories under +<a href="http://www.cs.wustl.edu/~schmidt/ACE_wrappers/TAO/orbsvcs/tests/"> +TAO's ORB Services tests</a>. + +<tr><td> +In particular, much of the code shown in this tutorial was drawn from the +<a href="http://www.cs.wustl.edu/~schmidt/ACE_wrappers/TAO/orbsvcs/tests/EC_Throughput/"> +EC_Throughput</a> test. This test exercises the Event Service and measures its +throughput capabilities. + +<tr><td> +A similar test, +<a href="http://www.cs.wustl.edu/~schmidt/ACE_wrappers/TAO/orbsvcs/tests/Event_Latency/"> +Event_Latency</a>, measures the latency of events through the Event Service. + +<tr><td> +The +<a href="http://www.cs.wustl.edu/~schmidt/ACE_wrappers/TAO/orbsvcs/tests/EC_Basic/"> +EC_Basic</a> test demonstrates the basic use the Event Service. + +<tr><td> +The +<a href="http://www.cs.wustl.edu/~schmidt/ACE_wrappers/TAO/orbsvcs/tests/EC_Multiple/"> +EC_Multiple</a> test shows a number of ways to connect multiple Event Channels. + + +<tr><td> +For the IDL source for the various interfaces, please see +<a href="http://www.cs.wustl.edu/~schmidt/ACE_wrappers/TAO/orbsvcs/orbsvcs/RtecScheduler.idl">RtecScheduler.idl</a>, +<a href="http://www.cs.wustl.edu/~schmidt/ACE_wrappers/TAO/orbsvcs/orbsvcs/CosEventChannelAdmin.idl">CosEventChannelAdmin.idl</a>, +<a href="http://www.cs.wustl.edu/~schmidt/ACE_wrappers/TAO/orbsvcs/orbsvcs/CosEventComm.idl">CosEventComm.idl</a> +and +<a href="http://www.cs.wustl.edu/~schmidt/ACE_wrappers/TAO/orbsvcs/orbsvcs/CosNaming.idl">CosNaming.idl</a>. + + +</table> +</center> + +<P><HR><P> +<!-- ************************************************************ --> + +<center><table cellpadding=1 border=0 cellspacing=4> +<tr><td> +<h2><a name="Section8">Reference Materials</a></h2> + +<tr><td> +The following materials were used in developing this tutorial: please refer to them for further information. + +<tr><td> +<br> +<tr><td> +<h3>Books</h3> + +<tr><td> +Mowbray, T. and Zahavi, R. The Essential CORBA, Systems Integration Using Distributed Objects. Wiley, 1995. +ISBN 0-471-10611-9 + +<tr><td> +<br> + +<tr><td> +Baker, S. CORBA Distributed Objects Using Orbix. Addison-Wesley, 1997. ISBN 0-201-92475-7 + +<tr><td> +<br> +<tr><td> +<h3>Papers</h3> + +<tr><td> +<ul> + +<li><a href="http://www.cs.wustl.edu/~schmidt/Arch.ps.gz"> +Architectural Considerations for Deterministic Real-Time ORB +Endsystems and Applications</a> + +<li><a href="http://www.cs.wustl.edu/~schmidt/JSAC-98.ps.gz"> The +Design and Performance of a Real-Time CORBA Object Event Service</a> + +<li><a href="http://www.cs.wustl.edu/~schmidt/RT-ORB.ps.gz"> The +Design of the TAO Real-Time Object Request Broker</a> + +</ul> + + +<tr><td> + +</table> +</center> + +<P><HR><P> +<!-- ************************************************************ --> + + +<center><table cellpadding=1 border=0 cellspacing=4> +<tr><td> +Last modified 10:50:30 CST 22 December 1998 by Chris Gill +</table></center> + +</body></html> + diff --git a/TAO/orbsvcs/tests/EC_Throughput/ECT_Consumer.cpp b/TAO/orbsvcs/tests/EC_Throughput/ECT_Consumer.cpp index 230abb4b462..48ed35d0664 100644 --- a/TAO/orbsvcs/tests/EC_Throughput/ECT_Consumer.cpp +++ b/TAO/orbsvcs/tests/EC_Throughput/ECT_Consumer.cpp @@ -35,7 +35,7 @@ Test_Consumer::connect (const char* name, RtecScheduler::handle_t rt_info = server->create (name, _env); - if (_env.exception () != 0) return; + TAO_CHECK_ENV_RETURN_VOID (_env); // The worst case execution time is far less than 2 // milliseconds, but that is a safe estimate.... @@ -51,7 +51,7 @@ Test_Consumer::connect (const char* name, 0, RtecScheduler::OPERATION, _env); - if (_env.exception () != 0) return; + TAO_CHECK_ENV_RETURN_VOID (_env); ACE_ConsumerQOS_Factory qos; qos.start_disjunction_group (); @@ -62,19 +62,19 @@ Test_Consumer::connect (const char* name, // = Connect as a consumer. RtecEventChannelAdmin::ConsumerAdmin_var consumer_admin = ec->for_consumers (_env); - if (_env.exception () != 0) return; + TAO_CHECK_ENV_RETURN_VOID (_env); this->supplier_proxy_ = consumer_admin->obtain_push_supplier (_env); - if (_env.exception () != 0) return; + TAO_CHECK_ENV_RETURN_VOID (_env); RtecEventComm::PushConsumer_var objref = this->_this (_env); - if (_env.exception () != 0) return; + TAO_CHECK_ENV_RETURN_VOID (_env); this->supplier_proxy_->connect_push_consumer (objref.in (), qos.get_ConsumerQOS (), _env); - if (_env.exception () != 0) return; + TAO_CHECK_ENV_RETURN_VOID (_env); } void @@ -84,7 +84,7 @@ Test_Consumer::disconnect (CORBA::Environment &_env) return; this->supplier_proxy_->disconnect_push_supplier (_env); - if (_env.exception () != 0) return; + TAO_CHECK_ENV_RETURN_VOID (_env); this->supplier_proxy_ = RtecEventChannelAdmin::ProxyPushSupplier::_nil (); diff --git a/TAO/orbsvcs/tests/EC_Throughput/ECT_Consumer_Driver.cpp b/TAO/orbsvcs/tests/EC_Throughput/ECT_Consumer_Driver.cpp index 14da8fb96db..e397255fc22 100644 --- a/TAO/orbsvcs/tests/EC_Throughput/ECT_Consumer_Driver.cpp +++ b/TAO/orbsvcs/tests/EC_Throughput/ECT_Consumer_Driver.cpp @@ -213,7 +213,7 @@ ECT_Consumer_Driver::connect_consumers (RtecEventChannelAdmin::EventChannel_ptr this->event_b_, channel, _env); - if (_env.exception () != 0) return; + TAO_CHECK_ENV_RETURN_VOID (_env); } } @@ -236,7 +236,7 @@ ECT_Consumer_Driver::disconnect_consumers (CORBA::Environment &_env) for (int i = 0; i < this->n_consumers_; ++i) { this->consumers_[i]->disconnect (_env); - if (_env.exception () != 0) return; + TAO_CHECK_ENV_RETURN_VOID (_env); } } diff --git a/TAO/orbsvcs/tests/EC_Throughput/ECT_Supplier_Driver.cpp b/TAO/orbsvcs/tests/EC_Throughput/ECT_Supplier_Driver.cpp index 4b11cffb690..1c68f8f5eb9 100644 --- a/TAO/orbsvcs/tests/EC_Throughput/ECT_Supplier_Driver.cpp +++ b/TAO/orbsvcs/tests/EC_Throughput/ECT_Supplier_Driver.cpp @@ -216,7 +216,7 @@ ECT_Supplier_Driver::connect_suppliers (RtecEventChannelAdmin::EventChannel_ptr this->event_b_, channel, _env); - if (_env.exception () != 0) return; + TAO_CHECK_ENV_RETURN_VOID (_env); } } @@ -235,7 +235,7 @@ ECT_Supplier_Driver::disconnect_suppliers (CORBA::Environment &_env) for (int i = 0; i < this->n_suppliers_; ++i) { this->suppliers_[i]->disconnect (_env); - if (_env.exception () != 0) return; + TAO_CHECK_ENV_RETURN_VOID (_env); } } |