diff options
Diffstat (limited to 'examples/Reactor')
33 files changed, 5495 insertions, 0 deletions
diff --git a/examples/Reactor/Dgram/CODgram.cpp b/examples/Reactor/Dgram/CODgram.cpp new file mode 100644 index 00000000000..8856e92d3c5 --- /dev/null +++ b/examples/Reactor/Dgram/CODgram.cpp @@ -0,0 +1,121 @@ +/* Exercise the ACE_SOCK_CODgram wrapper along with the ACE_Reactor. +// @(#)CODgram.cpp 1.1 10/18/96 + + + Typical invocation sequence is: + + % CODgram 10000 localhost 10001 & + % CODgram 10001 localhost 10000 + + This will start two interacting copies of the CODgram + application. */ + +#include "ace/Reactor.h" +#include "ace/SOCK_CODgram.h" +#include "ace/INET_Addr.h" + +class AAL_CP : public ACE_Event_Handler, public ACE_SOCK_CODgram +{ +public: + AAL_CP (const ACE_INET_Addr &remote_addr, + const ACE_INET_Addr &local_addr); + + virtual int get_handle () const; + + virtual int handle_input (int fd); + + virtual int handle_timeout (const ACE_Time_Value & tv, + const void *arg = 0); +}; + +AAL_CP::AAL_CP (const ACE_INET_Addr &remote_addr, + const ACE_INET_Addr &local_addr) + : ACE_SOCK_CODgram (remote_addr, local_addr) +{ +} + +int +AAL_CP::get_handle () const +{ + return ACE_SOCK_CODgram::get_handle (); +} + +int +AAL_CP::handle_input (int) +{ + char buf[128]; + int n; + ACE_DEBUG ((LM_DEBUG, "Activity occurred on handle %d!\n", + ACE_SOCK_CODgram::get_handle ())); + if ((n = ACE_SOCK_CODgram::recv (buf, sizeof buf)) == -1) + ACE_ERROR ((LM_ERROR, "%p\n", "handle_input")); + else + ACE_DEBUG ((LM_DEBUG, "got buf = %s\n", buf)); + + return 0; +} + +int +AAL_CP::handle_timeout (const ACE_Time_Value &, const void *) +{ + ACE_DEBUG ((LM_DEBUG, "timed out for aa1\n")); + return 0; +} + +main(int argc, char *argv[]) +{ + /* Estabish call backs, and socket names */ + if (argc != 4) + ACE_ERROR_RETURN ((LM_ERROR, + "usage: %s localport remotehost remoteport\n", + argv[0]), -1); + + ACE_Reactor reactor; + char buf[128]; + u_short localport = ACE_OS::atoi (argv[1]); + u_short remoteport = ACE_OS::atoi (argv[3]); + char *remotehost = argv[2]; + + ACE_INET_Addr remote_addr (remoteport, remotehost); + ACE_INET_Addr local_addr (localport); + + AAL_CP aal (remote_addr, local_addr); + + if (localport == 10000) // HACK + { + ACE_OS::memcpy (buf, "Data to transmit", sizeof buf); + ACE_DEBUG ((LM_DEBUG, "sending data\n")); + + for (int i = 0; i < 20; i++) + { + aal.send (buf, sizeof buf); + ACE_DEBUG ((LM_DEBUG, ".\n")); + ACE_OS::sleep (1); + } + } + + /* read data from other side */ + if (reactor.register_handler (&aal, ACE_Event_Handler::READ_MASK) == -1) + ACE_ERROR_RETURN ((LM_ERROR, "ACE_Reactor::register_handler"), -1); + + if (reactor.schedule_timer (&aal, 0, + ACE_Time_Value (1, 0), + ACE_Time_Value (0, 3500000)) == -1) + ACE_ERROR_RETURN ((LM_ERROR, "ACE_Reactor::schedule_timer"), -1); + + ACE_OS::memcpy (buf, "Data to transmit", sizeof buf); + + for (;;) + { + /* Wait at most two seconds */ + ACE_Time_Value tv (2, 0); + + reactor.handle_events (tv); + + ACE_DEBUG ((LM_DEBUG, "return from handle events\n")); + aal.send (buf, sizeof buf); + ACE_DEBUG ((LM_DEBUG, ".\n")); + } + + return 0; +} diff --git a/examples/Reactor/Dgram/Dgram.cpp b/examples/Reactor/Dgram/Dgram.cpp new file mode 100644 index 00000000000..d2f4305f267 --- /dev/null +++ b/examples/Reactor/Dgram/Dgram.cpp @@ -0,0 +1,121 @@ +// Exercise the ACE_SOCK_Dgram wrapper along with the ACE_Reactor. +// @(#)Dgram.cpp 1.1 10/18/96 + +// Typical invocation sequence is: +// +// % Dgram 10000 localhost 10001 & +// % Dgram 10001 localhost 10000 +// +// This will start two interacting copies of the Dgram +// application. + +#include "ace/Reactor.h" +#include "ace/SOCK_Dgram.h" +#include "ace/INET_Addr.h" + +class AAL_CP : public ACE_Event_Handler, public ACE_SOCK_Dgram +{ +public: + AAL_CP (const ACE_INET_Addr &local_addr); + + virtual ACE_HANDLE get_handle (void) const; + + virtual int handle_input (ACE_HANDLE handle); + + virtual int handle_timeout (const ACE_Time_Value & tv, + const void *arg = 0); +}; + +AAL_CP::AAL_CP (const ACE_INET_Addr &local_addr) + : ACE_SOCK_Dgram (local_addr) +{ +} + +ACE_HANDLE +AAL_CP::get_handle (void) const +{ + return ACE_SOCK_Dgram::get_handle (); +} + +int +AAL_CP::handle_input (ACE_HANDLE) +{ + char buf[BUFSIZ]; + int n; + ACE_INET_Addr from_addr; + + ACE_DEBUG ((LM_DEBUG, "Activity occurred on handle %d!\n", + ACE_SOCK_Dgram::get_handle ())); + if ((n = ACE_SOCK_Dgram::recv (buf, sizeof buf, from_addr)) == -1) + ACE_ERROR ((LM_ERROR, "%p\n", "handle_input")); + else + ACE_DEBUG ((LM_DEBUG, "got buf = %s\n", buf)); + + return 0; +} + +int +AAL_CP::handle_timeout (const ACE_Time_Value &, const void *) +{ + ACE_DEBUG ((LM_DEBUG, "timed out for aa1\n")); + return 0; +} + +int +main (int argc, char *argv[]) +{ + // Estabish call backs, and socket names. + if (argc != 4) + ACE_ERROR_RETURN ((LM_ERROR, + "usage: %s localport remotehost remoteport\n", + argv[0]), -1); + + ACE_Reactor reactor; + char buf[128]; + u_short localport = ACE_OS::atoi (argv[1]); + u_short remoteport = ACE_OS::atoi (argv[3]); + char *remotehost = argv[2]; + + ACE_INET_Addr remote_addr (remoteport, remotehost); + ACE_INET_Addr local_addr (localport); + + AAL_CP aal (local_addr); + + if (localport == 10000) // HACK + { + ACE_OS::memcpy (buf, "Data to transmit", sizeof buf); + ACE_DEBUG ((LM_DEBUG, "sending data\n")); + + for (size_t i = 0; i < 20; i++) + { + aal.send (buf, sizeof buf, remote_addr); + ACE_DEBUG ((LM_DEBUG, ".\n")); + ACE_OS::sleep (1); + } + } + + // Read data from other side. + if (reactor.register_handler (&aal, ACE_Event_Handler::READ_MASK) == -1) + ACE_ERROR_RETURN ((LM_ERROR, "ACE_Reactor::register_handler"), -1); + + if (reactor.schedule_timer (&aal, 0, + ACE_Time_Value (1, 0), + ACE_Time_Value (0, 3500000)) == -1) + ACE_ERROR_RETURN ((LM_ERROR, "ACE_Reactor::schedule_timer"), -1); + + ACE_OS::memcpy (buf, "Data to transmit", sizeof buf); + + for (;;) + { + // Wait at most two seconds. + ACE_Time_Value tv (2, 0); + + reactor.handle_events (tv); + + ACE_DEBUG ((LM_DEBUG, "return from handle events\n")); + aal.send (buf, sizeof buf, remote_addr); + ACE_DEBUG ((LM_DEBUG, ".\n")); + } + + return 0; +} diff --git a/examples/Reactor/Dgram/Makefile b/examples/Reactor/Dgram/Makefile new file mode 100644 index 00000000000..5c2204cd91a --- /dev/null +++ b/examples/Reactor/Dgram/Makefile @@ -0,0 +1,135 @@ +#---------------------------------------------------------------------------- +# @(#)Makefile 1.1 10/18/96 +# +# Makefile for a test of the CODgram and Dgram facilities and the Reactor +#---------------------------------------------------------------------------- + +#---------------------------------------------------------------------------- +# Local macros +#---------------------------------------------------------------------------- + +BIN = CODgram Dgram + +LSRC = CODgram.cpp Dgram.cpp + +LDLIBS = + +VLDLIBS = $(LDLIBS:%=%$(VAR)) + +BUILD = $(VBIN) + +INSTALL = + +#---------------------------------------------------------------------------- +# Include macros and targets +#---------------------------------------------------------------------------- + +include $(WRAPPER_ROOT)/include/makeinclude/wrapper_macros.GNU +include $(WRAPPER_ROOT)/include/makeinclude/macros.GNU +include $(WRAPPER_ROOT)/include/makeinclude/rules.common.GNU +include $(WRAPPER_ROOT)/include/makeinclude/rules.nonested.GNU +include $(WRAPPER_ROOT)/include/makeinclude/rules.bin.GNU +include $(WRAPPER_ROOT)/include/makeinclude/rules.local.GNU + +#---------------------------------------------------------------------------- +# Local targets +#---------------------------------------------------------------------------- + +#---------------------------------------------------------------------------- +# Dependencies +#---------------------------------------------------------------------------- +# DO NOT DELETE THIS LINE -- g++dep uses it. +# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY. + +.obj/CODgram.o .shobj/CODgram.so: CODgram.cpp \ + $(WRAPPER_ROOT)/ace/Reactor.h \ + $(WRAPPER_ROOT)/ace/Handle_Set.h \ + $(WRAPPER_ROOT)/ace/ACE.h \ + $(WRAPPER_ROOT)/ace/OS.h \ + $(WRAPPER_ROOT)/ace/Time_Value.h \ + $(WRAPPER_ROOT)/ace/config.h \ + $(WRAPPER_ROOT)/ace/Trace.h \ + $(WRAPPER_ROOT)/ace/ACE.i \ + $(WRAPPER_ROOT)/ace/Log_Msg.h \ + $(WRAPPER_ROOT)/ace/Log_Record.h \ + $(WRAPPER_ROOT)/ace/Log_Priority.h \ + $(WRAPPER_ROOT)/ace/Log_Record.i \ + $(WRAPPER_ROOT)/ace/Timer_Queue.h \ + $(WRAPPER_ROOT)/ace/Event_Handler.h \ + $(WRAPPER_ROOT)/ace/Synch.h \ + $(WRAPPER_ROOT)/ace/SV_Semaphore_Complex.h \ + $(WRAPPER_ROOT)/ace/SV_Semaphore_Simple.h \ + $(WRAPPER_ROOT)/ace/SV_Semaphore_Simple.i \ + $(WRAPPER_ROOT)/ace/SV_Semaphore_Complex.i \ + $(WRAPPER_ROOT)/ace/Synch_T.h \ + $(WRAPPER_ROOT)/ace/Synch_T.cpp \ + $(WRAPPER_ROOT)/ace/Thread.h \ + $(WRAPPER_ROOT)/ace/Synch_T.i \ + $(WRAPPER_ROOT)/ace/Timer_Queue.i \ + $(WRAPPER_ROOT)/ace/Signal.h \ + $(WRAPPER_ROOT)/ace/Set.h \ + $(WRAPPER_ROOT)/ace/Set.cpp \ + $(WRAPPER_ROOT)/ace/Set.i \ + $(WRAPPER_ROOT)/ace/Token.h \ + $(WRAPPER_ROOT)/ace/Pipe.h \ + $(WRAPPER_ROOT)/ace/Pipe.i \ + $(WRAPPER_ROOT)/ace/SOCK_Stream.h \ + $(WRAPPER_ROOT)/ace/SOCK_IO.h \ + $(WRAPPER_ROOT)/ace/SOCK.h \ + $(WRAPPER_ROOT)/ace/Addr.h \ + $(WRAPPER_ROOT)/ace/IPC_SAP.h \ + $(WRAPPER_ROOT)/ace/IPC_SAP.i \ + $(WRAPPER_ROOT)/ace/SOCK.i \ + $(WRAPPER_ROOT)/ace/SOCK_IO.i \ + $(WRAPPER_ROOT)/ace/INET_Addr.h \ + $(WRAPPER_ROOT)/ace/SOCK_Stream.i \ + $(WRAPPER_ROOT)/ace/Reactor.i \ + $(WRAPPER_ROOT)/ace/SOCK_CODgram.h \ + $(WRAPPER_ROOT)/ace/SOCK_CODgram.i +.obj/Dgram.o .shobj/Dgram.so: Dgram.cpp \ + $(WRAPPER_ROOT)/ace/Reactor.h \ + $(WRAPPER_ROOT)/ace/Handle_Set.h \ + $(WRAPPER_ROOT)/ace/ACE.h \ + $(WRAPPER_ROOT)/ace/OS.h \ + $(WRAPPER_ROOT)/ace/Time_Value.h \ + $(WRAPPER_ROOT)/ace/config.h \ + $(WRAPPER_ROOT)/ace/Trace.h \ + $(WRAPPER_ROOT)/ace/ACE.i \ + $(WRAPPER_ROOT)/ace/Log_Msg.h \ + $(WRAPPER_ROOT)/ace/Log_Record.h \ + $(WRAPPER_ROOT)/ace/Log_Priority.h \ + $(WRAPPER_ROOT)/ace/Log_Record.i \ + $(WRAPPER_ROOT)/ace/Timer_Queue.h \ + $(WRAPPER_ROOT)/ace/Event_Handler.h \ + $(WRAPPER_ROOT)/ace/Synch.h \ + $(WRAPPER_ROOT)/ace/SV_Semaphore_Complex.h \ + $(WRAPPER_ROOT)/ace/SV_Semaphore_Simple.h \ + $(WRAPPER_ROOT)/ace/SV_Semaphore_Simple.i \ + $(WRAPPER_ROOT)/ace/SV_Semaphore_Complex.i \ + $(WRAPPER_ROOT)/ace/Synch_T.h \ + $(WRAPPER_ROOT)/ace/Synch_T.cpp \ + $(WRAPPER_ROOT)/ace/Thread.h \ + $(WRAPPER_ROOT)/ace/Synch_T.i \ + $(WRAPPER_ROOT)/ace/Timer_Queue.i \ + $(WRAPPER_ROOT)/ace/Signal.h \ + $(WRAPPER_ROOT)/ace/Set.h \ + $(WRAPPER_ROOT)/ace/Set.cpp \ + $(WRAPPER_ROOT)/ace/Set.i \ + $(WRAPPER_ROOT)/ace/Token.h \ + $(WRAPPER_ROOT)/ace/Pipe.h \ + $(WRAPPER_ROOT)/ace/Pipe.i \ + $(WRAPPER_ROOT)/ace/SOCK_Stream.h \ + $(WRAPPER_ROOT)/ace/SOCK_IO.h \ + $(WRAPPER_ROOT)/ace/SOCK.h \ + $(WRAPPER_ROOT)/ace/Addr.h \ + $(WRAPPER_ROOT)/ace/IPC_SAP.h \ + $(WRAPPER_ROOT)/ace/IPC_SAP.i \ + $(WRAPPER_ROOT)/ace/SOCK.i \ + $(WRAPPER_ROOT)/ace/SOCK_IO.i \ + $(WRAPPER_ROOT)/ace/INET_Addr.h \ + $(WRAPPER_ROOT)/ace/SOCK_Stream.i \ + $(WRAPPER_ROOT)/ace/Reactor.i \ + $(WRAPPER_ROOT)/ace/SOCK_Dgram.h \ + $(WRAPPER_ROOT)/ace/SOCK_Dgram.i + +# IF YOU PUT ANYTHING HERE IT WILL GO AWAY diff --git a/examples/Reactor/Makefile b/examples/Reactor/Makefile new file mode 100644 index 00000000000..4613709a2a2 --- /dev/null +++ b/examples/Reactor/Makefile @@ -0,0 +1,24 @@ +#---------------------------------------------------------------------------- +# @(#)Makefile 1.1 10/18/96 +# +# Makefile for the Reactor tests +#---------------------------------------------------------------------------- + +#---------------------------------------------------------------------------- +# Local macros +#---------------------------------------------------------------------------- + +DIRS = Dgram \ + Misc \ + Multicast \ + Ntalker + +#---------------------------------------------------------------------------- +# Include macros and targets +#---------------------------------------------------------------------------- + +include $(WRAPPER_ROOT)/include/makeinclude/wrapper_macros.GNU +include $(WRAPPER_ROOT)/include/makeinclude/macros.GNU +include $(WRAPPER_ROOT)/include/makeinclude/rules.common.GNU +include $(WRAPPER_ROOT)/include/makeinclude/rules.nested.GNU +include $(WRAPPER_ROOT)/include/makeinclude/rules.nolocal.GNU diff --git a/examples/Reactor/Misc/Makefile b/examples/Reactor/Misc/Makefile new file mode 100644 index 00000000000..31d49795de7 --- /dev/null +++ b/examples/Reactor/Misc/Makefile @@ -0,0 +1,378 @@ +#---------------------------------------------------------------------------- +# @(#)Makefile 1.1 10/18/96 +# +# Makefile for a test of the miscellaneous Reactor examples +#---------------------------------------------------------------------------- + +#---------------------------------------------------------------------------- +# Local macros +#---------------------------------------------------------------------------- + +BIN = pingpong \ + notification \ + signal_tester \ + test_event_handler_t \ + test_handle_set \ + test_reactors \ + test_signals \ + test_time_value \ + test_timer_queue + +LSRC = $(addsuffix .cpp,$(BIN)) + +VLDLIBS = $(LDLIBS:%=%$(VAR)) + +BUILD = $(VBIN) + +#---------------------------------------------------------------------------- +# Include macros and targets +#---------------------------------------------------------------------------- + +include $(WRAPPER_ROOT)/include/makeinclude/wrapper_macros.GNU +include $(WRAPPER_ROOT)/include/makeinclude/macros.GNU +include $(WRAPPER_ROOT)/include/makeinclude/rules.common.GNU +include $(WRAPPER_ROOT)/include/makeinclude/rules.nonested.GNU +include $(WRAPPER_ROOT)/include/makeinclude/rules.bin.GNU +include $(WRAPPER_ROOT)/include/makeinclude/rules.local.GNU + +#---------------------------------------------------------------------------- +# Local targets +#---------------------------------------------------------------------------- + +#---------------------------------------------------------------------------- +# Dependencies +#---------------------------------------------------------------------------- +# DO NOT DELETE THIS LINE -- g++dep uses it. +# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY. + +.obj/pingpong.o .shobj/pingpong.so: pingpong.cpp \ + $(WRAPPER_ROOT)/ace/Log_Msg.h \ + $(WRAPPER_ROOT)/ace/Log_Record.h \ + $(WRAPPER_ROOT)/ace/ACE.h \ + $(WRAPPER_ROOT)/ace/OS.h \ + $(WRAPPER_ROOT)/ace/Time_Value.h \ + $(WRAPPER_ROOT)/ace/config.h \ + $(WRAPPER_ROOT)/ace/Trace.h \ + $(WRAPPER_ROOT)/ace/ACE.i \ + $(WRAPPER_ROOT)/ace/Log_Priority.h \ + $(WRAPPER_ROOT)/ace/Log_Record.i \ + $(WRAPPER_ROOT)/ace/Synch.h \ + $(WRAPPER_ROOT)/ace/SV_Semaphore_Complex.h \ + $(WRAPPER_ROOT)/ace/SV_Semaphore_Simple.h \ + $(WRAPPER_ROOT)/ace/SV_Semaphore_Simple.i \ + $(WRAPPER_ROOT)/ace/SV_Semaphore_Complex.i \ + $(WRAPPER_ROOT)/ace/Synch_T.h \ + $(WRAPPER_ROOT)/ace/Synch_T.cpp \ + $(WRAPPER_ROOT)/ace/Thread.h \ + $(WRAPPER_ROOT)/ace/Synch_T.i \ + $(WRAPPER_ROOT)/ace/Reactor.h \ + $(WRAPPER_ROOT)/ace/Handle_Set.h \ + $(WRAPPER_ROOT)/ace/Timer_Queue.h \ + $(WRAPPER_ROOT)/ace/Event_Handler.h \ + $(WRAPPER_ROOT)/ace/Timer_Queue.i \ + $(WRAPPER_ROOT)/ace/Signal.h \ + $(WRAPPER_ROOT)/ace/Set.h \ + $(WRAPPER_ROOT)/ace/Set.cpp \ + $(WRAPPER_ROOT)/ace/Set.i \ + $(WRAPPER_ROOT)/ace/Token.h \ + $(WRAPPER_ROOT)/ace/Pipe.h \ + $(WRAPPER_ROOT)/ace/Pipe.i \ + $(WRAPPER_ROOT)/ace/SOCK_Stream.h \ + $(WRAPPER_ROOT)/ace/SOCK_IO.h \ + $(WRAPPER_ROOT)/ace/SOCK.h \ + $(WRAPPER_ROOT)/ace/Addr.h \ + $(WRAPPER_ROOT)/ace/IPC_SAP.h \ + $(WRAPPER_ROOT)/ace/IPC_SAP.i \ + $(WRAPPER_ROOT)/ace/SOCK.i \ + $(WRAPPER_ROOT)/ace/SOCK_IO.i \ + $(WRAPPER_ROOT)/ace/INET_Addr.h \ + $(WRAPPER_ROOT)/ace/SOCK_Stream.i \ + $(WRAPPER_ROOT)/ace/Reactor.i +.obj/notification.o .shobj/notification.so: notification.cpp \ + $(WRAPPER_ROOT)/ace/Log_Msg.h \ + $(WRAPPER_ROOT)/ace/Log_Record.h \ + $(WRAPPER_ROOT)/ace/ACE.h \ + $(WRAPPER_ROOT)/ace/OS.h \ + $(WRAPPER_ROOT)/ace/Time_Value.h \ + $(WRAPPER_ROOT)/ace/config.h \ + $(WRAPPER_ROOT)/ace/Trace.h \ + $(WRAPPER_ROOT)/ace/ACE.i \ + $(WRAPPER_ROOT)/ace/Log_Priority.h \ + $(WRAPPER_ROOT)/ace/Log_Record.i \ + $(WRAPPER_ROOT)/ace/Service_Config.h \ + $(WRAPPER_ROOT)/ace/Service_Object.h \ + $(WRAPPER_ROOT)/ace/Shared_Object.h \ + $(WRAPPER_ROOT)/ace/Event_Handler.h \ + $(WRAPPER_ROOT)/ace/Thread_Manager.h \ + $(WRAPPER_ROOT)/ace/Thread.h \ + $(WRAPPER_ROOT)/ace/Synch.h \ + $(WRAPPER_ROOT)/ace/SV_Semaphore_Complex.h \ + $(WRAPPER_ROOT)/ace/SV_Semaphore_Simple.h \ + $(WRAPPER_ROOT)/ace/SV_Semaphore_Simple.i \ + $(WRAPPER_ROOT)/ace/SV_Semaphore_Complex.i \ + $(WRAPPER_ROOT)/ace/Synch_T.h \ + $(WRAPPER_ROOT)/ace/Synch_T.cpp \ + $(WRAPPER_ROOT)/ace/Synch_T.i \ + $(WRAPPER_ROOT)/ace/Set.h \ + $(WRAPPER_ROOT)/ace/Set.cpp \ + $(WRAPPER_ROOT)/ace/Set.i \ + $(WRAPPER_ROOT)/ace/Proactor.h \ + $(WRAPPER_ROOT)/ace/Message_Block.h \ + $(WRAPPER_ROOT)/ace/Malloc.h \ + $(WRAPPER_ROOT)/ace/Malloc_T.h \ + $(WRAPPER_ROOT)/ace/Malloc_T.cpp \ + $(WRAPPER_ROOT)/ace/Malloc_T.i \ + $(WRAPPER_ROOT)/ace/Memory_Pool.h \ + $(WRAPPER_ROOT)/ace/Signal.h \ + $(WRAPPER_ROOT)/ace/Mem_Map.h \ + $(WRAPPER_ROOT)/ace/Timer_Queue.h \ + $(WRAPPER_ROOT)/ace/Timer_Queue.i \ + $(WRAPPER_ROOT)/ace/ReactorEx.h \ + $(WRAPPER_ROOT)/ace/Token.h \ + $(WRAPPER_ROOT)/ace/Reactor.h \ + $(WRAPPER_ROOT)/ace/Handle_Set.h \ + $(WRAPPER_ROOT)/ace/Pipe.h \ + $(WRAPPER_ROOT)/ace/Pipe.i \ + $(WRAPPER_ROOT)/ace/SOCK_Stream.h \ + $(WRAPPER_ROOT)/ace/SOCK_IO.h \ + $(WRAPPER_ROOT)/ace/SOCK.h \ + $(WRAPPER_ROOT)/ace/Addr.h \ + $(WRAPPER_ROOT)/ace/IPC_SAP.h \ + $(WRAPPER_ROOT)/ace/IPC_SAP.i \ + $(WRAPPER_ROOT)/ace/SOCK.i \ + $(WRAPPER_ROOT)/ace/SOCK_IO.i \ + $(WRAPPER_ROOT)/ace/INET_Addr.h \ + $(WRAPPER_ROOT)/ace/SOCK_Stream.i \ + $(WRAPPER_ROOT)/ace/Reactor.i \ + $(WRAPPER_ROOT)/ace/Svc_Conf_Tokens.h +.obj/signal_tester.o .shobj/signal_tester.so: signal_tester.cpp \ + $(WRAPPER_ROOT)/ace/Log_Msg.h \ + $(WRAPPER_ROOT)/ace/Log_Record.h \ + $(WRAPPER_ROOT)/ace/ACE.h \ + $(WRAPPER_ROOT)/ace/OS.h \ + $(WRAPPER_ROOT)/ace/Time_Value.h \ + $(WRAPPER_ROOT)/ace/config.h \ + $(WRAPPER_ROOT)/ace/Trace.h \ + $(WRAPPER_ROOT)/ace/ACE.i \ + $(WRAPPER_ROOT)/ace/Log_Priority.h \ + $(WRAPPER_ROOT)/ace/Log_Record.i \ + $(WRAPPER_ROOT)/ace/Service_Config.h \ + $(WRAPPER_ROOT)/ace/Service_Object.h \ + $(WRAPPER_ROOT)/ace/Shared_Object.h \ + $(WRAPPER_ROOT)/ace/Event_Handler.h \ + $(WRAPPER_ROOT)/ace/Thread_Manager.h \ + $(WRAPPER_ROOT)/ace/Thread.h \ + $(WRAPPER_ROOT)/ace/Synch.h \ + $(WRAPPER_ROOT)/ace/SV_Semaphore_Complex.h \ + $(WRAPPER_ROOT)/ace/SV_Semaphore_Simple.h \ + $(WRAPPER_ROOT)/ace/SV_Semaphore_Simple.i \ + $(WRAPPER_ROOT)/ace/SV_Semaphore_Complex.i \ + $(WRAPPER_ROOT)/ace/Synch_T.h \ + $(WRAPPER_ROOT)/ace/Synch_T.cpp \ + $(WRAPPER_ROOT)/ace/Synch_T.i \ + $(WRAPPER_ROOT)/ace/Set.h \ + $(WRAPPER_ROOT)/ace/Set.cpp \ + $(WRAPPER_ROOT)/ace/Set.i \ + $(WRAPPER_ROOT)/ace/Proactor.h \ + $(WRAPPER_ROOT)/ace/Message_Block.h \ + $(WRAPPER_ROOT)/ace/Malloc.h \ + $(WRAPPER_ROOT)/ace/Malloc_T.h \ + $(WRAPPER_ROOT)/ace/Malloc_T.cpp \ + $(WRAPPER_ROOT)/ace/Malloc_T.i \ + $(WRAPPER_ROOT)/ace/Memory_Pool.h \ + $(WRAPPER_ROOT)/ace/Signal.h \ + $(WRAPPER_ROOT)/ace/Mem_Map.h \ + $(WRAPPER_ROOT)/ace/Timer_Queue.h \ + $(WRAPPER_ROOT)/ace/Timer_Queue.i \ + $(WRAPPER_ROOT)/ace/ReactorEx.h \ + $(WRAPPER_ROOT)/ace/Token.h \ + $(WRAPPER_ROOT)/ace/Reactor.h \ + $(WRAPPER_ROOT)/ace/Handle_Set.h \ + $(WRAPPER_ROOT)/ace/Pipe.h \ + $(WRAPPER_ROOT)/ace/Pipe.i \ + $(WRAPPER_ROOT)/ace/SOCK_Stream.h \ + $(WRAPPER_ROOT)/ace/SOCK_IO.h \ + $(WRAPPER_ROOT)/ace/SOCK.h \ + $(WRAPPER_ROOT)/ace/Addr.h \ + $(WRAPPER_ROOT)/ace/IPC_SAP.h \ + $(WRAPPER_ROOT)/ace/IPC_SAP.i \ + $(WRAPPER_ROOT)/ace/SOCK.i \ + $(WRAPPER_ROOT)/ace/SOCK_IO.i \ + $(WRAPPER_ROOT)/ace/INET_Addr.h \ + $(WRAPPER_ROOT)/ace/SOCK_Stream.i \ + $(WRAPPER_ROOT)/ace/Reactor.i \ + $(WRAPPER_ROOT)/ace/Svc_Conf_Tokens.h +.obj/test_event_handler_t.o .shobj/test_event_handler_t.so: test_event_handler_t.cpp \ + $(WRAPPER_ROOT)/ace/Log_Msg.h \ + $(WRAPPER_ROOT)/ace/Log_Record.h \ + $(WRAPPER_ROOT)/ace/ACE.h \ + $(WRAPPER_ROOT)/ace/OS.h \ + $(WRAPPER_ROOT)/ace/Time_Value.h \ + $(WRAPPER_ROOT)/ace/config.h \ + $(WRAPPER_ROOT)/ace/Trace.h \ + $(WRAPPER_ROOT)/ace/ACE.i \ + $(WRAPPER_ROOT)/ace/Log_Priority.h \ + $(WRAPPER_ROOT)/ace/Log_Record.i \ + $(WRAPPER_ROOT)/ace/Event_Handler_T.h \ + $(WRAPPER_ROOT)/ace/Event_Handler.h +.obj/test_handle_set.o .shobj/test_handle_set.so: test_handle_set.cpp \ + $(WRAPPER_ROOT)/ace/Log_Msg.h \ + $(WRAPPER_ROOT)/ace/Log_Record.h \ + $(WRAPPER_ROOT)/ace/ACE.h \ + $(WRAPPER_ROOT)/ace/OS.h \ + $(WRAPPER_ROOT)/ace/Time_Value.h \ + $(WRAPPER_ROOT)/ace/config.h \ + $(WRAPPER_ROOT)/ace/Trace.h \ + $(WRAPPER_ROOT)/ace/ACE.i \ + $(WRAPPER_ROOT)/ace/Log_Priority.h \ + $(WRAPPER_ROOT)/ace/Log_Record.i \ + $(WRAPPER_ROOT)/ace/Handle_Set.h +.obj/test_reactors.o .shobj/test_reactors.so: test_reactors.cpp \ + $(WRAPPER_ROOT)/ace/Reactor.h \ + $(WRAPPER_ROOT)/ace/Handle_Set.h \ + $(WRAPPER_ROOT)/ace/ACE.h \ + $(WRAPPER_ROOT)/ace/OS.h \ + $(WRAPPER_ROOT)/ace/Time_Value.h \ + $(WRAPPER_ROOT)/ace/config.h \ + $(WRAPPER_ROOT)/ace/Trace.h \ + $(WRAPPER_ROOT)/ace/ACE.i \ + $(WRAPPER_ROOT)/ace/Log_Msg.h \ + $(WRAPPER_ROOT)/ace/Log_Record.h \ + $(WRAPPER_ROOT)/ace/Log_Priority.h \ + $(WRAPPER_ROOT)/ace/Log_Record.i \ + $(WRAPPER_ROOT)/ace/Timer_Queue.h \ + $(WRAPPER_ROOT)/ace/Event_Handler.h \ + $(WRAPPER_ROOT)/ace/Synch.h \ + $(WRAPPER_ROOT)/ace/SV_Semaphore_Complex.h \ + $(WRAPPER_ROOT)/ace/SV_Semaphore_Simple.h \ + $(WRAPPER_ROOT)/ace/SV_Semaphore_Simple.i \ + $(WRAPPER_ROOT)/ace/SV_Semaphore_Complex.i \ + $(WRAPPER_ROOT)/ace/Synch_T.h \ + $(WRAPPER_ROOT)/ace/Synch_T.cpp \ + $(WRAPPER_ROOT)/ace/Thread.h \ + $(WRAPPER_ROOT)/ace/Synch_T.i \ + $(WRAPPER_ROOT)/ace/Timer_Queue.i \ + $(WRAPPER_ROOT)/ace/Signal.h \ + $(WRAPPER_ROOT)/ace/Set.h \ + $(WRAPPER_ROOT)/ace/Set.cpp \ + $(WRAPPER_ROOT)/ace/Set.i \ + $(WRAPPER_ROOT)/ace/Token.h \ + $(WRAPPER_ROOT)/ace/Pipe.h \ + $(WRAPPER_ROOT)/ace/Pipe.i \ + $(WRAPPER_ROOT)/ace/SOCK_Stream.h \ + $(WRAPPER_ROOT)/ace/SOCK_IO.h \ + $(WRAPPER_ROOT)/ace/SOCK.h \ + $(WRAPPER_ROOT)/ace/Addr.h \ + $(WRAPPER_ROOT)/ace/IPC_SAP.h \ + $(WRAPPER_ROOT)/ace/IPC_SAP.i \ + $(WRAPPER_ROOT)/ace/SOCK.i \ + $(WRAPPER_ROOT)/ace/SOCK_IO.i \ + $(WRAPPER_ROOT)/ace/INET_Addr.h \ + $(WRAPPER_ROOT)/ace/SOCK_Stream.i \ + $(WRAPPER_ROOT)/ace/Reactor.i \ + $(WRAPPER_ROOT)/ace/Service_Config.h \ + $(WRAPPER_ROOT)/ace/Service_Object.h \ + $(WRAPPER_ROOT)/ace/Shared_Object.h \ + $(WRAPPER_ROOT)/ace/Thread_Manager.h \ + $(WRAPPER_ROOT)/ace/Proactor.h \ + $(WRAPPER_ROOT)/ace/Message_Block.h \ + $(WRAPPER_ROOT)/ace/Malloc.h \ + $(WRAPPER_ROOT)/ace/Malloc_T.h \ + $(WRAPPER_ROOT)/ace/Malloc_T.cpp \ + $(WRAPPER_ROOT)/ace/Malloc_T.i \ + $(WRAPPER_ROOT)/ace/Memory_Pool.h \ + $(WRAPPER_ROOT)/ace/Mem_Map.h \ + $(WRAPPER_ROOT)/ace/ReactorEx.h \ + $(WRAPPER_ROOT)/ace/Svc_Conf_Tokens.h \ + $(WRAPPER_ROOT)/ace/Task.h \ + $(WRAPPER_ROOT)/ace/Message_Queue.h \ + $(WRAPPER_ROOT)/ace/IO_Cntl_Msg.h \ + $(WRAPPER_ROOT)/ace/Message_Queue.cpp \ + $(WRAPPER_ROOT)/ace/Message_Queue.i \ + $(WRAPPER_ROOT)/ace/Task.cpp \ + $(WRAPPER_ROOT)/ace/Module.h \ + $(WRAPPER_ROOT)/ace/Module.cpp \ + $(WRAPPER_ROOT)/ace/Stream_Modules.h \ + $(WRAPPER_ROOT)/ace/Stream_Modules.cpp \ + $(WRAPPER_ROOT)/ace/Stream_Modules.i \ + $(WRAPPER_ROOT)/ace/Module.i \ + $(WRAPPER_ROOT)/ace/Task.i +.obj/test_signals.o .shobj/test_signals.so: test_signals.cpp \ + $(WRAPPER_ROOT)/ace/Log_Msg.h \ + $(WRAPPER_ROOT)/ace/Log_Record.h \ + $(WRAPPER_ROOT)/ace/ACE.h \ + $(WRAPPER_ROOT)/ace/OS.h \ + $(WRAPPER_ROOT)/ace/Time_Value.h \ + $(WRAPPER_ROOT)/ace/config.h \ + $(WRAPPER_ROOT)/ace/Trace.h \ + $(WRAPPER_ROOT)/ace/ACE.i \ + $(WRAPPER_ROOT)/ace/Log_Priority.h \ + $(WRAPPER_ROOT)/ace/Log_Record.i \ + $(WRAPPER_ROOT)/ace/Reactor.h \ + $(WRAPPER_ROOT)/ace/Handle_Set.h \ + $(WRAPPER_ROOT)/ace/Timer_Queue.h \ + $(WRAPPER_ROOT)/ace/Event_Handler.h \ + $(WRAPPER_ROOT)/ace/Synch.h \ + $(WRAPPER_ROOT)/ace/SV_Semaphore_Complex.h \ + $(WRAPPER_ROOT)/ace/SV_Semaphore_Simple.h \ + $(WRAPPER_ROOT)/ace/SV_Semaphore_Simple.i \ + $(WRAPPER_ROOT)/ace/SV_Semaphore_Complex.i \ + $(WRAPPER_ROOT)/ace/Synch_T.h \ + $(WRAPPER_ROOT)/ace/Synch_T.cpp \ + $(WRAPPER_ROOT)/ace/Thread.h \ + $(WRAPPER_ROOT)/ace/Synch_T.i \ + $(WRAPPER_ROOT)/ace/Timer_Queue.i \ + $(WRAPPER_ROOT)/ace/Signal.h \ + $(WRAPPER_ROOT)/ace/Set.h \ + $(WRAPPER_ROOT)/ace/Set.cpp \ + $(WRAPPER_ROOT)/ace/Set.i \ + $(WRAPPER_ROOT)/ace/Token.h \ + $(WRAPPER_ROOT)/ace/Pipe.h \ + $(WRAPPER_ROOT)/ace/Pipe.i \ + $(WRAPPER_ROOT)/ace/SOCK_Stream.h \ + $(WRAPPER_ROOT)/ace/SOCK_IO.h \ + $(WRAPPER_ROOT)/ace/SOCK.h \ + $(WRAPPER_ROOT)/ace/Addr.h \ + $(WRAPPER_ROOT)/ace/IPC_SAP.h \ + $(WRAPPER_ROOT)/ace/IPC_SAP.i \ + $(WRAPPER_ROOT)/ace/SOCK.i \ + $(WRAPPER_ROOT)/ace/SOCK_IO.i \ + $(WRAPPER_ROOT)/ace/INET_Addr.h \ + $(WRAPPER_ROOT)/ace/SOCK_Stream.i \ + $(WRAPPER_ROOT)/ace/Reactor.i +.obj/test_time_value.o .shobj/test_time_value.so: test_time_value.cpp \ + $(WRAPPER_ROOT)/ace/ACE.h \ + $(WRAPPER_ROOT)/ace/OS.h \ + $(WRAPPER_ROOT)/ace/Time_Value.h \ + $(WRAPPER_ROOT)/ace/config.h \ + $(WRAPPER_ROOT)/ace/Trace.h \ + $(WRAPPER_ROOT)/ace/ACE.i \ + $(WRAPPER_ROOT)/ace/Log_Msg.h \ + $(WRAPPER_ROOT)/ace/Log_Record.h \ + $(WRAPPER_ROOT)/ace/Log_Priority.h \ + $(WRAPPER_ROOT)/ace/Log_Record.i +.obj/test_timer_queue.o .shobj/test_timer_queue.so: test_timer_queue.cpp \ + $(WRAPPER_ROOT)/ace/Log_Msg.h \ + $(WRAPPER_ROOT)/ace/Log_Record.h \ + $(WRAPPER_ROOT)/ace/ACE.h \ + $(WRAPPER_ROOT)/ace/OS.h \ + $(WRAPPER_ROOT)/ace/Time_Value.h \ + $(WRAPPER_ROOT)/ace/config.h \ + $(WRAPPER_ROOT)/ace/Trace.h \ + $(WRAPPER_ROOT)/ace/ACE.i \ + $(WRAPPER_ROOT)/ace/Log_Priority.h \ + $(WRAPPER_ROOT)/ace/Log_Record.i \ + $(WRAPPER_ROOT)/ace/Timer_Queue.h \ + $(WRAPPER_ROOT)/ace/Event_Handler.h \ + $(WRAPPER_ROOT)/ace/Synch.h \ + $(WRAPPER_ROOT)/ace/SV_Semaphore_Complex.h \ + $(WRAPPER_ROOT)/ace/SV_Semaphore_Simple.h \ + $(WRAPPER_ROOT)/ace/SV_Semaphore_Simple.i \ + $(WRAPPER_ROOT)/ace/SV_Semaphore_Complex.i \ + $(WRAPPER_ROOT)/ace/Synch_T.h \ + $(WRAPPER_ROOT)/ace/Synch_T.cpp \ + $(WRAPPER_ROOT)/ace/Thread.h \ + $(WRAPPER_ROOT)/ace/Synch_T.i \ + $(WRAPPER_ROOT)/ace/Timer_Queue.i + +# IF YOU PUT ANYTHING HERE IT WILL GO AWAY diff --git a/examples/Reactor/Misc/notification.cpp b/examples/Reactor/Misc/notification.cpp new file mode 100644 index 00000000000..45836446b5a --- /dev/null +++ b/examples/Reactor/Misc/notification.cpp @@ -0,0 +1,249 @@ +#include "ace/Log_Msg.h" +// @(#)notification.cpp 1.1 10/18/96 + +#include "ace/Service_Config.h" +#include "ace/Thread.h" + +#if defined (ACE_HAS_THREADS) + +class Thread_Handler : public ACE_Event_Handler + // = TITLE + // Illustrate how the ACE_Reactor's thread-safe event notification + // mechanism works. + // + // = DESCRIPTION + // Handle timeouts in the main thread via the ACE_Reactor and I/O + // events in a separate thread. Just before the separate I/O thread + // exits it notifies the ACE_Reactor in the main thread using the + // ACE_Reactor's notification mechanism. +{ +public: + Thread_Handler (int delay, int interval, int n_threads); + Thread_Handler (size_t id): id_ (id) {} + + virtual int handle_signal (int signum, siginfo_t * = 0, ucontext_t * = 0); + // Handle signals. + + virtual int handle_exception (ACE_HANDLE); + // Print data from main thread. + + virtual int handle_output (ACE_HANDLE); + // Print data from main thread. + + virtual int handle_timeout (const ACE_Time_Value &, + const void *); + // Handle timeout events in the main thread. + + virtual int handle_input (ACE_HANDLE); + // General notification messages to the Reactor. + + virtual int notify (void); + // Perform notifications. + + virtual int svc (void); + // Handle I/O events in a separate threads. + +private: + static void *svc_run (void *); + // Glues C++ to C thread library functions. + + size_t id_; + // ID passed in by Thread_Handler constructor. + + // = Timing variables. + // Delay factor for timer-driven I/O. + static ACE_Time_Value delay_; + + // Interval factor for Event_Handler timer. + static ACE_Time_Value interval_; +}; + +// Delay factor for timer-driven I/O. +ACE_Time_Value Thread_Handler::delay_; + +// Interval factor for Event_Handler timer. +ACE_Time_Value Thread_Handler::interval_; + +Thread_Handler::Thread_Handler (int delay, + int interval, + int n_threads) +{ + delay_.set (delay); + interval_.set (interval); + + ACE_Sig_Set sig_set; + + sig_set.sig_add (SIGQUIT); + sig_set.sig_add (SIGINT); + + this->id_ = 0; + + if (ACE::register_stdin_handler (this, + ACE_Service_Config::reactor (), + ACE_Service_Config::thr_mgr ()) == -1) + ACE_ERROR ((LM_ERROR, "%p\n", "register_stdin_handler")); + + else if (ACE_Service_Config::reactor ()->register_handler (sig_set, this) == -1) + ACE_ERROR ((LM_ERROR, "(%t) %p\n", "register_handler")); + + else if (ACE_Service_Config::reactor ()->schedule_timer + (this, 0, Thread_Handler::delay_, Thread_Handler::interval_) == -1) + ACE_ERROR ((LM_ERROR, "(%t) %p\n", "schedule_timer")); + + // Set up this thread's signal mask, which is inherited by the + // threads it spawns. + + ACE_Thread::sigsetmask (SIG_BLOCK, sig_set); + + // Create N new threads of control Thread_Handlers. + + for (size_t i = 0; i < n_threads; i++) + if (ACE_Thread::spawn (&Thread_Handler::svc_run, + new Thread_Handler (i + 1), + THR_NEW_LWP | THR_DETACHED) != 0) + ACE_ERROR ((LM_ERROR, "%p\n", "ACE_Thread::spawn")); + + // Unblock signal set so that only this thread receives them! + ACE_Thread::sigsetmask (SIG_UNBLOCK, sig_set); +} + +// Test stdin handling (can use select to demultiplex HANDLEs) + +int +Thread_Handler::handle_input (ACE_HANDLE handle) +{ + char buf[BUFSIZ]; + ssize_t n = ACE_OS::read (handle, buf, sizeof buf); + + if (n > 0) + { + ACE_DEBUG ((LM_DEBUG, "(%t) %*s", n, buf)); + return this->notify (); + } + else + return -1; +} + +int +Thread_Handler::notify (void) +{ + // Just do something to test the ACE_Reactor's multi-thread + // capabilities... + + if (ACE_Service_Config::reactor ()->notify + (this, ACE_Event_Handler::EXCEPT_MASK) == -1) + ACE_ERROR_RETURN ((LM_ERROR, "(%t) %p\n", "notify"), -1); + + else if (ACE_Service_Config::reactor ()->notify + (this, ACE_Event_Handler::WRITE_MASK) == -1) + ACE_ERROR_RETURN ((LM_ERROR, "(%t) %p\n", "notify"), -1); + + return 0; +} + +// Perform a task that will test the ACE_Reactor's multi-threading +// capabilities in separate threads. + +int +Thread_Handler::svc (void) +{ + for (;;) + { + if (Thread_Handler::delay_.sec () > 0) + // Block for delay_.secs () / 2, then notify the Reactor. + ACE_OS::sleep (Thread_Handler::delay_.sec () / 2); + + this->notify (); + } + return 0; +} + +// Test signal handling. + +int +Thread_Handler::handle_signal (int signum, siginfo_t *, ucontext_t *) +{ + ACE_DEBUG ((LM_DEBUG, "(%t) received signal %S\n", signum)); + + switch (signum) + { + case SIGINT: + case SIGQUIT: + ACE_ERROR ((LM_ERROR, + "(%t) ******************** shutting down %n on signal %S\n", + signum)); + ACE_Service_Config::end_reactor_event_loop (); + } + return 0; +} + +int +Thread_Handler::handle_timeout (const ACE_Time_Value &time, + const void *) +{ + ACE_DEBUG ((LM_DEBUG, "(%t) received timeout at (%u, %u)\n", + time.sec (), time.usec ())); + return 0; +} + +// Called by the ACE_Reactor when it receives a notification. + +int +Thread_Handler::handle_exception (ACE_HANDLE) +{ + ACE_DEBUG ((LM_DEBUG, + "(%t) handle_exception received notification from id %d\n", + this->id_)); + return 0; +} + +// Called by the ACE_Reactor when it receives a notification. + +int +Thread_Handler::handle_output (ACE_HANDLE) +{ + ACE_DEBUG ((LM_DEBUG, + "(%t) handle_output received notification from id %d\n", + this->id_)); + return 0; +} + +// "Shim" function that integrates C thread API with C++. + +void * +Thread_Handler::svc_run (void *eh) +{ + Thread_Handler *this_handler = (Thread_Handler *) eh; + + return this_handler->svc () == 0 ? 0 : (void *) -1; +} + +int +main (int argc, char *argv[]) +{ + // Required to initialize the Service Configurator. + ACE_Service_Config daemon (argv[0]); + + if (argc != 4) + ACE_ERROR ((LM_ERROR, + "usage: %s delay interval n_threads%a\n", + argv[0], 1)); + + int delay = ACE_OS::atoi (argv[1]); + int interval = ACE_OS::atoi (argv[2]); + size_t n_threads = ACE_OS::atoi (argv[3]); + + Thread_Handler thr_handler (delay, interval, n_threads); + + ACE_Service_Config::run_reactor_event_loop (); + ACE_DEBUG ((LM_DEBUG, "exiting from main%a\n", 1)); + return 0; +} +#else +int +main (int, char *[]) +{ + ACE_ERROR_RETURN ((LM_ERROR, + "threads not supported on this platform\n"), -1); +} +#endif /* ACE_HAS_THREADS */ diff --git a/examples/Reactor/Misc/pingpong.cpp b/examples/Reactor/Misc/pingpong.cpp new file mode 100644 index 00000000000..a44267f4e82 --- /dev/null +++ b/examples/Reactor/Misc/pingpong.cpp @@ -0,0 +1,241 @@ +/* Simple program that illustrates all the features of the ACE_Reactor: +// @(#)pingpong.cpp 1.1 10/18/96 + + + 1. I/O event demultiplexing + 2. Signal-based demultiplexing + 3. Timer-based demultiplexing + + To test this program, compile it and then execute it as follows: + + % ./pingpong hello + + You should see lots of the following output: + + writing <4> [7860] + writing <4> [7860] + writing <4> [7860] + writing <4> [7860] + reading <5> (7860) [1] = hello + writing <4> [7860] + writing <5> [7861] + reading <4> (7861) [2] = hello + reading <5> (7860) [2] = hello + writing <4> [7860] + writing <5> [7861] + reading <4> (7861) [3] = hello + reading <5> (7860) [3] = hello + + After 10 seconds you'll see the following: + + ./pingpong: shutting down tester (pid = 7861) + ./pingpong: shutting down tester (pid = 7860) + + and the program will stop. If you'd like to + stop it earlier, just hit the control-C sequence + and you'll see the same messages. */ + +#include "ace/Log_Msg.h" +#include "ace/Synch.h" +#include "ace/Reactor.h" +#include "ace/Pipe.h" + +class Ping_Pong : public ACE_Test_and_Set<ACE_Null_Mutex, sig_atomic_t> +{ +public: + Ping_Pong (char b[], ACE_HANDLE f); + virtual ACE_HANDLE get_handle (void) const; + virtual int handle_input (ACE_HANDLE); + virtual int handle_output (ACE_HANDLE); + virtual int handle_timeout (const ACE_Time_Value &, const void *); + +private: + char buf_[BUFSIZ]; + // Buffer to send. + + size_t buflen_; + // Length of the buffer to send. + + int pid_; + // Process ID. + + ACE_HANDLE handle_; + // Open handle. +}; + +Ping_Pong::Ping_Pong (char b[], ACE_HANDLE f) + : handle_ (f), + buflen_ (ACE_OS::strlen (b) + 1 + (2 * sizeof (int))), + pid_ (ACE_OS::getpid ()) +{ + *((int *) this->buf_) = (int) this->pid_; + *((int *) (this->buf_ + sizeof (int))) = 0; + ACE_OS::strcpy (this->buf_ + (2 * sizeof (int)), b); + this->buf_[this->buflen_ - 1] = '\n'; + this->buf_[this->buflen_] = '\0'; +} + +ACE_HANDLE +Ping_Pong::get_handle (void) const +{ + return this->handle_; +} + +int +Ping_Pong::handle_input (ACE_HANDLE) +{ +#if defined (ACE_HAS_STREAM_PIPES) + // We can rely on record-oriented reads... + + ssize_t n = ACE::recv (this->handle_, this->buf_, this->buflen_); + + if (n != this->buflen_) + ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) reading [%d] %p\n", handle_, "read"), -1); + + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) reading <%d> (%d) [%d] = %s\n", + this->handle_, + *(int *) this->buf_, + *(int *) (this->buf_ + sizeof (int)), + this->buf_ + (2 * sizeof (int)))); +#else + ssize_t n = ACE::recv (this->handle_, this->buf_, sizeof this->buf_); + + if (n == -1) + ACE_ERROR_RETURN ((LM_ERROR, "[%d] %p\n", handle_, "read"), -1); + + n -= (2 * sizeof (int)); + char *buf = this->buf_ + (2 * sizeof (int)); + + ACE_DEBUG ((LM_DEBUG, "(%P|%t) reading <%d> = %*s\n", + this->handle_, n, buf)); +#endif /* ACE_HAS_STREAM_PIPES */ + return 0; +} + +int +Ping_Pong::handle_output (ACE_HANDLE) +{ +#if defined (ACE_HAS_STREAM_PIPES) + // We can rely on record-oriented reads... + + (*(int *) (this->buf_)) = this->pid_; + (*(int *) (this->buf_ + sizeof (int)))++; + if (ACE::send (this->handle_, this->buf_, this->buflen_) == -1) + return -1; + else + { + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) writing <%d> [%d]\n", + this->handle_, this->pid_)); + return 0; + } +#else + if (ACE::send (this->handle_, this->buf_, this->buflen_) == -1) + return -1; + else + { + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) writing <%d>\n", this->handle_)); + return 0; + } +#endif /* ACE_HAS_STREAM_PIPES */ +} + +int +Ping_Pong::handle_timeout (const ACE_Time_Value &, + const void *) +{ + this->set (1); + return 0; +} + +// Contains the string to "pingpong" back and forth... +static char *string_name; + +// Wait for 10 seconds and then shut down. +static const int SHUTDOWN_TIME = 10; + +#if defined (ACE_WIN32) +static ACE_Barrier barrier (3); + +static void * +worker (void *arg) +{ + ACE_HANDLE handle = (ACE_HANDLE) arg; + + run_svc (handle); + barrier.wait (); + ACE_DEBUG ((LM_DEBUG, "(%P|%t) %n: shutting down tester\n")); + return 0; +} +#endif /* ACE_WIN32 */ + +static void +run_svc (ACE_HANDLE handle) +{ + ACE_Reactor reactor; + + Ping_Pong callback (string_name, handle); + + // Register the callback object for the various I/O, signal, and + // timer-based events. + + if (reactor.register_handler (&callback, + ACE_Event_Handler::READ_MASK + | ACE_Event_Handler::WRITE_MASK) == -1 + || reactor.register_handler (SIGINT, &callback) == -1 + || reactor.schedule_timer (&callback, 0, SHUTDOWN_TIME) == -1) + ACE_ERROR ((LM_ERROR, "%p\n%a", "reactor", 1)); + + // Main event loop (one per process). + + while (callback.is_set () == 0) + reactor.handle_events (); +} + +int +main (int argc, char *argv[]) +{ + ACE_LOG_MSG->open (argv[0]); + + if (argc != 2) + ACE_ERROR ((LM_ERROR, "usage: %n string\n%a", 1)); + + string_name = argv[1]; + + ACE_HANDLE handles[2]; + + // Create a pipe and initialize the handles. + ACE_Pipe pipe (handles); + +#if defined (ACE_WIN32) + if (ACE_Thread::spawn (ACE_THR_FUNC (worker), + (void *) handles[0], + THR_DETACHED) == -1 + || ACE_Thread::spawn (ACE_THR_FUNC (worker), + (void *) handles[1], + THR_DETACHED) == -1) + ACE_ERROR ((LM_ERROR, "%p\n%a", "spawn", 1)); + + barrier.wait (); + +#else + pid_t pid = ACE_OS::fork (); + + if (pid == -1) + ACE_ERROR ((LM_ERROR, "%p\n%a", "fork", 1)); + + // Resync the ACE_Log_Msg notion of process id and program name. + ACE_LOG_MSG->sync (argv[0]); + + run_svc (handles[pid == 0]); + + ACE_DEBUG ((LM_DEBUG, "(%P|%t) %n: shutting down tester\n")); +#endif /* ACE_WIN32 */ + + if (pipe.close () == -1) + ACE_ERROR ((LM_ERROR, "%p\n", "close")); + + return 0; +} diff --git a/examples/Reactor/Misc/signal_tester.cpp b/examples/Reactor/Misc/signal_tester.cpp new file mode 100644 index 00000000000..1631c00b2d0 --- /dev/null +++ b/examples/Reactor/Misc/signal_tester.cpp @@ -0,0 +1,221 @@ +// Perform an extensive test of the ACE_Reactor's event dispatching +// @(#)signal_tester.cpp 1.1 10/18/96 + +// mechanisms. These mechanisms illustrate how signals, I/O, and +// timeout events can all be handled within the same framework. In +// addition, this example illustrates how to use the ACE_Reactor for +// devices that perform I/O via signals (such as SVR4 message queues). + +#include "ace/Log_Msg.h" +#include "ace/Service_Config.h" + +// Used to shut down the event loop. +static sig_atomic_t done = 0; + +// This class illustrates how to handle signal-driven I/O using the +// ACE_Reactor framework. Note that signals may be caught and +// processed without requiring the use of global signal handler +// functions or global signal handler data. + +class Sig_Handler : public ACE_Event_Handler +{ +public: + Sig_Handler (void); + virtual ACE_HANDLE get_handle (void) const; + virtual int handle_input (ACE_HANDLE); + virtual int shutdown (ACE_HANDLE, ACE_Reactor_Mask); + virtual int handle_signal (ACE_HANDLE signum, siginfo_t * = 0, + ucontext_t * = 0); + +private: + ACE_HANDLE handle_; +}; + +// A dummy_handle is required to reserve a slot in the ACE_Reactor's +// descriptor table. + +Sig_Handler::Sig_Handler (void) +{ + // Assign the Sig_Handler a dummy I/O descriptor. Note that even + // though we open this file "Write Only" we still need to use the + // ACE_Event_Handler::NULL_MASK when registering this with the + // ACE_Reactor (see below). + this->handle_ = ACE_OS::open (ACE_DEV_NULL, O_WRONLY); + ACE_ASSERT (this->handle_ != -1); + + // Register signal handler object. Note that NULL_MASK is used to + // keep the ACE_Reactor from calling us back on the "/dev/null" + // descriptor. + if (ACE_Service_Config::reactor ()->register_handler + (this, ACE_Event_Handler::NULL_MASK) == -1) + ACE_ERROR ((LM_ERROR, "%p\n%a", "register_handler", 1)); + + // Create a sigset_t corresponding to the signals we want to catch. + ACE_Sig_Set sig_set; + + sig_set.sig_add (SIGINT); + sig_set.sig_add (SIGQUIT); + sig_set.sig_add (SIGALRM); + + // Register the signal handler object to catch the signals. + if (ACE_Service_Config::reactor ()->register_handler (sig_set, this) == -1) + ACE_ERROR ((LM_ERROR, "%p\n%a", "register_handler", 1)); +} + +// Called by the ACE_Reactor to extract the fd. + +ACE_HANDLE +Sig_Handler::get_handle (void) const +{ + return this->handle_; +} + +// In a real application, this method would be where the read on the +// signal-driven I/O device would occur asynchronously. For now we'll +// just print a greeting to let you know that everything is working +// properly! + +int +Sig_Handler::handle_input (ACE_HANDLE) +{ + ACE_DEBUG ((LM_DEBUG, "handling asynchonrous input...\n")); + return 0; +} + +// In a real application, this method would do any cleanup activities +// required when shutting down the I/O device. + +int +Sig_Handler::shutdown (ACE_HANDLE, ACE_Reactor_Mask) +{ + ACE_DEBUG ((LM_DEBUG, "closing down Sig_Handler...\n")); + return 0; +} + +// This method handles all the signals that are being caught by this +// object. In our simple example, we are simply catching SIGALRM, +// SIGINT, and SIGQUIT. Anything else is logged and ignored. +// +// There are several advantages to using this approach. First, +// the behavior triggered by the signal is handled in the main event +// loop, rather than in the signal handler. Second, the ACE_Reactor's +// signal handling mechanism eliminates the need to use global signal +// handler functions and data. + +int +Sig_Handler::handle_signal (int signum, siginfo_t *, ucontext_t *) +{ + ACE_DEBUG ((LM_DEBUG, "received signal %S\n", signum)); + + switch (signum) + { + case SIGALRM: + // Rearm the alarm. + ACE_OS::alarm (4); + break; + case SIGINT: + // Tell the ACE_Reactor to enable the ready bit for + // this->handle_. The ACE_Reactor will subsequently call the + // Sig_Handler::handle_input method from within its event loop. + return ACE_Service_Config::reactor ()->ready_ops + (this->handle_, ACE_Event_Handler::READ_MASK, ACE_Reactor::ADD_MASK); + case SIGQUIT: + ACE_DEBUG ((LM_DEBUG, "%S: shutting down signal tester\n", signum)); + ACE_Service_Config::end_reactor_event_loop (); + break; + default: + ACE_DEBUG ((LM_DEBUG, + "%S: not handled, returning to program\n", signum)); + break; + } + return 0; +} + +// This class illustrates that the ACE_Reactor can handle signals, +// STDIO, and timeouts using the same mechanisms. + +class STDIN_Handler : public ACE_Event_Handler +{ +public: + STDIN_Handler (void); + virtual int handle_input (ACE_HANDLE); + virtual int handle_timeout (const ACE_Time_Value &, + const void *arg); +}; + +STDIN_Handler::STDIN_Handler (void) +{ + if (ACE::register_stdin_handler (this, + ACE_Service_Config::reactor (), + ACE_Service_Config::thr_mgr ()) == -1) + ACE_ERROR ((LM_ERROR, "%p\n", "register_stdin_handler")); + + // Register the STDIN_Handler to be dispatched once every second. + else if (ACE_Service_Config::reactor ()->schedule_timer + (this, 0, ACE_Time_Value (1), ACE_Time_Value (1)) == -1) + ACE_ERROR ((LM_ERROR, "%p\n%a", "schedule_timer", 1)); +} + +int +STDIN_Handler::handle_timeout (const ACE_Time_Value &tv, + const void *arg) +{ + ACE_DEBUG ((LM_DEBUG, "timeout occurred at %d sec, %d usec\n", + tv.sec (), tv.usec ())); + return 0; +} + +// Read from input descriptor and write to stdout descriptor. + +int +STDIN_Handler::handle_input (ACE_HANDLE handle) +{ + ssize_t n; + char buf[BUFSIZ]; + + switch (n = ACE_OS::read (handle, buf, sizeof buf)) + { + case -1: + if (errno == EINTR) + return 0; + /* NOTREACHED */ + else + ACE_ERROR ((LM_ERROR, "%p\n", "read")); + /* FALLTHROUGH */ + case 0: + ACE_Service_Config::end_reactor_event_loop (); + break; + default: + { + ssize_t result = ACE::write_n (ACE_STDOUT, buf, n); + + if (result != n) + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "write"), + result == -1 && errno == EINTR ? 0 : -1); + } + } + return 0; +} + +int +main (int argc, char *argv[]) +{ + ACE_Service_Config daemon (argv [0]); + + // Signal handler. + Sig_Handler sh; + + // Define an I/O handler object. + STDIN_Handler ioh; + + // Optionally start the alarm. + if (argc > 1) + ACE_OS::alarm (4); + + // Loop handling signals and I/O events until SIGQUIT occurs. + + while (daemon.reactor_event_loop_done () == 0) + daemon.run_reactor_event_loop (); + + return 0; +} diff --git a/examples/Reactor/Misc/test_event_handler_t.cpp b/examples/Reactor/Misc/test_event_handler_t.cpp new file mode 100644 index 00000000000..a28108baf10 --- /dev/null +++ b/examples/Reactor/Misc/test_event_handler_t.cpp @@ -0,0 +1,45 @@ +#include "ace/Log_Msg.h" +// @(#)test_event_handler_t.cpp 1.1 10/18/96 + +#include "ace/Event_Handler_T.h" + +#if defined (ACE_HAS_TEMPLATE_TYPEDEFS) + +class ACE_Sig_Handler +{ +public: + ACE_Sig_Handler (void) {} + virtual ACE_HANDLE get_handle (void) const { return 0; } + virtual void set_handle (ACE_HANDLE) {} + virtual int handle_async_io (ACE_HANDLE) { return 0; } + virtual int shutdown (ACE_HANDLE, ACE_Reactor_Mask) { return 0; } + virtual int signal_handler (ACE_HANDLE signum +#if defined (ACE_HAS_SIGINFO_T) + , siginfo_t * = 0, ucontext_t * = 0 +#endif /* ACE_HAS_SIGINFO_T */ + ) + { + return 0; + } +}; + +int +main (void) +{ + typedef ACE_Event_Handler_T<ACE_Sig_Handler> EH_SH; + + // Tie the ACE_Event_Handler_T together with the methods from ACE_Sig_Handler. + EH_SH tied_sh (new ACE_Sig_Handler, 1, + &ACE_Sig_Handler::get_handle, + &ACE_Sig_Handler::handle_async_io, + &ACE_Sig_Handler::shutdown, + &ACE_Sig_Handler::signal_handler); + return 0; +} +#else +int +main (void) +{ + ACE_ERROR_RETURN ((LM_ERROR, "your platform does not support template typedefs\n"), 1); +} +#endif /* ACE_HAS_TEMPLATE_TYPEDEFS */ diff --git a/examples/Reactor/Misc/test_handle_set.cpp b/examples/Reactor/Misc/test_handle_set.cpp new file mode 100644 index 00000000000..65e7db3fc67 --- /dev/null +++ b/examples/Reactor/Misc/test_handle_set.cpp @@ -0,0 +1,75 @@ +#include "ace/Log_Msg.h" +// @(#)test_handle_set.cpp 1.1 10/18/96 + +#include "ace/Handle_Set.h" + +#define IS_ODD(X) (((X) & 1) != 0) + +void +test1 (int count) +{ + int duplicates = 0; + int sets = 0; + int clears = 0; + + ACE_Handle_Set handle_set; + + ACE_OS::srand (ACE_OS::time (0L)); + + for (int i = 0; i < count; i++) + { + int i = int (ACE_OS::rand () % ACE_Handle_Set::MAXSIZE); + + if (IS_ODD (i)) + { + if (handle_set.is_set (i)) + duplicates++; + + handle_set.set_bit (i); + sets++; + } + else + { + if (handle_set.is_set (i)) + duplicates--; + + handle_set.clr_bit (i); + clears++; + } + } + + ACE_DEBUG ((LM_DEBUG, "count = %d, set_size = %d, duplicates = %d\n", + count, handle_set.num_set (), (sets - clears) == duplicates)); +} + +void +test2 (void) +{ + ACE_Handle_Set handle_set; + ACE_HANDLE handle; + + handle_set.set_bit (0); + handle_set.set_bit (1); + handle_set.set_bit (32); + handle_set.set_bit (63); + handle_set.set_bit (64); + handle_set.set_bit (65); + handle_set.set_bit (122); + handle_set.set_bit (129); + handle_set.set_bit (245); + handle_set.set_bit (255); + + for (ACE_Handle_Set_Iterator fi (handle_set); + (handle = fi ()) != -1; + ++fi) + ACE_DEBUG ((LM_DEBUG, "handle = %d\n", handle)); +} + +int +main (int argc, char *argv[]) +{ + int count = argc > 1 ? ACE_OS::atoi (argv[1]) : ACE_Handle_Set::MAXSIZE; + test1 (count); + test2 (); +} + diff --git a/examples/Reactor/Misc/test_reactors.cpp b/examples/Reactor/Misc/test_reactors.cpp new file mode 100644 index 00000000000..81bc1c3a20d --- /dev/null +++ b/examples/Reactor/Misc/test_reactors.cpp @@ -0,0 +1,205 @@ +// Perform a torture test of multiple ACE_Reactors and ACE_Tasks in +// @(#)test_reactors.cpp 1.1 10/18/96 + +// the same process... Thanks to Detlef Becker for contributing this. + +#include "ace/Reactor.h" +#include "ace/Synch.h" +#include "ace/Service_Config.h" +#include "ace/Task.h" + +#if defined (ACE_HAS_THREADS) + +static const int NUM_INVOCATIONS = 10; +static const int MAX_TASKS = 20; + +class Test_Task : public ACE_Task<ACE_MT_SYNCH> +{ +public: + Test_Task (void); + ~Test_Task (void); + + virtual int open (void *args = 0); + virtual int close (u_long flags = 0); + virtual int put (ACE_Message_Block *, ACE_Time_Value *tv = 0); + virtual int svc (void); + + virtual int handle_input (ACE_HANDLE handle); + virtual int handle_close (ACE_HANDLE fd, + ACE_Reactor_Mask close_mask); + +private: + ACE_Reactor *r_; + int handled_; + + static int task_count_; +}; + +int Test_Task::task_count_ = 0; + +static ACE_Atomic_Op<ACE_Thread_Mutex, u_long> done_count = MAX_TASKS * 2; + +static ACE_Recursive_Thread_Mutex reclock_; + +Test_Task::Test_Task (void) + : handled_ (0) +{ + ACE_GUARD (ACE_Recursive_Thread_Mutex, ace_mon, reclock_); + + Test_Task::task_count_++; + ACE_DEBUG ((LM_DEBUG, + "(%t) TT+ Test_Task::task_count_ = %d\n", + Test_Task::task_count_)); +} + +Test_Task::~Test_Task (void) +{ + ACE_GUARD (ACE_Recursive_Thread_Mutex, ace_mon, reclock_); + + ACE_DEBUG ((LM_DEBUG, + "(%t) TT- Test_Task::task_count_ = %d\n", + Test_Task::task_count_)); +} + +int +Test_Task::open (void *args) +{ + r_ = (ACE_Reactor *) args; + return this->activate (THR_NEW_LWP); +} + +int +Test_Task::close (u_long flags) +{ + ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, reclock_, -1); + + Test_Task::task_count_--; + ACE_DEBUG ((LM_DEBUG, + "(%t) close Test_Task::task_count_ = %d\n", + Test_Task::task_count_)); + return 0; +} + +int +Test_Task::put (ACE_Message_Block *mb, + ACE_Time_Value *tv) +{ + return 0; +} + +int +Test_Task::svc (void) +{ + for (int i = 0; i < NUM_INVOCATIONS; i++) + { + ACE_OS::thr_yield (); + + // ACE_DEBUG ((LM_DEBUG, "(%t) calling notify %d\n", i)); + + if (r_->notify (this, ACE_Event_Handler::READ_MASK) == -1) + ACE_ERROR_RETURN ((LM_ERROR, "(%t) %p\n", "notify"), -1); + + // ACE_DEBUG ((LM_DEBUG, "(%t) leaving notify %d\n", i)); + } + + return 0; +} + +int +Test_Task::handle_close (ACE_HANDLE fd, + ACE_Reactor_Mask close_mask) +{ + ACE_DEBUG ((LM_DEBUG, "(%t) handle_close\n")); + return 0; +} + +int +Test_Task::handle_input (ACE_HANDLE fd) +{ + ACE_DEBUG ((LM_DEBUG, "(%t) handle_input\n")); + + this->handled_++; + + if (this->handled_ == NUM_INVOCATIONS) + { + done_count--; + ACE_DEBUG ((LM_DEBUG, + "(%t) handle_input, handled_ = %d, done_count = %d\n", + this->handled_, (u_long) done_count)); + } + + ACE_OS::thr_yield (); + return -1; +} + +static void * +worker (void *args) +{ + ACE_Thread_Control tc (ACE_Service_Config::thr_mgr ()); + ACE_Reactor *reactor = (ACE_Reactor *) args; + + reactor->owner (ACE_Thread::self ()); + + ACE_Time_Value timeout (4); + + for (;;) + { + //ACE_DEBUG ((LM_DEBUG, "(%t) calling handle_events\n")); + + switch (reactor->handle_events (timeout)) + { + case -1: + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "reactor"), 0); + /* NOTREACHED */ + case 0: + ACE_ERROR_RETURN ((LM_ERROR, "timeout\n"), 0); + /* NOTREACHED */ + } + + // ACE_DEBUG ((LM_DEBUG, "(%t) done with handle_events\n")); + + } + + return 0; +} + +int +main (void) +{ + ACE_Reactor *react1 = ACE_Service_Config::reactor (); + ACE_Reactor *react2 = new ACE_Reactor (); + Test_Task tt1[MAX_TASKS]; + Test_Task tt2[MAX_TASKS]; + + for (int i = 0; i < MAX_TASKS; i++) + { + tt1[i].open (react1); + tt2[i].open (react2); + } + + if (ACE_Service_Config::thr_mgr ()->spawn + (ACE_THR_FUNC (worker), (void *) react1, THR_NEW_LWP) == -1) + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "spawn"), -1); + + else if (ACE_Service_Config::thr_mgr ()->spawn + (ACE_THR_FUNC (worker), (void *) react2, THR_NEW_LWP) == -1) + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "spawn"), -1); + + ACE_Service_Config::thr_mgr ()->wait (); + ACE_DEBUG ((LM_DEBUG, "(%t) done\n")); + + return 42; +} + +#if defined (ACE_TEMPLATES_REQUIRE_SPECIALIZATION) +template class ACE_Atomic_Op<ACE_Thread_Mutex, u_long>; +#endif /* ACE_TEMPLATES_REQUIRE_SPECIALIZATION */ + +#else +int +main (int, char *[]) +{ + ACE_ERROR ((LM_ERROR, "threads not supported on this platform\n")); + return 0; +} +#endif /* ACE_HAS_THREADS */ diff --git a/examples/Reactor/Misc/test_signals.cpp b/examples/Reactor/Misc/test_signals.cpp new file mode 100644 index 00000000000..b3725f66c89 --- /dev/null +++ b/examples/Reactor/Misc/test_signals.cpp @@ -0,0 +1,226 @@ +// Test the ability of the Reactor/Signal_Handler to register multiple +// @(#)test_signals.cpp 1.1 10/18/96 + +// handler per-signal. + +/* This test works as follows: + + 1. To test the "original" semantics of ACE (i.e., only one + ACE_Event_Handler can be registered per signal), you don't + need to do anything special. Existing programs work the + same since giving the Reactor's constructor a 0 value + (which is the default argument, BTW) instructs it to behave + as before. When a 0 is given, the ACE_Reactor's + constructor/open method creates an instance of + ACE_Sig_Handler and assigns this to an internal pointer. + This pointer is then used to dispatch all signal-related + methods within the Reactor. The default ACE_Sig_Handler + only allows *one* ACE_Event_Handler to be registered + per-signal. + + To run this version of the test do the following: + + % ./test-signal + ./test_signals + waiting for SIGINT or SIGQUIT + ^C + signal Interrupt occurred in Sig_Handler_2 (fruity, 0, 0) with count = 1 + waiting for SIGINT or SIGQUIT + ^\ + signal Quit occurred in Sig_Handler_2 (fruity, 0, 0) with count = 2 + shutting down SIGQUIT in Sig_Handler_2 (fruity, 0, 0) + waiting for SIGINT or SIGQUIT + ^C + signal Interrupt occurred in Sig_Handler_2 (fruity, 0, 0) with count = 3 + waiting for SIGINT or SIGQUIT + ^\Quit (core dumped) + + Note that in this test only one handler (the last one -- + "Sig_Handler_2 (fruity)") is actually registered. BTW, the + core dump is the expected behavior since the default + disposition is restored when there are no more handlers + (see the code below). + + 2. To test the "multiple handlers per-signal semantics", you + need to pass the constructor/open method of the ACE_Reactor + a pointer to a an instance of ACE_Sig_Handlers (note the + plural "s"). ACE_Sig_Handlers is a class that derives from + ACE_Sig_Handler. The difference between these two classes + is that (1) ACE_Sig_Handlers::register_signal allows + multiple ACE_Event_Handlers to be registered per-signal and + (2) it enables SA_RESTART by default. This class also + implements Detlef Becker's algorithm for integrating ACE + signal handling with 3rd party libraries. + + To run this version of the test do the following: + + % ./test_signals 1 + + waiting for SIGINT or SIGQUIT + ^C + signal Interrupt occurred in external handler! + signal Interrupt occurred in Sig_Handler_1 (howdy, 3, 1) with count = 1 + shutting down SIGINT in Sig_Handler_1 (howdy, 3, 1) + signal Interrupt occurred in Sig_Handler_1 (doody, 5, 4) with count = 1 + shutting down SIGINT in Sig_Handler_1 (doody, 5, 4) + signal Interrupt occurred in Sig_Handler_2 (tutty, 7, 6) with count = 1 + signal Interrupt occurred in Sig_Handler_2 (fruity, 9, 8) with count = 1 + waiting for SIGINT or SIGQUIT + ^\ + signal Quit occurred in Sig_Handler_1 (howdy, 3, 1) with count = 2 + shutting down SIGQUIT in Sig_Handler_1 (howdy, 3, 1) + signal Quit occurred in Sig_Handler_1 (doody, 5, 4) with count = 2 + shutting down SIGQUIT in Sig_Handler_1 (doody, 5, 4) + signal Quit occurred in Sig_Handler_2 (tutty, 7, 6) with count = 2 + shutting down SIGQUIT in Sig_Handler_2 (tutty, 7, 6) + signal Quit occurred in Sig_Handler_2 (fruity, 9, 8) with count = 2 + shutting down SIGQUIT in Sig_Handler_2 (fruity, 9, 8) + waiting for SIGINT or SIGQUIT + ^C + signal Interrupt occurred in external handler! + signal Interrupt occurred in Sig_Handler_2 (tutty, 7, 6) with count = 3 + signal Interrupt occurred in Sig_Handler_2 (fruity, 9, 8) with count = 3 + waiting for SIGINT or SIGQUIT + ^\Quit (core dumped) + + When this test begins all four handlers are registered and + dispatched when a SIGINT or SIGQUIT occurs. After the + first SIGINT, the handle_signal method of the Sig_Handler_1 + objects unregister themselves. At that point there are 4 + SIGQUIT handlers left, but only 2 of our SIGINT handlers + left (and the 1 external handler). After the first + SIGQUIT, there are no SIGQUIT handlers left since they all + deregister themselves (which restores the "SIG_DFL" + disposition). On the second SIGINT there are only 3 + handlers left (2 of ours and 1 external). Finally, on the + second SIGQUIT we exit and dump core since that's what + happens with the default disposition for SIGQUIT. */ + +#include "ace/Log_Msg.h" +#include "ace/Reactor.h" + +class Sig_Handler_1 : public ACE_Event_Handler +{ +public: + Sig_Handler_1 (ACE_Reactor &reactor, char *msg) + : msg_ (msg), + count_ (0), + reactor_ (reactor) + { + // Register the signal handlers. + this->quit_sigkey_ = reactor.register_handler (SIGQUIT, this); + this->int_sigkey_ = reactor.register_handler (SIGINT, this); + + if (this->quit_sigkey_ == -1 || this->int_sigkey_ == -1) + ACE_ERROR ((LM_ERROR, "%p\n", "register_handler")); + } + + virtual int handle_signal (int signum, siginfo_t *, ucontext_t *) + { + this->count_++; + ACE_DEBUG ((LM_DEBUG, + "\nsignal %S occurred in Sig_Handler_1 (%s, %d, %d) with count = %d", + signum, this->msg_, this->int_sigkey_, this->quit_sigkey_, this->count_)); + if (this->count_ != 1 && signum == SIGQUIT) + { + if (this->reactor_.remove_handler (SIGQUIT, 0, 0, + this->quit_sigkey_) == -1) + ACE_ERROR ((LM_ERROR, "\n%p", "remove_handler")); + else + ACE_DEBUG ((LM_DEBUG, "\nshutting down SIGQUIT in Sig_Handler_1 (%s, %d, %d)", + this->msg_, this->int_sigkey_, this->quit_sigkey_)); + } + else if (this->count_ != 2 && signum == SIGINT) + { + if (this->reactor_.remove_handler (SIGINT, 0, 0, + this->int_sigkey_) == -1) + ACE_ERROR ((LM_ERROR, "\n%p", "remove_handler")); + else + ACE_DEBUG ((LM_DEBUG, "\nshutting down SIGINT in Sig_Handler_1 (%s, %d, %d)", + this->msg_, this->int_sigkey_, this->quit_sigkey_)); + } + return 0; + } + +protected: + char *msg_; + int count_; + int int_sigkey_; + int quit_sigkey_; + ACE_Reactor &reactor_; +}; + +class Sig_Handler_2 : public Sig_Handler_1 +{ +public: + Sig_Handler_2 (ACE_Reactor &reactor, char *msg) + : Sig_Handler_1 (reactor, msg) + { + } + + virtual int handle_signal (int signum, siginfo_t *, ucontext_t *) + { + this->count_++; + ACE_DEBUG ((LM_DEBUG, + "\nsignal %S occurred in Sig_Handler_2 (%s, %d, %d) with count = %d", + signum, this->msg_, this->int_sigkey_, this->quit_sigkey_, this->count_)); + if (this->count_ != 0 && signum == SIGQUIT) + { + if (this->reactor_.remove_handler (SIGQUIT, 0, 0, + this->quit_sigkey_) == -1) + ACE_ERROR ((LM_ERROR, "\n%p", "remove_handler")); + else + ACE_DEBUG ((LM_DEBUG, "\nshutting down SIGQUIT in Sig_Handler_2 (%s, %d, %d)", + this->msg_, this->int_sigkey_, this->quit_sigkey_)); + } + else + return 0; + } +}; + +static void +external_handler (int signum) +{ + ACE_DEBUG ((LM_DEBUG, "\nsignal %S occurred in external handler!", signum)); +} + +#if !defined (HPUX) +int +main (int argc, char *argv) +{ + // If argc > 1 then allow multiple handlers per-signal, else just + // allow 1 handler per-signal. + ACE_Sig_Handlers multi_handlers; + + ACE_Reactor reactor (argc > 1 ? &multi_handlers: 0); + + if (argc > 1) + { + // Register an "external" signal handler so that the + // ACE_Sig_Handlers code will have something to incorporate! + ACE_SignalHandler eh = ACE_SignalHandler (external_handler); + ACE_Sig_Action sa (eh); + + sa.register_action (SIGINT); + } + + // Create a bevy of handlers. + Sig_Handler_1 h1 (reactor, "howdy"), h2 (reactor, "doody"); + Sig_Handler_2 h3 (reactor, "tutty"), h4 (reactor, "fruity"); + + // Wait for user to type SIGINT and SIGQUIT. + + for (;;) + { + ACE_DEBUG ((LM_DEBUG, "\nwaiting for SIGINT or SIGQUIT\n")); + reactor.handle_events (); + } + return 0; +} +#else +int +main (void) +{ + ACE_ERROR_RETURN ((LM_ERROR, "The HP C++ compiler is too lame to support this feature\n"), -1); +} +#endif /* HPUX */ diff --git a/examples/Reactor/Misc/test_time_value.cpp b/examples/Reactor/Misc/test_time_value.cpp new file mode 100644 index 00000000000..691528eb292 --- /dev/null +++ b/examples/Reactor/Misc/test_time_value.cpp @@ -0,0 +1,69 @@ +#include "ace/ACE.h" +// @(#)test_time_value.cpp 1.1 10/18/96 + + +inline int my_abs (int d) { return d > 0 ? d : -d; } + +ostream & +operator<< (ostream &stream, const ACE_Time_Value &tv) +{ + if (tv.usec () < 0 || tv.sec () < 0) + stream << "-"; + + stream << dec << my_abs (int (tv.sec ())) << "." +// << setw (6) << setfill ('0') + << dec << my_abs (int (tv.usec ())); + return stream; +} + +int +main (int argc, char *argv[]) +{ + ACE_Time_Value tv1; + ACE_Time_Value tv2 (2); + ACE_Time_Value tv3 (100); + ACE_Time_Value tv4 (1, 1000000); + ACE_Time_Value tv5 (2); + ACE_Time_Value tv6 (1, -1000000); + + ACE_ASSERT (tv1 == ACE_Time_Value (0)); + ACE_ASSERT (tv2 < tv3); + ACE_ASSERT (tv2 <= tv2); + ACE_ASSERT (tv2 >= tv4); + ACE_ASSERT (tv5 >= tv6); + ACE_ASSERT (tv2 == ACE_Time_Value (1, 1000000)); + ACE_ASSERT (tv5 == tv4); + ACE_ASSERT (tv2 == tv4); + ACE_ASSERT (tv1 != tv2); + ACE_ASSERT (tv6 == tv1); + + cout << "0,0 :\t\t" << ACE_Time_Value (0,0) << endl; + cout << "-0,0 :\t\t" << ACE_Time_Value (-0,0) << endl; + cout << "0,-0 :\t\t" << ACE_Time_Value (0,-0) << endl; + cout << "-0,-0 :\t\t" << ACE_Time_Value (-0,-0) << endl; + cout << endl; + + cout << "0,1 :\t\t" << ACE_Time_Value (0,1) << endl; + cout << "1,0 :\t\t" << ACE_Time_Value (1,0) << endl; + cout << "-1,0 :\t\t" << ACE_Time_Value (-1,0) << endl; + cout << "-1,-0 :\t\t" << ACE_Time_Value (-1,-0) << endl; + cout << endl; + + cout << "1,1 :\t\t" << ACE_Time_Value (1,1) << endl; + cout << "-1,1 :\t\t" << ACE_Time_Value (-1,1) << endl; + cout << "1,-1 :\t\t" << ACE_Time_Value (1,-1) << endl; + cout << "-1,-1 :\t\t" << ACE_Time_Value (-1,-1) << endl; + cout << endl; + + cout << "1,-1111111 :\t" << ACE_Time_Value (1,-1111111) << endl; + cout << "1,-100000 :\t" << ACE_Time_Value (1,-100000) << endl; + cout << "1,-1000000 :\t" << ACE_Time_Value (1,-1000000) << endl; + cout << "-1,1000000 :\t" << ACE_Time_Value (-1,1000000) << endl; + cout << "5,-1000000 :\t" << ACE_Time_Value (5,-1000000) << endl; + cout << "5,-1500000 :\t" << ACE_Time_Value (5,-1500000) << endl; + cout << "2,-2500000 :\t" << ACE_Time_Value (2,-2500000) << endl; + cout << "2,-4500000 :\t" << ACE_Time_Value (2,-4500000) << endl; + + return 0; +} + diff --git a/examples/Reactor/Misc/test_timer_queue.cpp b/examples/Reactor/Misc/test_timer_queue.cpp new file mode 100644 index 00000000000..4e7010d1e94 --- /dev/null +++ b/examples/Reactor/Misc/test_timer_queue.cpp @@ -0,0 +1,47 @@ +#include "ace/Log_Msg.h" +// @(#)test_timer_queue.cpp 1.1 10/18/96 + +#include "ace/Timer_Queue.h" + +class Example_Handler : public ACE_Event_Handler +{ +public: + Example_Handler (void) + : count_ (0) + {} + + virtual int handle_timeout (const ACE_Time_Value &tv, const void *arg) + { + ACE_DEBUG ((LM_DEBUG, "yow, the time has come and gone %d times %d, Horatio!\n", + this->count_++, int (arg))); + return 0; + } + +private: + int count_; +}; + +int +main (int argc, char *argv[]) +{ + ACE_Timer_Queue tq; + Example_Handler eh; + + ACE_ASSERT (tq.is_empty ()); + ACE_ASSERT (ACE_Time_Value::zero == ACE_Time_Value (0)); + int timer_id; + + timer_id = tq.schedule (&eh, (const void *) 1, ACE_OS::gettimeofday ()); + tq.schedule (&eh, (const void *) 2, ACE_OS::gettimeofday ()); + tq.schedule (&eh, (const void *) 3, ACE_OS::gettimeofday ()); + tq.cancel (timer_id); + ACE_ASSERT (!tq.is_empty ()); + tq.expire (ACE_OS::gettimeofday ()); + tq.schedule (&eh, (const void *) 4, ACE_OS::gettimeofday ()); + tq.schedule (&eh, (const void *) 5, ACE_OS::gettimeofday ()); + tq.cancel (&eh); + ACE_ASSERT (tq.is_empty ()); + tq.expire (ACE_OS::gettimeofday ()); + return 0; +} + diff --git a/examples/Reactor/Multicast/Log_Wrapper.cpp b/examples/Reactor/Multicast/Log_Wrapper.cpp new file mode 100644 index 00000000000..0b0526cdf2c --- /dev/null +++ b/examples/Reactor/Multicast/Log_Wrapper.cpp @@ -0,0 +1,75 @@ +// client.C +// @(#)Log_Wrapper.cpp 1.1 10/18/96 + + +#include "Log_Wrapper.h" + +Log_Wrapper::Log_Wrapper (void) +{ + this->log_msg_.sequence_number = 0; + this->log_msg_.app_id = ACE_OS::getpid(); +} + +Log_Wrapper::~Log_Wrapper (void) +{ +} + +// Set the log_msg_ host address. +// Get a binding to a logger object from orbixd + +int +Log_Wrapper::open (const int port, const char *mcast_addr) +{ + struct hostent *host_info; + struct utsname host_data; + + if (ACE_OS::uname (&host_data) < 0) + return -1; + + if ((host_info = ACE_OS::gethostbyname (host_data.nodename)) == NULL) + return -1; + else + ACE_OS::memcpy ((char *) &this->log_msg_.host, + (char *) host_info->h_addr, + host_info->h_length); + + // This starts out initialized to all zeros! + ACE_INET_Addr sockdg_addr; + + if (this->logger_.open (sockdg_addr) == -1) + return -1; + + if (this->server_.set (port, mcast_addr) == -1) + return -1; + + // success. + return 0; +} + +// Send the message to a logger object. +// This wrapper fills in all the log_record info for you. +// uses iovector stuff to make contiguous header and message. + +int +Log_Wrapper::log_message (ACE_Log_Priority type, char *message) +{ + this->log_msg_.type = type; this->log_msg_.time = time (0); + this->log_msg_.msg_length = strlen(message); + this->log_msg_.sequence_number++; + + iovec *iovp = new iovec[2]; + iovp[0].iov_base = (char *) &log_msg_; + iovp[0].iov_len = sizeof log_msg_; + iovp[1].iov_base = message; + iovp[1].iov_len = log_msg_.msg_length; + + logger_.send (iovp, 2, server_); + + delete iovp; + + // success. + return 0; +} + + + diff --git a/examples/Reactor/Multicast/Log_Wrapper.h b/examples/Reactor/Multicast/Log_Wrapper.h new file mode 100644 index 00000000000..d1932d92cfa --- /dev/null +++ b/examples/Reactor/Multicast/Log_Wrapper.h @@ -0,0 +1,59 @@ +/* -*- C++ -*- */ +// @(#)Log_Wrapper.h 1.1 10/18/96 + + +// log_wrapper.h +// wrapper around sending log messages via multicast + +#include "ace/Profile_Timer.h" +#include "ace/INET_Addr.h" +#include "ace/SOCK_Dgram.h" + +#if !defined (_LM_WRAPPER_H) +#define _LM_WRAPPER_H + +class Log_Wrapper +{ +public: + Log_Wrapper (void); + ~Log_Wrapper (void); + + // = Types of logging messages. + enum ACE_Log_Priority + { + LM_MESSAGE, + LM_DEBUG, + LM_WARNING, + LM_ERROR, + LM_EMERG + }; + + int open (const int port, const char* mcast_addr); + // get an object reference from an orbixd + + int log_message (ACE_Log_Priority type, char *message); + // send a string to the logger + + // = Format of the logging record. + struct ACE_Log_Record + { + unsigned long sequence_number; + ACE_Log_Priority type; + long host; + long time; + long app_id; + long msg_length; + }; + +private: + ACE_INET_Addr server_; + // Server address where records are logged. + + ACE_Log_Record log_msg_; + // One record used for many log messages. + + ACE_SOCK_Dgram logger_; + // A logger object. +}; + +#endif /* _LM_WRAPPER_H */ diff --git a/examples/Reactor/Multicast/Makefile b/examples/Reactor/Multicast/Makefile new file mode 100644 index 00000000000..980cb7d28b3 --- /dev/null +++ b/examples/Reactor/Multicast/Makefile @@ -0,0 +1,69 @@ +#---------------------------------------------------------------------------- +# @(#)Makefile 1.1 10/18/96 +# +# Makefile for the Reactor multicast tests +#---------------------------------------------------------------------------- + +#---------------------------------------------------------------------------- +# Local macros +#---------------------------------------------------------------------------- + +BIN = client server + +FILES = Log_Wrapper + +LSRC = $(addsuffix .cpp,$(FILES)) +LOBJ = $(addsuffix .o,$(FILES)) +SHOBJ = $(addsuffix .so,$(FILES)) + +LDLIBS = $(addprefix .shobj/,$(SHOBJ)) + +VLDLIBS = $(LDLIBS:%=%$(VAR)) + +BUILD = $(VBIN) + +#---------------------------------------------------------------------------- +# ACE stuff +#---------------------------------------------------------------------------- + +include $(WRAPPER_ROOT)/include/makeinclude/wrapper_macros.GNU +include $(WRAPPER_ROOT)/include/makeinclude/macros.GNU +include $(WRAPPER_ROOT)/include/makeinclude/rules.common.GNU +include $(WRAPPER_ROOT)/include/makeinclude/rules.nonested.GNU +include $(WRAPPER_ROOT)/include/makeinclude/rules.lib.GNU +include $(WRAPPER_ROOT)/include/makeinclude/rules.bin.GNU +include $(WRAPPER_ROOT)/include/makeinclude/rules.local.GNU + +#---------------------------------------------------------------------------- +# Local targets +#---------------------------------------------------------------------------- + +#---------------------------------------------------------------------------- +# Dependencies +#---------------------------------------------------------------------------- + +# DO NOT DELETE THIS LINE -- g++dep uses it. +# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY. + +.obj/Log_Wrapper.o .shobj/Log_Wrapper.so: Log_Wrapper.cpp Log_Wrapper.h \ + $(WRAPPER_ROOT)/ace/Profile_Timer.h \ + $(WRAPPER_ROOT)/ace/ACE.h \ + $(WRAPPER_ROOT)/ace/OS.h \ + $(WRAPPER_ROOT)/ace/Time_Value.h \ + $(WRAPPER_ROOT)/ace/config.h \ + $(WRAPPER_ROOT)/ace/Trace.h \ + $(WRAPPER_ROOT)/ace/ACE.i \ + $(WRAPPER_ROOT)/ace/Log_Msg.h \ + $(WRAPPER_ROOT)/ace/Log_Record.h \ + $(WRAPPER_ROOT)/ace/Log_Priority.h \ + $(WRAPPER_ROOT)/ace/Log_Record.i \ + $(WRAPPER_ROOT)/ace/INET_Addr.h \ + $(WRAPPER_ROOT)/ace/Addr.h \ + $(WRAPPER_ROOT)/ace/SOCK_Dgram.h \ + $(WRAPPER_ROOT)/ace/SOCK.h \ + $(WRAPPER_ROOT)/ace/IPC_SAP.h \ + $(WRAPPER_ROOT)/ace/IPC_SAP.i \ + $(WRAPPER_ROOT)/ace/SOCK.i \ + $(WRAPPER_ROOT)/ace/SOCK_Dgram.i + +# IF YOU PUT ANYTHING HERE IT WILL GO AWAY diff --git a/examples/Reactor/Multicast/README b/examples/Reactor/Multicast/README new file mode 100644 index 00000000000..85f64cc8120 --- /dev/null +++ b/examples/Reactor/Multicast/README @@ -0,0 +1,15 @@ +The following test illustrates the SOCK Mcast multicast wrappers in +conjunction with the Reactor. This test was written by Tim Harrison +(harrison@cs.wustl.edu). + +To run the server type: + +% server & + +It will wait for the first message sent to it and then read for 5 seconds. + +To run the client type any of these: + +% client -m max_message_size -i iterations +% client < <filename> +% client diff --git a/examples/Reactor/Multicast/client.cpp b/examples/Reactor/Multicast/client.cpp new file mode 100644 index 00000000000..1f5774fdb26 --- /dev/null +++ b/examples/Reactor/Multicast/client.cpp @@ -0,0 +1,110 @@ +// client.C (written by Tim Harrison) +// @(#)client.cpp 1.1 10/18/96 + +// This program reads in messages from stdin and sends them +// to a Log_Wrapper. + +#include "ace/Log_Msg.h" +#include "Log_Wrapper.h" + +const char *MCAST_ADDR = ACE_DEFAULT_MULTICAST_ADDR; + +// this is hardware specific. +// use netstat(1M) to find whether your interface +// is le0 or ie0 + +const int UDP_PORT = ACE_DEFAULT_MULTICAST_PORT; + +// maximum message size +static int max_message_size = BUFSIZ * 20; + +// number of times to send message of max_message_size +static int iterations = 0; + +static void +parse_args (int argc, char *argv[]) +{ + extern char *optarg; + extern int optind; + int c; + + ACE_LOG_MSG->open (argv[0]); + + while ((c = ACE_OS::getopt (argc, argv, "m:ui:")) != -1) + switch (c) + { + case 'm': + max_message_size = ACE_OS::atoi (optarg) * BUFSIZ; + break; + case 'i': + iterations = ACE_OS::atoi (optarg); + break; + case 'u': + // usage fallthrough + default: + ACE_ERROR ((LM_ERROR, "%n: -m max_message_size (in k) -i iterations\n%a", 1)); + /* NOTREACHED */ + } +} + +int +main (int argc, char **argv) +{ + int user_prompt; + + parse_args (argc,argv); + + ACE_DEBUG ((LM_DEBUG, "Max Buffer size = %d\n", max_message_size)); + + // Instantiate a log wrapper for logging + Log_Wrapper log; + + // make a connection to a logger via orbixd + if (log.open (UDP_PORT, MCAST_ADDR) == -1) + ACE_OS::perror ("connect failed"), ACE_OS::exit (1); + + char *buf = new char[::max_message_size]; + + // if -i has been specified, send max_message_size messages + // iterations number of times + if (iterations) + { + ACE_OS::memset (buf,1,::max_message_size); + while (iterations--) + if (log.log_message (Log_Wrapper::LM_DEBUG, buf) == -1) + perror("log failed."), exit(1); + } + + // otherwise, a file has been redirected, or give prompts + else + { + // If a file has been redirected, don't activate user prompts + if (ACE_OS::isatty (0)) + user_prompt = 1; + else + user_prompt = 0; + + int nbytes; + // continually read messages from stdin and log them. + while (1) + { + if (user_prompt) + ACE_DEBUG ((LM_DEBUG, "\nEnter message ('Q':quit):\n")); + + if ((nbytes = read (0, buf, max_message_size)) == 0) + break; // end of file + buf[nbytes] = '\0'; + + // quitting? + if (buf[0] == 'Q') + break; + + // send the message to the logger + else if (log.log_message (Log_Wrapper::LM_DEBUG, buf) == -1) + perror("log failed."), exit(1); + } // while(1) + } + + ACE_DEBUG ((LM_DEBUG, "Client done.\n")); + return 0; +} diff --git a/examples/Reactor/Multicast/server.cpp b/examples/Reactor/Multicast/server.cpp new file mode 100644 index 00000000000..b9c3942a9a7 --- /dev/null +++ b/examples/Reactor/Multicast/server.cpp @@ -0,0 +1,157 @@ +// server.C (written by Tim Harrison) +// @(#)server.cpp 1.1 10/18/96 + +// +// listens to multicast address. after first message received, will +// listen for 5 more seconds. prints Mbits/sec received from client. + +#include "ace/SOCK_Dgram.h" +#include "ace/INET_Addr.h" +#include "ace/Log_Msg.h" +#include "ace/SOCK_Dgram_Mcast.h" +#include "ace/Reactor.h" +#include "Log_Wrapper.h" + +#if defined (ACE_HAS_IP_MULTICAST) +class Server_Events : public ACE_Event_Handler +{ +public: + Server_Events (u_short port, + const char *mcast_addr, + long time_interval = 0); + ~Server_Events (void); + + virtual int handle_input (ACE_HANDLE fd); + virtual ACE_HANDLE get_handle (void) const; + + ACE_Time_Value *wait_time (void); + +private: + char *message_; + Log_Wrapper::ACE_Log_Record *log_record_; + char buf_[4*BUFSIZ]; + + int interval_; + // time interval to log messages + + ACE_Time_Value *how_long_; + ACE_Reactor *reactor_; + ACE_SOCK_Dgram_Mcast mcast_dgram_; + ACE_INET_Addr remote_addr_; + ACE_INET_Addr mcast_addr_; + + // = statistics on messages received + double total_bytes_received_; + int total_messages_received_; + int last_sequence_number_; +}; + +ACE_HANDLE +Server_Events::get_handle (void) const +{ + return this->mcast_dgram_.get_handle (); +} + +ACE_Time_Value * +Server_Events::wait_time (void) +{ + return this->how_long_; +} + +Server_Events::Server_Events (u_short port, + const char *mcast_addr, + long time_interval) + : total_bytes_received_ (0), + interval_ (time_interval), + mcast_addr_ (port, mcast_addr) +{ + // use ACE_SOCK_Dgram_Mcast factory to subscribe to multicast group. + + if (this->mcast_dgram_.subscribe (this->mcast_addr_) == -1) + perror("can't subscribe to multicast group"), exit(1); + + // Point to NULL so that we block in the beginning. + this->how_long_ = 0; + + this->log_record_ = (Log_Wrapper::ACE_Log_Record *) &buf_; + this->message_ = &buf_[sizeof (Log_Wrapper::ACE_Log_Record)]; +} + +// A destructor that emacs refuses to color blue ;-) + +Server_Events::~Server_Events (void) +{ + this->mcast_dgram_.unsubscribe (); + + ACE_DEBUG ((LM_DEBUG, "total bytes received = %d after %d second\n", + this->total_bytes_received_, this->interval_)); + + ACE_DEBUG ((LM_DEBUG, "Mbits/sec = %.2f\n", + (float) (total_bytes_received_ * 8 / (float) (1024*1024*interval_)))); + + ACE_DEBUG ((LM_DEBUG, + "last sequence number = %d\ntotal messages received = %d\ndiff = %d\n", + this->last_sequence_number_, + this->total_messages_received_, + this->last_sequence_number_ - total_messages_received_)); +} + +int +Server_Events::handle_input (ACE_HANDLE fd) +{ + // after the first message, point this to a timer + // that way, the next time reactor::handle_events is called, + // a nonzero time value will be passed in. + if (this->how_long_ == 0) + this->how_long_ = new ACE_Time_Value (this->interval_); + + // receive message from multicast group + int retcode = this->mcast_dgram_.recv (this->buf_, + sizeof this->buf_, + this->remote_addr_); + if (retcode != -1) + { + total_messages_received_++; + total_bytes_received_ += retcode; + last_sequence_number_ = log_record_->sequence_number; + ACE_DEBUG ((LM_DEBUG, "sequence number = %d\n", + log_record_->sequence_number)); + return 0; + } + else + return -1; +} + +static const char MCAST_ADDR[] = ACE_DEFAULT_MULTICAST_ADDR; +static const int UDP_PORT = ACE_DEFAULT_MULTICAST_PORT; + +int +main(int argc, char *argv[]) +{ + int duration = 5; + + // Instantiate a server which will receive messages for 5 seconds. + Server_Events server_events (UDP_PORT, MCAST_ADDR, duration); + + // Instance of the ACE_Reactor. + ACE_Reactor reactor; + + if (reactor.register_handler (&server_events, + ACE_Event_Handler::READ_MASK) == -1) + ACE_ERROR ((LM_ERROR, "%p\n%a", "register_handler", 1)); + + for (;;) + reactor.handle_events (server_events.wait_time ()); + + /* NOTREACHED */ + return 0; +} +#else +int +main (int argc, char *argv[]) +{ + ACE_ERROR_RETURN ((LM_ERROR, + "error: %s must be run on a platform that support IP multicast\n", + argv[0]), -1); +} +#endif /* ACE_HAS_IP_MULTICAST */ diff --git a/examples/Reactor/Ntalker/Makefile b/examples/Reactor/Ntalker/Makefile new file mode 100644 index 00000000000..d01010c27a0 --- /dev/null +++ b/examples/Reactor/Ntalker/Makefile @@ -0,0 +1,91 @@ +#---------------------------------------------------------------------------- +# @(#)Makefile 1.1 10/18/96 +# +# Makefile for ntalker demo of SOCK_Dgram_Mcast +#---------------------------------------------------------------------------- + +#---------------------------------------------------------------------------- +# Local macros +#---------------------------------------------------------------------------- + +BIN = ntalker + +SRC = $(addsuffix .cpp,$(BIN)) + +LDLIBS = +VLDLIBS = $(LDLIBS:%=%$(VAR)) + +BUILD = $(VBIN) + +#---------------------------------------------------------------------------- +# ACE stuff +#---------------------------------------------------------------------------- + +include $(WRAPPER_ROOT)/include/makeinclude/wrapper_macros.GNU +include $(WRAPPER_ROOT)/include/makeinclude/macros.GNU +include $(WRAPPER_ROOT)/include/makeinclude/rules.common.GNU +include $(WRAPPER_ROOT)/include/makeinclude/rules.nonested.GNU +include $(WRAPPER_ROOT)/include/makeinclude/rules.lib.GNU +include $(WRAPPER_ROOT)/include/makeinclude/rules.bin.GNU +include $(WRAPPER_ROOT)/include/makeinclude/rules.local.GNU + +#---------------------------------------------------------------------------- +# Local targets +#---------------------------------------------------------------------------- + +#---------------------------------------------------------------------------- +# Dependencies +#---------------------------------------------------------------------------- + +# DO NOT DELETE THIS LINE -- g++dep uses it. +# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY. + +.obj/ntalker.o .shobj/ntalker.so: ntalker.cpp \ + $(WRAPPER_ROOT)/ace/INET_Addr.h \ + $(WRAPPER_ROOT)/ace/ACE.h \ + $(WRAPPER_ROOT)/ace/OS.h \ + $(WRAPPER_ROOT)/ace/Time_Value.h \ + $(WRAPPER_ROOT)/ace/config.h \ + $(WRAPPER_ROOT)/ace/Trace.h \ + $(WRAPPER_ROOT)/ace/ACE.i \ + $(WRAPPER_ROOT)/ace/Log_Msg.h \ + $(WRAPPER_ROOT)/ace/Log_Record.h \ + $(WRAPPER_ROOT)/ace/Log_Priority.h \ + $(WRAPPER_ROOT)/ace/Log_Record.i \ + $(WRAPPER_ROOT)/ace/Addr.h \ + $(WRAPPER_ROOT)/ace/SOCK_Dgram_Mcast.h \ + $(WRAPPER_ROOT)/ace/SOCK_Dgram.h \ + $(WRAPPER_ROOT)/ace/SOCK.h \ + $(WRAPPER_ROOT)/ace/IPC_SAP.h \ + $(WRAPPER_ROOT)/ace/IPC_SAP.i \ + $(WRAPPER_ROOT)/ace/SOCK.i \ + $(WRAPPER_ROOT)/ace/SOCK_Dgram.i \ + $(WRAPPER_ROOT)/ace/SOCK_Dgram_Mcast.i \ + $(WRAPPER_ROOT)/ace/Reactor.h \ + $(WRAPPER_ROOT)/ace/Handle_Set.h \ + $(WRAPPER_ROOT)/ace/Timer_Queue.h \ + $(WRAPPER_ROOT)/ace/Event_Handler.h \ + $(WRAPPER_ROOT)/ace/Synch.h \ + $(WRAPPER_ROOT)/ace/SV_Semaphore_Complex.h \ + $(WRAPPER_ROOT)/ace/SV_Semaphore_Simple.h \ + $(WRAPPER_ROOT)/ace/SV_Semaphore_Simple.i \ + $(WRAPPER_ROOT)/ace/SV_Semaphore_Complex.i \ + $(WRAPPER_ROOT)/ace/Synch_T.h \ + $(WRAPPER_ROOT)/ace/Synch_T.cpp \ + $(WRAPPER_ROOT)/ace/Thread.h \ + $(WRAPPER_ROOT)/ace/Synch_T.i \ + $(WRAPPER_ROOT)/ace/Timer_Queue.i \ + $(WRAPPER_ROOT)/ace/Signal.h \ + $(WRAPPER_ROOT)/ace/Set.h \ + $(WRAPPER_ROOT)/ace/Set.cpp \ + $(WRAPPER_ROOT)/ace/Set.i \ + $(WRAPPER_ROOT)/ace/Token.h \ + $(WRAPPER_ROOT)/ace/Pipe.h \ + $(WRAPPER_ROOT)/ace/Pipe.i \ + $(WRAPPER_ROOT)/ace/SOCK_Stream.h \ + $(WRAPPER_ROOT)/ace/SOCK_IO.h \ + $(WRAPPER_ROOT)/ace/SOCK_IO.i \ + $(WRAPPER_ROOT)/ace/SOCK_Stream.i \ + $(WRAPPER_ROOT)/ace/Reactor.i + +# IF YOU PUT ANYTHING HERE IT WILL GO AWAY diff --git a/examples/Reactor/Ntalker/ntalker.cpp b/examples/Reactor/Ntalker/ntalker.cpp new file mode 100644 index 00000000000..54c8e20f453 --- /dev/null +++ b/examples/Reactor/Ntalker/ntalker.cpp @@ -0,0 +1,188 @@ +// Server.C +// @(#)ntalker.cpp 1.1 10/18/96 + +// +// listens to multicast address. after first message received, will +// listen for 5 more seconds. prints Mbits/sec received from client + +#include "ace/INET_Addr.h" +#include "ace/SOCK_Dgram_Mcast.h" +#include "ace/Reactor.h" + +#if defined (ACE_HAS_IP_MULTICAST) +// network interface to subscribe to +// this is hardware specific. +// use netstat(1M) to find whether your interface +// is le0 or ie0 + +static const char *interface = "le0"; +static const char *MCAST_ADDR = ACE_DEFAULT_MULTICAST_ADDR; +static const u_short UDP_PORT = ACE_DEFAULT_MULTICAST_PORT; + +// Handle both multicast and stdin events. + +class Handle_Events : public ACE_Event_Handler +{ +public: + Handle_Events (u_short udp_port, + const char *ip_addr, + const char *interface, + ACE_Reactor &reactor); + ~Handle_Events (void); + + virtual int handle_input (ACE_HANDLE); + virtual int handle_close (ACE_HANDLE, ACE_Reactor_Mask); + +private: + ACE_SOCK_Dgram_Mcast mcast_; + ACE_Handle_Set handle_set_; +}; + +int +Handle_Events::handle_input (ACE_HANDLE h) +{ + char buf[BUFSIZ]; + + if (h == 0) + { + int readresult = ACE_OS::read (h, buf, BUFSIZ); + if (readresult > 0) + { + if (this->mcast_.send (buf, readresult) != readresult) + { + ACE_OS::perror ("send error"); + return -1; + } + return 0; + } + else if (readresult == -1) + ::perror ("can't read from STDIN"); + + return -1; + } + else + { + ACE_INET_Addr remote_addr; + + // receive message from multicast group + int retcode = this->mcast_.recv (buf, sizeof buf, remote_addr); + + if (retcode != -1) + { + cout << "received datagram from host " << remote_addr.get_host_name () + << " on port " << remote_addr.get_port_number () + << " bytes = " << retcode << endl; + ACE_OS::write (ACE_STDOUT, buf, retcode); + cout << endl; + return 0; + } + + ACE_OS::perror ("Something amiss."); + return -1; + } +} + +int +Handle_Events::handle_close (ACE_HANDLE h, ACE_Reactor_Mask) +{ + if (h == 0) + cout << "STDIN_Events handle removed from reactor." << endl << flush; + else + cout << "Mcast_Events handle removed from reactor." << endl << flush; + return 0; +} + +Handle_Events::~Handle_Events (void) +{ + // ACE_OS::exit on error (bogus)... + + if (this->mcast_.unsubscribe () == -1) + ACE_OS::perror ("unsubscribe fails"), ACE_OS::exit (1); +} + +Handle_Events::Handle_Events (u_short udp_port, + const char *ip_addr, + const char *interface, + ACE_Reactor &reactor) +{ + // Create multicast address to listen on. + + ACE_INET_Addr sockmc_addr (udp_port, ip_addr); + + // subscribe to multicast group. + + if (this->mcast_.subscribe (sockmc_addr, 1, interface) == -1) + ACE_OS::perror ("can't subscribe to multicast group"), ACE_OS::exit (1); + + // disable loopbacks + +// if (this->mcast_.set_option (IP_MULTICAST_LOOP, 0) == -1 ) +// ACE_OS::perror (" can't disable loopbacks " ), ACE_OS::exit (1); + + this->handle_set_.set_bit (0); + this->handle_set_.set_bit (this->mcast_.get_handle ()); + + // Register callbacks with the ACE_Reactor. + if (reactor.register_handler (this->handle_set_, + this, + ACE_Event_Handler::READ_MASK) == -1) + ACE_OS::perror ("can't register events"), ACE_OS::exit (1); +} + +static void +parse_args (int argc, char *argv[]) +{ + extern char *optarg; + extern int optind; + int c; + + while ((c = ACE_OS::getopt (argc, argv, "i:u")) != -1) + switch (c) + { + case 'i': + interface = optarg; + break; + case 'u': + // usage fallthrough + default: + cerr << argv[0] << " -i interface\n"; + ::exit (1); + } +} + +static sig_atomic_t done = 0; + +// Signal handler. + +static void +handler (int) +{ + done = 1; +} + +int +main (int argc, char *argv[]) +{ + ACE_Sig_Action sig ((ACE_SignalHandler) handler, SIGINT); + parse_args (argc, argv); + + ACE_Reactor reactor; + Handle_Events handle_events (UDP_PORT, MCAST_ADDR, interface, reactor); + + // main loop + + while (!done) + reactor.handle_events (); + + cout << "\ntalker Done.\n"; + return 0; +} +#else +int +main (int argc, char *argv[]) +{ + ACE_ERROR ((LM_ERROR, "error: %s must be run on a platform that support IP multicast\n", + argv[0])); + return 0; +} +#endif /* ACE_HAS_IP_MULTICAST */ diff --git a/examples/Reactor/README b/examples/Reactor/README new file mode 100644 index 00000000000..fefaeeaf317 --- /dev/null +++ b/examples/Reactor/README @@ -0,0 +1,20 @@ +This directory contains subdirectories that test the ACE Reactor and Proactor + + . Dgram + Tests the CODgram and Dgram classes with the Reactor. + + . Misc + Various miscellaneous tests of Reactor functionality + (e.g., signals, timers, notification, etc.). + + . Multicast + Tests out the ACE multicast capabilities in conjunction + with the Reactor. + + . Ntalker + A program that implements a multicast "chat" program. + + + . Proactor + A program that illustrates the "Proactive" version of + the Reactor diff --git a/examples/Reactor/ReactorEx/README b/examples/Reactor/ReactorEx/README new file mode 100644 index 00000000000..1184d09dd68 --- /dev/null +++ b/examples/Reactor/ReactorEx/README @@ -0,0 +1,204 @@ +The ACE_ReactorEx encapsulates the Win32 WaitForMultipleObjects() API +within ACE. The ACE_ReactorEx is similar in spirit to the +ACE_Reactor, except that (1) it is much simpler and (2) it works for +the complete range of Win32 handles (whereas the ACE_Reactor just +works for socket handles. + +Here's the API for the ACE_ReactorEx: + +class ACE_ReactorEx +{ +public: + // = Event loop. + virtual int handle_events (ACE_Time_Value *); + + // = Handler registration management. + virtual int register_handler (ACE_Event_Handler *); + virtual int remove_handler (ACE_Event_Handler *); + + virtual int notify (void); + + // = Timer management + virtual int schedule_timer (), etc. + // ... +}; + +---------------------------------------- + +Here's how you might use it: + +---------------------------------------- + +class My_Thread_Handler : public ACE_Event_Handler +{ +public: + My_Thread_Handler (void) { + // Create a thread that will run + // for a time and then exit. + this->thread_handle_ = + ACE_OS::thr_create (run, ......); + } + + // Called back by the ACE_ReactorEx when the + // event is signaled. + virtual int handle_signal (int) + { + cout << "thread is done" << endl; + } + + virtual ACE_HANDLE get_handle (void) const + { + return this->thread_handle_; + } + +private: + ACE_HANDLE thread_handle_; + + static void *run (void *) { + // Sleep for a while and then exit. + ACE_OS::sleep (100000); + return 0; + } +}; + +---------------------------------------- + +The main program might look something like this: + +---------------------------------------- + +int main (void) +{ + // ... + ACE_ReactorEx dispatcher; + My_Thread_Handler handler; + + // Register the thread handler. + dispatcher.register_handler (&handler); + + // Block until the thread exits and the + // handle_signal() method of the My_Thread_Handler + // is called! + dispatcher.handle_events (); + + // ... +} + +---------------------------------------- + +. test_remove_handler -- + +This application tests the ReactorEx's ability to handle simultaneous +events. If you pass anything on the command-line, then each handler +requests to be removed from the ReactorEx after each event. This has +a funky effect on the order in which handlers are serviced. So, if no +parameters are passed in, the handlers should be serviced 1 through +MAXIMUM_WAIT_OBJECTS. If handlers to request to be removed as signals +occur, they will be serviced 1, MAX, MAX-1, ..., 2. This is because +of a ReactorEx bookkeeping optimization. + +. test_reactorEx.cpp -- + +This test application tests a wide range of events that can be +demultiplexed using various ACE utilities. Events used include ^C +events, reading from STDIN, vanilla Win32 events, thread exits, +ReactorEx notifications, proactive reads, and proactive writes. + +The proactive I/O events are demultiplexed by the ACE_Proactor. The +thread exits, notications, and vanilla Win32 events are demultiplexed +by the ACE_ReactorEx. To enable a single thread to run all these +events, the Proactor is integrated with the ReactorEx. + +The test application prototypes a simple ntalk program. Two instances +of the application connect. Input from either console is displayed on +the others console also. Because of the evils of Win32 STDIN, a +separate thread is used to read from STDIN. To test the Proactor and +ReactorEx, I/O between the remote processes is performed proactively +and interactions between the STDIN thread and the main thread are +performed reactively. + +The following description of the test application is in two parts. +The participants section explains the main components involved in the +application. The collaboration section describes how the partipants +interact in response to the multiple event types which occur. + +The ReactorEx test application has the following participants: + +. ReactorEx -- The ReactorEx demultiplexes Win32 "waitable" events + using WaitForMultipleObjects. + +. Proactor -- The proactor initiates and demultiplexes overlapped I/O + operations. The Proactor registers with the ReactorEx so that a + single-thread can demultiplex all application events. + +. STDIN_Handler -- STDIN_Handler is an Active Object which reads from + STDIN and forwards the input to the Peer_Handler. This runs + in a separate thread to make the test more interesting. However, + STDIN is "waitable", so in general it can be waited on by the ACE + ReactorEx, thanks MicroSlush! + +. Peer_Handler -- The Peer_Handler connects to another instance of + test_reactorEx. It Proactively reads and writes data to the peer. + When the STDIN_Handler gives it messages, it fowards them to the + remote peer. When it receives messages from the remote peer, it + prints the output to the console. + +The collaborations of the participants are as follows: + +. Initialization + + Peer_Handler -- connects to the remote peer. It then begins + proactively reading from the remote connection. Note that it will + be notified by the Proactor when a read completes. It also + registers a new_msg_event with the ReactorEx. Note that when the + new_msg_event is signaled (by the STDIN_Handler), + Peer_Handler::handle_signal will get called. + + STDIN_Handler -- STDIN_Handler registers a signal handler for + SIGINT. This just captures the exception so that the kernel doesn't + kill our process; We want to exit gracefully. It also creates an + Exit_Hook object which registers the STDIN_Handler's thread handle + with the ReactorEx. The Exit_Hook will get called back when the + STDIN_Handler thread exits. After registering these, it blocks + reading from STDIN. + + Proactor -- is registered with the ReactorEx. + + The main thread of control waits in the ReactorEx. + +. STDIN events -- When the STDIN_Handler thread reads from STDIN, it + puts the message on Peer_Handler's message queue and signals the + new_msg_event. It then returns to reading from STDIN. + +. new_msg_events -- The ReactorEx thread wakes up and calls + Peer_Handler::handle_signal. The Peer_Handler then tries to dequeue + a message from its message queue. If it can, the message is + Proactively sent to the remote peer. Note that the Peer_Handler + will be notified with this operation is complete. The Peer_Handler + then falls back into the ReactorEx event loop. + +. Send complete event -- When a proactive send is complete, the + Proactor is notified by the ReactorEx. The Proactor, in turn, + notifies the Peer_Handler. The Peer_Handler then checks for more + messages from the message queue. If there are any, it tries to send + them. If there are not, it returns to the ReactorEx event loop. + This is ok since it is notified via new_msg_event when new message + arrive. + +. Read complete event -- When a proactive read is complete (the + Peer_Handler initiated a proactive read when it connected to the + remote peer), the Proactor is notified by the ReactorEx. The + Proactor, in turn notifies the Peer_Handler. If the read was + successful the Peer_Handler just displays the received msg to the + console and reinvokes a proactive read from the network connection. + If the read failed (i.e. the remote peer exited), the Peer_Handler + sets a flag to end the event loop and returns. This will cause the + application to exit. + +. ^C events -- When the user types ^C at the console, the + STDIN_Handler's signal handler will be called. It does nothing, but + as a result of the signal, the STDIN_Handler thread will exit. + +. STDIN_Handler thread exits -- The Exit_Hook will get called back + from the ReactorEx. Exit_Hook::handle_signal sets a flag to end the + event loop and returns. This will cause the application to exit. diff --git a/examples/Reactor/ReactorEx/reactorex.mak b/examples/Reactor/ReactorEx/reactorex.mak new file mode 100644 index 00000000000..150d04508d7 --- /dev/null +++ b/examples/Reactor/ReactorEx/reactorex.mak @@ -0,0 +1,535 @@ +# Microsoft Developer Studio Generated NMAKE File, Format Version 4.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+!IF "$(CFG)" == ""
+CFG=test_remove_handler - Win32 Debug
+!MESSAGE No configuration specified. Defaulting to test_remove_handler - Win32\
+ Debug.
+!ENDIF
+
+!IF "$(CFG)" != "ntalk - Win32 Release" && "$(CFG)" != "ntalk - Win32 Debug" &&\
+ "$(CFG)" != "test_remove_handler - Win32 Release" && "$(CFG)" !=\
+ "test_remove_handler - Win32 Debug"
+!MESSAGE Invalid configuration "$(CFG)" specified.
+!MESSAGE You can specify a configuration when running NMAKE on this makefile
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "reactorEx.mak" CFG="test_remove_handler - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "ntalk - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "ntalk - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE "test_remove_handler - Win32 Release" (based on\
+ "Win32 (x86) Console Application")
+!MESSAGE "test_remove_handler - Win32 Debug" (based on\
+ "Win32 (x86) Console Application")
+!MESSAGE
+!ERROR An invalid configuration is specified.
+!ENDIF
+
+!IF "$(OS)" == "Windows_NT"
+NULL=
+!ELSE
+NULL=nul
+!ENDIF
+################################################################################
+# Begin Project
+# PROP Target_Last_Scanned "ntalk - Win32 Debug"
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "ntalk - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "ntalk\Release"
+# PROP BASE Intermediate_Dir "ntalk\Release"
+# PROP BASE Target_Dir "ntalk"
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "ntalk\Release"
+# PROP Intermediate_Dir "ntalk\Release"
+# PROP Target_Dir "ntalk"
+OUTDIR=.\ntalk\Release
+INTDIR=.\ntalk\Release
+
+ALL : "$(OUTDIR)\ntalk.exe"
+
+CLEAN :
+ -@erase ".\ntalk\Release\ntalk.exe"
+ -@erase ".\ntalk\Release\test_reactorEx.obj"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c
+# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c
+CPP_PROJ=/nologo /ML /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE"\
+ /Fp"$(INTDIR)/ntalk.pch" /YX /Fo"$(INTDIR)/" /c
+CPP_OBJS=.\ntalk\Release/
+CPP_SBRS=
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+BSC32_FLAGS=/nologo /o"$(OUTDIR)/ntalk.bsc"
+BSC32_SBRS=
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib ace.lib /nologo /subsystem:console /machine:I386
+LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
+ advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\
+ odbccp32.lib ace.lib /nologo /subsystem:console /incremental:no\
+ /pdb:"$(OUTDIR)/ntalk.pdb" /machine:I386 /out:"$(OUTDIR)/ntalk.exe"
+LINK32_OBJS= \
+ "$(INTDIR)/test_reactorEx.obj"
+
+"$(OUTDIR)\ntalk.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+!ELSEIF "$(CFG)" == "ntalk - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "ntalk\Debug"
+# PROP BASE Intermediate_Dir "ntalk\Debug"
+# PROP BASE Target_Dir "ntalk"
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir ""
+# PROP Intermediate_Dir "debug"
+# PROP Target_Dir "ntalk"
+OUTDIR=.
+INTDIR=.\debug
+
+ALL : "$(OUTDIR)\test_reactorEx.exe"
+
+CLEAN :
+ -@erase ".\debug\vc40.pdb"
+ -@erase ".\debug\vc40.idb"
+ -@erase ".\test_reactorEx.exe"
+ -@erase ".\debug\test_reactorEx.obj"
+ -@erase ".\test_reactorEx.ilk"
+ -@erase ".\test_reactorEx.pdb"
+
+"$(INTDIR)" :
+ if not exist "$(INTDIR)/$(NULL)" mkdir "$(INTDIR)"
+
+# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /YX /c
+# ADD CPP /nologo /MDd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /YX /c
+CPP_PROJ=/nologo /MDd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE"\
+ /Fp"$(INTDIR)/ntalk.pch" /YX /Fo"$(INTDIR)/" /Fd"$(INTDIR)/" /c
+CPP_OBJS=.\debug/
+CPP_SBRS=
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+BSC32_FLAGS=/nologo /o"$(OUTDIR)/ntalk.bsc"
+BSC32_SBRS=
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib ace.lib /nologo /subsystem:console /debug /machine:I386 /out:"test_reactorEx.exe"
+LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
+ advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\
+ odbccp32.lib ace.lib /nologo /subsystem:console /incremental:yes\
+ /pdb:"$(OUTDIR)/test_reactorEx.pdb" /debug /machine:I386\
+ /out:"$(OUTDIR)/test_reactorEx.exe"
+LINK32_OBJS= \
+ "$(INTDIR)/test_reactorEx.obj"
+
+"$(OUTDIR)\test_reactorEx.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+!ELSEIF "$(CFG)" == "test_remove_handler - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "test_remove_handler\Release"
+# PROP BASE Intermediate_Dir "test_remove_handler\Release"
+# PROP BASE Target_Dir "test_remove_handler"
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "test_remove_handler\Release"
+# PROP Intermediate_Dir "test_remove_handler\Release"
+# PROP Target_Dir "test_remove_handler"
+OUTDIR=.\test_remove_handler\Release
+INTDIR=.\test_remove_handler\Release
+
+ALL : "$(OUTDIR)\test_remove_handler.exe"
+
+CLEAN :
+ -@erase ".\test_remove_handler\Release\test_remove_handler.exe"
+ -@erase ".\test_remove_handler\Release\test_remove_handler.obj"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c
+# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c
+CPP_PROJ=/nologo /ML /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE"\
+ /Fp"$(INTDIR)/test_remove_handler.pch" /YX /Fo"$(INTDIR)/" /c
+CPP_OBJS=.\test_remove_handler\Release/
+CPP_SBRS=
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+BSC32_FLAGS=/nologo /o"$(OUTDIR)/test_remove_handler.bsc"
+BSC32_SBRS=
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
+ advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\
+ odbccp32.lib /nologo /subsystem:console /incremental:no\
+ /pdb:"$(OUTDIR)/test_remove_handler.pdb" /machine:I386\
+ /out:"$(OUTDIR)/test_remove_handler.exe"
+LINK32_OBJS= \
+ "$(INTDIR)/test_remove_handler.obj"
+
+"$(OUTDIR)\test_remove_handler.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+!ELSEIF "$(CFG)" == "test_remove_handler - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "test_remove_handler\Debug"
+# PROP BASE Intermediate_Dir "test_remove_handler\Debug"
+# PROP BASE Target_Dir "test_remove_handler"
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir ""
+# PROP Intermediate_Dir "Debug"
+# PROP Target_Dir "test_remove_handler"
+OUTDIR=.
+INTDIR=.\Debug
+
+ALL : "$(OUTDIR)\test_remove_handler.exe"
+
+CLEAN :
+ -@erase ".\debug\vc40.pdb"
+ -@erase ".\debug\vc40.idb"
+ -@erase ".\test_remove_handler.exe"
+ -@erase ".\Debug\test_remove_handler.obj"
+ -@erase ".\test_remove_handler.ilk"
+ -@erase ".\test_remove_handler.pdb"
+
+"$(INTDIR)" :
+ if not exist "$(INTDIR)/$(NULL)" mkdir "$(INTDIR)"
+
+# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /YX /c
+# ADD CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /YX /c
+CPP_PROJ=/nologo /MLd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE"\
+ /Fp"$(INTDIR)/test_remove_handler.pch" /YX /Fo"$(INTDIR)/" /Fd"$(INTDIR)/" /c
+CPP_OBJS=.\Debug/
+CPP_SBRS=
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+BSC32_FLAGS=/nologo /o"$(OUTDIR)/test_remove_handler.bsc"
+BSC32_SBRS=
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib ace.lib /nologo /subsystem:console /debug /machine:I386
+LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
+ advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\
+ odbccp32.lib ace.lib /nologo /subsystem:console /incremental:yes\
+ /pdb:"$(OUTDIR)/test_remove_handler.pdb" /debug /machine:I386\
+ /out:"$(OUTDIR)/test_remove_handler.exe"
+LINK32_OBJS= \
+ "$(INTDIR)/test_remove_handler.obj"
+
+"$(OUTDIR)\test_remove_handler.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+!ENDIF
+
+.c{$(CPP_OBJS)}.obj:
+ $(CPP) $(CPP_PROJ) $<
+
+.cpp{$(CPP_OBJS)}.obj:
+ $(CPP) $(CPP_PROJ) $<
+
+.cxx{$(CPP_OBJS)}.obj:
+ $(CPP) $(CPP_PROJ) $<
+
+.c{$(CPP_SBRS)}.sbr:
+ $(CPP) $(CPP_PROJ) $<
+
+.cpp{$(CPP_SBRS)}.sbr:
+ $(CPP) $(CPP_PROJ) $<
+
+.cxx{$(CPP_SBRS)}.sbr:
+ $(CPP) $(CPP_PROJ) $<
+
+################################################################################
+# Begin Target
+
+# Name "ntalk - Win32 Release"
+# Name "ntalk - Win32 Debug"
+
+!IF "$(CFG)" == "ntalk - Win32 Release"
+
+!ELSEIF "$(CFG)" == "ntalk - Win32 Debug"
+
+!ENDIF
+
+################################################################################
+# Begin Source File
+
+SOURCE=.\test_reactorEx.cpp
+DEP_CPP_TEST_=\
+ {$(INCLUDE)}"\ace\ReactorEx.h"\
+ {$(INCLUDE)}"\ace\Proactor.h"\
+ {$(INCLUDE)}"\ace\SOCK_Connector.h"\
+ {$(INCLUDE)}"\ace\SOCK_Acceptor.h"\
+ {$(INCLUDE)}"\ace\Get_Opt.h"\
+ {$(INCLUDE)}"\ace\Time_Value.h"\
+ {$(INCLUDE)}"\ace\Service_Config.h"\
+ {$(INCLUDE)}"\ace\Synch.h"\
+ {$(INCLUDE)}"\ace\Task.h"\
+ {$(INCLUDE)}"\ace\OS.h"\
+ {$(INCLUDE)}"\ace\Timer_Queue.h"\
+ {$(INCLUDE)}"\ace\Event_Handler.h"\
+ {$(INCLUDE)}"\ace\Token.h"\
+ {$(INCLUDE)}"\ace\Local_Tokens.h"\
+ {$(INCLUDE)}"\ace\ReactorEx.i"\
+ {$(INCLUDE)}"\ace\Timer_Queue.i"\
+ {$(INCLUDE)}"\ace\ACE.h"\
+ {$(INCLUDE)}"\ace\Event_Handler.i"\
+ {$(INCLUDE)}"\ace\ACE.i"\
+ {$(INCLUDE)}"\ace\Log_Msg.h"\
+ {$(INCLUDE)}"\ace\Log_Record.h"\
+ {$(INCLUDE)}"\ace\Log_Priority.h"\
+ {$(INCLUDE)}"\ace\Log_Record.i"\
+ {$(INCLUDE)}"\ace\Token.i"\
+ {$(INCLUDE)}"\ace\Stack.h"\
+ {$(INCLUDE)}"\ace\Synch_Options.h"\
+ {$(INCLUDE)}"\ace\Map_Manager.h"\
+ {$(INCLUDE)}"\ace\Local_Tokens.i"\
+ {$(INCLUDE)}"\ace\Stack.i"\
+ {$(INCLUDE)}"\ace\Stack.cpp"\
+ {$(INCLUDE)}"\ace\Map_Manager.i"\
+ {$(INCLUDE)}"\ace\Map_Manager.cpp"\
+ {$(INCLUDE)}"\ace\Malloc.h"\
+ {$(INCLUDE)}"\ace\SV_Semaphore_Simple.h"\
+ {$(INCLUDE)}"\ace\Malloc.i"\
+ {$(INCLUDE)}"\ace\Malloc_T.h"\
+ {$(INCLUDE)}"\ace\Memory_Pool.h"\
+ {$(INCLUDE)}"\ace\SV_Semaphore_Simple.i"\
+ {$(INCLUDE)}"\ace\Trace.h"\
+ {$(INCLUDE)}"\ace\Malloc_T.i"\
+ {$(INCLUDE)}"\ace\Malloc_T.cpp"\
+ {$(INCLUDE)}"\ace\Signal.h"\
+ {$(INCLUDE)}"\ace\Mem_Map.h"\
+ {$(INCLUDE)}"\ace\SV_Semaphore_Complex.h"\
+ {$(INCLUDE)}"\ace\Memory_Pool.i"\
+ {$(INCLUDE)}"\ace\Set.h"\
+ {$(INCLUDE)}"\ace\Signal.i"\
+ {$(INCLUDE)}"\ace\Set.i"\
+ {$(INCLUDE)}"\ace\Set.cpp"\
+ {$(INCLUDE)}"\ace\Mem_Map.i"\
+ {$(INCLUDE)}"\ace\SV_Semaphore_Complex.i"\
+ {$(INCLUDE)}"\ace\Message_Block.h"\
+ {$(INCLUDE)}"\ace\Proactor.i"\
+ {$(INCLUDE)}"\ace\Message_Block.i"\
+ {$(INCLUDE)}"\ace\SOCK_Stream.h"\
+ {$(INCLUDE)}"\ace\SOCK_Connector.i"\
+ {$(INCLUDE)}"\ace\SOCK_IO.h"\
+ {$(INCLUDE)}"\ace\INET_Addr.h"\
+ {$(INCLUDE)}"\ace\SOCK_Stream.i"\
+ {$(INCLUDE)}"\ace\SOCK.h"\
+ {$(INCLUDE)}"\ace\SOCK_IO.i"\
+ {$(INCLUDE)}"\ace\Addr.h"\
+ {$(INCLUDE)}"\ace\IPC_SAP.h"\
+ {$(INCLUDE)}"\ace\SOCK.i"\
+ {$(INCLUDE)}"\ace\Addr.i"\
+ {$(INCLUDE)}"\ace\IPC_SAP.i"\
+ {$(INCLUDE)}"\ace\INET_Addr.i"\
+ {$(INCLUDE)}"\ace\SOCK_Acceptor.i"\
+ {$(INCLUDE)}"\ace\Get_Opt.i"\
+ {$(INCLUDE)}"\ace\config.h"\
+ {$(INCLUDE)}"\ace\Time_Value.i"\
+ {$(INCLUDE)}"\ace\Service_Object.h"\
+ {$(INCLUDE)}"\ace\Thread_Manager.h"\
+ {$(INCLUDE)}"\ace\Service_Config.i"\
+ {$(INCLUDE)}"\ace\Reactor.h"\
+ {$(INCLUDE)}"\ace\Svc_Conf_Tokens.h"\
+ {$(INCLUDE)}"\ace\Shared_Object.h"\
+ {$(INCLUDE)}"\ace\Service_Object.i"\
+ {$(INCLUDE)}"\ace\Shared_Object.i"\
+ {$(INCLUDE)}"\ace\Thread.h"\
+ {$(INCLUDE)}"\ace\Thread_Manager.i"\
+ {$(INCLUDE)}"\ace\Thread.i"\
+ {$(INCLUDE)}"\ace\Handle_Set.h"\
+ {$(INCLUDE)}"\ace\Pipe.h"\
+ {$(INCLUDE)}"\ace\Reactor.i"\
+ {$(INCLUDE)}"\ace\Handle_Set.i"\
+ {$(INCLUDE)}"\ace\Pipe.i"\
+ {$(INCLUDE)}"\ace\Synch.i"\
+ {$(INCLUDE)}"\ace\Synch_T.h"\
+ {$(INCLUDE)}"\ace\Synch_T.i"\
+ {$(INCLUDE)}"\ace\Synch_T.cpp"\
+ {$(INCLUDE)}"\ace\Message_Queue.h"\
+ {$(INCLUDE)}"\ace\Task.i"\
+ {$(INCLUDE)}"\ace\Task.cpp"\
+ {$(INCLUDE)}"\ace\IO_Cntl_Msg.h"\
+ {$(INCLUDE)}"\ace\Message_Queue.i"\
+ {$(INCLUDE)}"\ace\Message_Queue.cpp"\
+ {$(INCLUDE)}"\ace\Module.h"\
+ {$(INCLUDE)}"\ace\Module.i"\
+ {$(INCLUDE)}"\ace\Module.cpp"\
+ {$(INCLUDE)}"\ace\Stream_Modules.h"\
+ {$(INCLUDE)}"\ace\Stream_Modules.i"\
+ {$(INCLUDE)}"\ace\Stream_Modules.cpp"\
+ {$(INCLUDE)}"\sys\TYPES.H"\
+ {$(INCLUDE)}"\sys\STAT.H"\
+ {$(INCLUDE)}"\sys\TIMEB.H"\
+ {$(INCLUDE)}"\ace\OS.i"\
+
+NODEP_CPP_TEST_=\
+ ".\..\..\ace\ace\Sync_T.h"\
+ ".\..\..\ace\semLib.h"\
+
+
+"$(INTDIR)\test_reactorEx.obj" : $(SOURCE) $(DEP_CPP_TEST_) "$(INTDIR)"
+
+
+# End Source File
+# End Target
+################################################################################
+# Begin Target
+
+# Name "test_remove_handler - Win32 Release"
+# Name "test_remove_handler - Win32 Debug"
+
+!IF "$(CFG)" == "test_remove_handler - Win32 Release"
+
+!ELSEIF "$(CFG)" == "test_remove_handler - Win32 Debug"
+
+!ENDIF
+
+################################################################################
+# Begin Source File
+
+SOURCE=.\test_remove_handler.cpp
+DEP_CPP_TEST_R=\
+ {$(INCLUDE)}"\ace\ReactorEx.h"\
+ {$(INCLUDE)}"\ace\Service_Config.h"\
+ {$(INCLUDE)}"\ace\Synch.h"\
+ {$(INCLUDE)}"\ace\Timer_Queue.h"\
+ {$(INCLUDE)}"\ace\Time_Value.h"\
+ {$(INCLUDE)}"\ace\Event_Handler.h"\
+ {$(INCLUDE)}"\ace\Token.h"\
+ {$(INCLUDE)}"\ace\Local_Tokens.h"\
+ {$(INCLUDE)}"\ace\ReactorEx.i"\
+ {$(INCLUDE)}"\ace\Timer_Queue.i"\
+ {$(INCLUDE)}"\ace\config.h"\
+ {$(INCLUDE)}"\ace\Time_Value.i"\
+ {$(INCLUDE)}"\ace\Trace.h"\
+ {$(INCLUDE)}"\ace\ACE.h"\
+ {$(INCLUDE)}"\ace\Event_Handler.i"\
+ {$(INCLUDE)}"\ace\OS.h"\
+ {$(INCLUDE)}"\ace\ACE.i"\
+ {$(INCLUDE)}"\sys\TYPES.H"\
+ {$(INCLUDE)}"\sys\STAT.H"\
+ {$(INCLUDE)}"\sys\TIMEB.H"\
+ {$(INCLUDE)}"\ace\OS.i"\
+ {$(INCLUDE)}"\ace\Log_Msg.h"\
+ {$(INCLUDE)}"\ace\Log_Record.h"\
+ {$(INCLUDE)}"\ace\Log_Priority.h"\
+ {$(INCLUDE)}"\ace\Log_Record.i"\
+ {$(INCLUDE)}"\ace\Token.i"\
+ {$(INCLUDE)}"\ace\Stack.h"\
+ {$(INCLUDE)}"\ace\Synch_Options.h"\
+ {$(INCLUDE)}"\ace\Map_Manager.h"\
+ {$(INCLUDE)}"\ace\Local_Tokens.i"\
+ {$(INCLUDE)}"\ace\Stack.i"\
+ {$(INCLUDE)}"\ace\Stack.cpp"\
+ {$(INCLUDE)}"\ace\Map_Manager.i"\
+ {$(INCLUDE)}"\ace\Map_Manager.cpp"\
+ {$(INCLUDE)}"\ace\Malloc.h"\
+ {$(INCLUDE)}"\ace\SV_Semaphore_Simple.h"\
+ {$(INCLUDE)}"\ace\Malloc.i"\
+ {$(INCLUDE)}"\ace\Malloc_T.h"\
+ {$(INCLUDE)}"\ace\Memory_Pool.h"\
+ {$(INCLUDE)}"\ace\SV_Semaphore_Simple.i"\
+ {$(INCLUDE)}"\ace\Malloc_T.i"\
+ {$(INCLUDE)}"\ace\Malloc_T.cpp"\
+ {$(INCLUDE)}"\ace\Signal.h"\
+ {$(INCLUDE)}"\ace\Mem_Map.h"\
+ {$(INCLUDE)}"\ace\SV_Semaphore_Complex.h"\
+ {$(INCLUDE)}"\ace\Memory_Pool.i"\
+ {$(INCLUDE)}"\ace\Set.h"\
+ {$(INCLUDE)}"\ace\Signal.i"\
+ {$(INCLUDE)}"\ace\Set.i"\
+ {$(INCLUDE)}"\ace\Set.cpp"\
+ {$(INCLUDE)}"\ace\Mem_Map.i"\
+ {$(INCLUDE)}"\ace\SV_Semaphore_Complex.i"\
+ {$(INCLUDE)}"\ace\Service_Object.h"\
+ {$(INCLUDE)}"\ace\Thread_Manager.h"\
+ {$(INCLUDE)}"\ace\Proactor.h"\
+ {$(INCLUDE)}"\ace\Service_Config.i"\
+ {$(INCLUDE)}"\ace\Reactor.h"\
+ {$(INCLUDE)}"\ace\Svc_Conf_Tokens.h"\
+ {$(INCLUDE)}"\ace\Shared_Object.h"\
+ {$(INCLUDE)}"\ace\Service_Object.i"\
+ {$(INCLUDE)}"\ace\Shared_Object.i"\
+ {$(INCLUDE)}"\ace\Thread.h"\
+ {$(INCLUDE)}"\ace\Thread_Manager.i"\
+ {$(INCLUDE)}"\ace\Thread.i"\
+ {$(INCLUDE)}"\ace\Message_Block.h"\
+ {$(INCLUDE)}"\ace\Proactor.i"\
+ {$(INCLUDE)}"\ace\Message_Block.i"\
+ {$(INCLUDE)}"\ace\Handle_Set.h"\
+ {$(INCLUDE)}"\ace\Pipe.h"\
+ {$(INCLUDE)}"\ace\SOCK_Stream.h"\
+ {$(INCLUDE)}"\ace\Reactor.i"\
+ {$(INCLUDE)}"\ace\Handle_Set.i"\
+ {$(INCLUDE)}"\ace\Pipe.i"\
+ {$(INCLUDE)}"\ace\SOCK_IO.h"\
+ {$(INCLUDE)}"\ace\INET_Addr.h"\
+ {$(INCLUDE)}"\ace\SOCK_Stream.i"\
+ {$(INCLUDE)}"\ace\SOCK.h"\
+ {$(INCLUDE)}"\ace\SOCK_IO.i"\
+ {$(INCLUDE)}"\ace\Addr.h"\
+ {$(INCLUDE)}"\ace\IPC_SAP.h"\
+ {$(INCLUDE)}"\ace\SOCK.i"\
+ {$(INCLUDE)}"\ace\Addr.i"\
+ {$(INCLUDE)}"\ace\IPC_SAP.i"\
+ {$(INCLUDE)}"\ace\INET_Addr.i"\
+ {$(INCLUDE)}"\ace\Synch.i"\
+ {$(INCLUDE)}"\ace\Synch_T.h"\
+ {$(INCLUDE)}"\ace\Synch_T.i"\
+ {$(INCLUDE)}"\ace\Synch_T.cpp"\
+
+NODEP_CPP_TEST_R=\
+ ".\..\..\ace\semLib.h"\
+ ".\..\..\ace\ace\Sync_T.h"\
+
+
+"$(INTDIR)\test_remove_handler.obj" : $(SOURCE) $(DEP_CPP_TEST_R) "$(INTDIR)"
+
+
+# End Source File
+# End Target
+# End Project
+################################################################################
diff --git a/examples/Reactor/ReactorEx/reactorex.mdp b/examples/Reactor/ReactorEx/reactorex.mdp Binary files differnew file mode 100644 index 00000000000..0135cc67b75 --- /dev/null +++ b/examples/Reactor/ReactorEx/reactorex.mdp diff --git a/examples/Reactor/ReactorEx/test_reactorEx.cpp b/examples/Reactor/ReactorEx/test_reactorEx.cpp new file mode 100644 index 00000000000..757e78c1e9e --- /dev/null +++ b/examples/Reactor/ReactorEx/test_reactorEx.cpp @@ -0,0 +1,444 @@ +// ============================================================================ +// @(#)test_reactorEx.cpp 1.1 10/18/96 + +// +// = LIBRARY +// examples +// +// = FILENAME +// test_reactorEx.cpp +// +// = DESCRIPTION +// This test application tests a wide range of events that can be +// demultiplexed using various ACE utilities. Events used include ^C +// events, reading from STDIN, vanilla Win32 events, thread exits, +// ReactorEx notifications, proactive reads, and proactive writes. +// +// The proactive I/O events are demultiplexed by the ACE_Proactor. +// The thread exits, notications, and vanilla Win32 events are +// demultiplexed by the ACE_ReactorEx. To enable a single thread +// to run all these events, the Proactor is integrated with the +// ReactorEx. +// +// = AUTHOR +// Tim Harrison +// +// ============================================================================ + +#include "ace/ReactorEx.h" +#include "ace/Proactor.h" +#include "ace/SOCK_Connector.h" +#include "ace/SOCK_Acceptor.h" +#include "ace/Get_Opt.h" +#include "ace/Time_Value.h" +#include "ace/Service_Config.h" +#include "ace/Synch.h" +#include "ace/Task.h" +#include "ace/OS.h" + +typedef ACE_Task<ACE_MT_SYNCH> MT_TASK; + +class Peer_Handler : public MT_TASK + // = TITLE + // Connect to a server. Receive messages from STDIN_Handler + // and forward them to the server using proactive I/O. +{ +public: + Peer_Handler (int argc, char *argv[]); + + int open (void * =0); + // This method creates the network connection to the remote peer. + // It does blocking connects and accepts depending on whether a + // hostname was specified from the command line. + + virtual int handle_output_complete (ACE_Message_Block *msg, + long bytes_transfered); + // One of our asynchronous writes to the remote peer has completed. + // Make sure it succeeded and then delete the message. + + virtual int handle_input_complete (ACE_Message_Block *msg, + long bytes_transfered); + // The remote peer has sent us something. If it succeeded, print + // out the message and reinitiate a read. Otherwise, fail. In both + // cases, delete the message sent. + + virtual ACE_Message_Block *get_message (void); + // This is so the Proactor can get a message to read into. + + virtual ACE_HANDLE get_handle (void) const; + // This is so the Proactor can get our handle. + + virtual int handle_close (ACE_HANDLE, ACE_Reactor_Mask); + // We've been removed from the ReactorEx. + + virtual int handle_signal (int index, siginfo_t *, ucontext_t *); + // We've been signaled by the STDIN thread. Try to dequeue a + // message. + + void try_send (void); + // Try to dequeue a message. If successful, send it proactively to + // the remote peer. + + virtual int put (ACE_Message_Block *mb, + ACE_Time_Value *tv = 0); + // Enqueue the new mb and signal the main thread. + +private: + ACE_SOCK_Stream stream_; + // Socket that we have connected to the server. + + ACE_HANDLE new_msg_event_; + // Event that gets signaled when messages arrive. + + // = Remote peer info. + char *host_; + // Name of remote host. + + u_short port_; + // Port number for remote host. + + // = Make Task happy. + int close (u_long) { return 0; } +}; + +class STDIN_Handler : public ACE_Task<ACE_NULL_SYNCH> + // = TITLE + // Active Object. Reads from STDIN and passes message blocks to + // the peer handler. +{ +public: + STDIN_Handler (MT_TASK &ph); + + virtual int open (void * = 0); + // Activate object. + + virtual int close (u_long = 0); + // Shut down. + + int svc (void); + // Thread runs here. + +private: + MT_TASK &ph_; + // Send all input to ph_. + + static void handler (int signum); + // Handle a ^C. (Do nothing). + + int put (ACE_Message_Block *, ACE_Time_Value *) { return 0; } + // Make Task happy. + + void register_thread_exit_hook (void); + // Helper function to register with the ReactorEx for thread exit. + + virtual int handle_signal (int index, siginfo_t *, ucontext_t *); + // The STDIN thread has exited. This means the user hit ^C. We can + // end the event loop. +}; + +Peer_Handler::Peer_Handler (int argc, char *argv[]) + : host_ (0), + port_ (ACE_DEFAULT_SERVER_PORT) +{ + ACE_Get_Opt get_opt (argc, argv, "h:p:"); + int c; + + while ((c = get_opt ()) != EOF) + { + switch (c) + { + case 'h': + host_ = get_opt.optarg; + break; + case 'p': + port_ = ACE_OS::atoi (get_opt.optarg); + break; + } + } + + // Auto reset event. + new_msg_event_ = ::CreateEvent (NULL, FALSE, FALSE, NULL); + ACE_Service_Config::reactorEx ()-> + register_handler (this, new_msg_event_); +} + +// This method creates the network connection to the remote peer. It +// does blocking connects and accepts depending on whether a hostname +// was specified from the command line. + +int +Peer_Handler::open (void *) +{ + if (host_ != 0) // Connector + { + ACE_INET_Addr addr (port_, host_); + ACE_SOCK_Connector connector; + + // Establish connection with server. + if (connector.connect (stream_, addr) == -1) + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "connect"), -1); + + ACE_DEBUG ((LM_DEBUG, "connected.\n")); + } + else // Acceptor + { + ACE_SOCK_Acceptor acceptor; + ACE_INET_Addr local_addr (port_); + + if ((acceptor.open (local_addr) == -1) || + (acceptor.accept (this->stream_) == -1)) + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "accept failed"), -1); + + ACE_DEBUG ((LM_DEBUG, "accepted.\n")); + } + + return ACE_Service_Config::proactor ()->initiate + (this, ACE_Event_Handler::READ_MASK); +} + +// One of our asynchronous writes to the remote peer has completed. +// Make sure it succeeded and then delete the message. + +int +Peer_Handler::handle_output_complete (ACE_Message_Block *msg, + long bytes_transfered) +{ + if (bytes_transfered <= 0) + ACE_DEBUG ((LM_DEBUG, "%p bytes = %d\n", "Message failed", + bytes_transfered)); + + // This was allocated by the STDIN_Handler, queued, dequeued, + // passed to the proactor, and now passed back to us. + delete msg; + return 0; // Do not reinvoke a send. +} + +// The remote peer has sent us something. If it succeeded, print +// out the message and reinitiate a read. Otherwise, fail. In both +// cases, delete the message sent. + +int +Peer_Handler::handle_input_complete (ACE_Message_Block *msg, + long bytes_transfered) +{ + if ((bytes_transfered > 0) && (msg->length () > 0)) + { + msg->rd_ptr ()[bytes_transfered] = '\0'; + // Print out the message received from the server. + ACE_DEBUG ((LM_DEBUG, "%s", msg->rd_ptr ())); + delete msg; + return 1; // Reinvokes the recv() operation! + } + + delete msg; + // If a read failed, we will assume it's because the remote peer + // went away. We will end the event loop. Since we're in the main + // thread, we don't need to do a notify. + ACE_Service_Config::end_reactorEx_event_loop (); + return -1; // Close down. +} + +// This is so the Proactor can get a message to read into. + +ACE_Message_Block * +Peer_Handler::get_message (void) +{ + // An extra byte for NUL termination. + ACE_Message_Block *message = + new ACE_Message_Block (BUFSIZ + 1); + + message->size (BUFSIZ); + return message; +} + +// This is so the Proactor can get our handle. +ACE_HANDLE +Peer_Handler::get_handle (void) const +{ + return this->stream_.get_handle (); +} + +// We've been removed from the ReactorEx. +int +Peer_Handler::handle_close (ACE_HANDLE, ACE_Reactor_Mask) +{ + ACE_DEBUG ((LM_DEBUG, "Peer_Handler closing down\n")); + return 0; +} + +// We've been signaled by the STDIN thread. Try to dequeue a +// message. + +int +Peer_Handler::handle_signal (int, siginfo_t *, ucontext_t *) +{ + this->try_send (); + return 0; +} + +// Try to dequeue a message. If successful, send it proactively to +// the remote peer. + +void +Peer_Handler::try_send (void) +{ + ACE_Message_Block *mb; + + ACE_Time_Value tv (ACE_Time_Value::zero); + + if (this->getq (mb, &tv) != -1) + { + if (ACE_Service_Config::proactor ()-> + initiate (this, ACE_Event_Handler::WRITE_MASK, mb) == -1) + ACE_ERROR ((LM_ERROR, "%p Write initiate.\n", "Peer_Handler")); + } +} + +// Enqueue the new mb and signal the main thread. + +int +Peer_Handler::put (ACE_Message_Block *mb, ACE_Time_Value *tv) +{ + // Enqueue the mb. + int result = this->putq (mb, tv); + + // Signal the main thread. This will remain signaled until the main + // thread wakes up. + + if (::SetEvent (new_msg_event_) == 0) + ACE_ERROR ((LM_ERROR, "Pulse Failed!\n")); + + return result; +} + +void +STDIN_Handler::handler (int signum) +{ + ACE_DEBUG ((LM_DEBUG, "signal = %S\n", signum)); +} + +STDIN_Handler::STDIN_Handler (MT_TASK &ph) + : ph_ (ph) +{ + // Register for ^C from the console. We just need to catch the + // exception so that the kernel doesn't kill our process. + // Registering this signal handler just tells the kernel that we + // know what we're doing; to leave us alone. + ACE_OS::signal (SIGINT, ACE_SignalHandler (STDIN_Handler::handler)); +}; + +// Activate object. + +int +STDIN_Handler::open (void *) +{ + if (this->activate (THR_NEW_LWP | THR_DETACHED) == -1) + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "spawn"), -1); + + return 0; +} + +// Shut down. + +int +STDIN_Handler::close (u_long) +{ + ACE_DEBUG ((LM_DEBUG, "(%t) thread is exiting.\n")); + return 0; +} + +// Thread runs here. + +int +STDIN_Handler::svc (void) +{ + this->register_thread_exit_hook (); + + for (;;) + { + ACE_Message_Block *mb = new ACE_Message_Block (BUFSIZ); + + // Read from stdin into mb. + int read_result = ACE_OS::read (ACE_STDIN, + mb->rd_ptr (), + mb->size ()); + + // If read succeeds, put mb to peer handler, else end the loop. + if (read_result > 0) + { + mb->wr_ptr (read_result); + this->ph_.put (mb); + } + else + break; + } + + // handle_signal will get called. + return 42; +} + +// Register an exit hook with the reactorEx. All this junk is testing +// out how ACE_Thread::self (hthread_id&) doesn't work!! + +void +STDIN_Handler::register_thread_exit_hook (void) +{ + ACE_hthread_t handle; + + // Get a real handle to our thread. + ACE_Service_Config::thr_mgr ()->thr_self (handle); + + // Register ourselves to get called back when our thread exits. + + if (ACE_Service_Config::reactorEx ()-> + register_handler (this, handle) == -1) + ACE_ERROR ((LM_ERROR, "Exit_Hook Register failed.\n")); + + // We're in another thread, so we need to notify the ReactorEx so + // that it wakes up and waits on the new set of handles. + ACE_Service_Config::reactorEx ()->notify (); +} + +// The STDIN thread has exited. This means the user hit ^C. We can +// end the event loop and delete ourself. + +int +STDIN_Handler::handle_signal (int, siginfo_t *, ucontext_t *) +{ + ACE_DEBUG ((LM_DEBUG, "STDIN thread has exited.\n")); + ACE_Service_Config::end_reactorEx_event_loop (); + return 0; +} + +int +main (int argc, char *argv[]) +{ + // Open handler for remote peer communications this will run from + // the main thread. + Peer_Handler peer_handler (argc, argv); + + if (peer_handler.open () == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p open failed, errno = %d.\n", + "peer_handler", errno), 0); + + // Open active object for reading from stdin. + STDIN_Handler stdin_handler (peer_handler); + + if (stdin_handler.open () == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p open failed, errno = %d.\n", + "stdin_handler", errno), 0); + + // Register proactor with ReactorEx so that we can demultiplex + // "waitable" events and I/O operations from a single thread. + if (ACE_Service_Config::reactorEx ()->register_handler + (ACE_Service_Config::proactor ()) != 0) + ACE_ERROR_RETURN ((LM_ERROR, "%p failed to register Proactor.\n", + argv[0]), -1); + + // Run main event demultiplexor. + ACE_Service_Config::run_reactorEx_event_loop (); + + return 42; +} diff --git a/examples/Reactor/ReactorEx/test_remove_handler.cpp b/examples/Reactor/ReactorEx/test_remove_handler.cpp new file mode 100644 index 00000000000..fb61519b1e9 --- /dev/null +++ b/examples/Reactor/ReactorEx/test_remove_handler.cpp @@ -0,0 +1,94 @@ +// ============================================================================ +// @(#)test_remove_handler.cpp 1.1 10/18/96 + +// +// = LIBRARY +// examples +// +// = FILENAME +// test_remove_handler.cpp +// +// = DESCRIPTION +// Tests the ReactorEx's ability to handle simultaneous events. If +// you pass anything on the command-line, then each handler +// requests to be removed from the ReactorEx after each event. +// This has a funky effect on the order in which handlers are +// serviced. So, if no parameters are passed in, the handlers +// should be serviced 1 through MAXIMUM_WAIT_OBJECTS. If handlers +// to request to be removed as signals occur, they will be serviced +// 1, MAX, MAX-1, ..., 2. This is because of a ReactorEx +// bookkeeping optimization. +// +// = AUTHOR +// Tim Harrison +// +// ============================================================================ + +#include "ace/ReactorEx.h" +#include "ace/Service_Config.h" +#include "ace/Synch.h" + +class Event_Handler : public ACE_Event_Handler +// = TITLE +// Generic Event Handler. +// +// = DESCRIPTION +// +// Creates event. Registers with ReactorEx. Signals event. If +// created with -close_down- it returns -1 from handle signal. +{ +public: + Event_Handler (int event_number, + int close_down) + : event_number_ (event_number), + close_down_ (close_down) + { + ACE_Service_Config::reactorEx ()->register_handler (this, + this->event_.handle ()); + this->event_.signal (); + } + + virtual int handle_signal (int index, siginfo_t *, ucontext_t *) + { + ACE_DEBUG ((LM_DEBUG, "event %d occured.\n", event_number_)); + + if (this->close_down_) + return -1; + else + return 0; + } + + virtual int handle_close (ACE_HANDLE, ACE_Reactor_Mask) + { + // ACE_DEBUG ((LM_DEBUG, "event handler %d closed.\n", event_number_)); + delete this; + return 0; + } + + virtual ACE_HANDLE get_handle (void) const + { + return event_.handle (); + } + +private: + int event_number_; + // Our event number. + + int close_down_; + // Shall we close down or not. + + ACE_Event event_; + // Signaled to shut down the handler. +}; + +int +main (int argc, char *argv[]) +{ + int close_down = arg > 1 ? 1 : 0; + + for (int i = 0; i < ACE_ReactorEx::MAX_SIZE; i++) + new Event_Handler (i, close_down); + + ACE_Service_Config::reactorEx ()->handle_events (); + return 42; +} diff --git a/examples/Reactor/WFMO_Reactor/README b/examples/Reactor/WFMO_Reactor/README new file mode 100644 index 00000000000..1184d09dd68 --- /dev/null +++ b/examples/Reactor/WFMO_Reactor/README @@ -0,0 +1,204 @@ +The ACE_ReactorEx encapsulates the Win32 WaitForMultipleObjects() API +within ACE. The ACE_ReactorEx is similar in spirit to the +ACE_Reactor, except that (1) it is much simpler and (2) it works for +the complete range of Win32 handles (whereas the ACE_Reactor just +works for socket handles. + +Here's the API for the ACE_ReactorEx: + +class ACE_ReactorEx +{ +public: + // = Event loop. + virtual int handle_events (ACE_Time_Value *); + + // = Handler registration management. + virtual int register_handler (ACE_Event_Handler *); + virtual int remove_handler (ACE_Event_Handler *); + + virtual int notify (void); + + // = Timer management + virtual int schedule_timer (), etc. + // ... +}; + +---------------------------------------- + +Here's how you might use it: + +---------------------------------------- + +class My_Thread_Handler : public ACE_Event_Handler +{ +public: + My_Thread_Handler (void) { + // Create a thread that will run + // for a time and then exit. + this->thread_handle_ = + ACE_OS::thr_create (run, ......); + } + + // Called back by the ACE_ReactorEx when the + // event is signaled. + virtual int handle_signal (int) + { + cout << "thread is done" << endl; + } + + virtual ACE_HANDLE get_handle (void) const + { + return this->thread_handle_; + } + +private: + ACE_HANDLE thread_handle_; + + static void *run (void *) { + // Sleep for a while and then exit. + ACE_OS::sleep (100000); + return 0; + } +}; + +---------------------------------------- + +The main program might look something like this: + +---------------------------------------- + +int main (void) +{ + // ... + ACE_ReactorEx dispatcher; + My_Thread_Handler handler; + + // Register the thread handler. + dispatcher.register_handler (&handler); + + // Block until the thread exits and the + // handle_signal() method of the My_Thread_Handler + // is called! + dispatcher.handle_events (); + + // ... +} + +---------------------------------------- + +. test_remove_handler -- + +This application tests the ReactorEx's ability to handle simultaneous +events. If you pass anything on the command-line, then each handler +requests to be removed from the ReactorEx after each event. This has +a funky effect on the order in which handlers are serviced. So, if no +parameters are passed in, the handlers should be serviced 1 through +MAXIMUM_WAIT_OBJECTS. If handlers to request to be removed as signals +occur, they will be serviced 1, MAX, MAX-1, ..., 2. This is because +of a ReactorEx bookkeeping optimization. + +. test_reactorEx.cpp -- + +This test application tests a wide range of events that can be +demultiplexed using various ACE utilities. Events used include ^C +events, reading from STDIN, vanilla Win32 events, thread exits, +ReactorEx notifications, proactive reads, and proactive writes. + +The proactive I/O events are demultiplexed by the ACE_Proactor. The +thread exits, notications, and vanilla Win32 events are demultiplexed +by the ACE_ReactorEx. To enable a single thread to run all these +events, the Proactor is integrated with the ReactorEx. + +The test application prototypes a simple ntalk program. Two instances +of the application connect. Input from either console is displayed on +the others console also. Because of the evils of Win32 STDIN, a +separate thread is used to read from STDIN. To test the Proactor and +ReactorEx, I/O between the remote processes is performed proactively +and interactions between the STDIN thread and the main thread are +performed reactively. + +The following description of the test application is in two parts. +The participants section explains the main components involved in the +application. The collaboration section describes how the partipants +interact in response to the multiple event types which occur. + +The ReactorEx test application has the following participants: + +. ReactorEx -- The ReactorEx demultiplexes Win32 "waitable" events + using WaitForMultipleObjects. + +. Proactor -- The proactor initiates and demultiplexes overlapped I/O + operations. The Proactor registers with the ReactorEx so that a + single-thread can demultiplex all application events. + +. STDIN_Handler -- STDIN_Handler is an Active Object which reads from + STDIN and forwards the input to the Peer_Handler. This runs + in a separate thread to make the test more interesting. However, + STDIN is "waitable", so in general it can be waited on by the ACE + ReactorEx, thanks MicroSlush! + +. Peer_Handler -- The Peer_Handler connects to another instance of + test_reactorEx. It Proactively reads and writes data to the peer. + When the STDIN_Handler gives it messages, it fowards them to the + remote peer. When it receives messages from the remote peer, it + prints the output to the console. + +The collaborations of the participants are as follows: + +. Initialization + + Peer_Handler -- connects to the remote peer. It then begins + proactively reading from the remote connection. Note that it will + be notified by the Proactor when a read completes. It also + registers a new_msg_event with the ReactorEx. Note that when the + new_msg_event is signaled (by the STDIN_Handler), + Peer_Handler::handle_signal will get called. + + STDIN_Handler -- STDIN_Handler registers a signal handler for + SIGINT. This just captures the exception so that the kernel doesn't + kill our process; We want to exit gracefully. It also creates an + Exit_Hook object which registers the STDIN_Handler's thread handle + with the ReactorEx. The Exit_Hook will get called back when the + STDIN_Handler thread exits. After registering these, it blocks + reading from STDIN. + + Proactor -- is registered with the ReactorEx. + + The main thread of control waits in the ReactorEx. + +. STDIN events -- When the STDIN_Handler thread reads from STDIN, it + puts the message on Peer_Handler's message queue and signals the + new_msg_event. It then returns to reading from STDIN. + +. new_msg_events -- The ReactorEx thread wakes up and calls + Peer_Handler::handle_signal. The Peer_Handler then tries to dequeue + a message from its message queue. If it can, the message is + Proactively sent to the remote peer. Note that the Peer_Handler + will be notified with this operation is complete. The Peer_Handler + then falls back into the ReactorEx event loop. + +. Send complete event -- When a proactive send is complete, the + Proactor is notified by the ReactorEx. The Proactor, in turn, + notifies the Peer_Handler. The Peer_Handler then checks for more + messages from the message queue. If there are any, it tries to send + them. If there are not, it returns to the ReactorEx event loop. + This is ok since it is notified via new_msg_event when new message + arrive. + +. Read complete event -- When a proactive read is complete (the + Peer_Handler initiated a proactive read when it connected to the + remote peer), the Proactor is notified by the ReactorEx. The + Proactor, in turn notifies the Peer_Handler. If the read was + successful the Peer_Handler just displays the received msg to the + console and reinvokes a proactive read from the network connection. + If the read failed (i.e. the remote peer exited), the Peer_Handler + sets a flag to end the event loop and returns. This will cause the + application to exit. + +. ^C events -- When the user types ^C at the console, the + STDIN_Handler's signal handler will be called. It does nothing, but + as a result of the signal, the STDIN_Handler thread will exit. + +. STDIN_Handler thread exits -- The Exit_Hook will get called back + from the ReactorEx. Exit_Hook::handle_signal sets a flag to end the + event loop and returns. This will cause the application to exit. diff --git a/examples/Reactor/WFMO_Reactor/reactorex.mak b/examples/Reactor/WFMO_Reactor/reactorex.mak new file mode 100644 index 00000000000..150d04508d7 --- /dev/null +++ b/examples/Reactor/WFMO_Reactor/reactorex.mak @@ -0,0 +1,535 @@ +# Microsoft Developer Studio Generated NMAKE File, Format Version 4.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+!IF "$(CFG)" == ""
+CFG=test_remove_handler - Win32 Debug
+!MESSAGE No configuration specified. Defaulting to test_remove_handler - Win32\
+ Debug.
+!ENDIF
+
+!IF "$(CFG)" != "ntalk - Win32 Release" && "$(CFG)" != "ntalk - Win32 Debug" &&\
+ "$(CFG)" != "test_remove_handler - Win32 Release" && "$(CFG)" !=\
+ "test_remove_handler - Win32 Debug"
+!MESSAGE Invalid configuration "$(CFG)" specified.
+!MESSAGE You can specify a configuration when running NMAKE on this makefile
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "reactorEx.mak" CFG="test_remove_handler - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "ntalk - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "ntalk - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE "test_remove_handler - Win32 Release" (based on\
+ "Win32 (x86) Console Application")
+!MESSAGE "test_remove_handler - Win32 Debug" (based on\
+ "Win32 (x86) Console Application")
+!MESSAGE
+!ERROR An invalid configuration is specified.
+!ENDIF
+
+!IF "$(OS)" == "Windows_NT"
+NULL=
+!ELSE
+NULL=nul
+!ENDIF
+################################################################################
+# Begin Project
+# PROP Target_Last_Scanned "ntalk - Win32 Debug"
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "ntalk - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "ntalk\Release"
+# PROP BASE Intermediate_Dir "ntalk\Release"
+# PROP BASE Target_Dir "ntalk"
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "ntalk\Release"
+# PROP Intermediate_Dir "ntalk\Release"
+# PROP Target_Dir "ntalk"
+OUTDIR=.\ntalk\Release
+INTDIR=.\ntalk\Release
+
+ALL : "$(OUTDIR)\ntalk.exe"
+
+CLEAN :
+ -@erase ".\ntalk\Release\ntalk.exe"
+ -@erase ".\ntalk\Release\test_reactorEx.obj"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c
+# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c
+CPP_PROJ=/nologo /ML /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE"\
+ /Fp"$(INTDIR)/ntalk.pch" /YX /Fo"$(INTDIR)/" /c
+CPP_OBJS=.\ntalk\Release/
+CPP_SBRS=
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+BSC32_FLAGS=/nologo /o"$(OUTDIR)/ntalk.bsc"
+BSC32_SBRS=
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib ace.lib /nologo /subsystem:console /machine:I386
+LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
+ advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\
+ odbccp32.lib ace.lib /nologo /subsystem:console /incremental:no\
+ /pdb:"$(OUTDIR)/ntalk.pdb" /machine:I386 /out:"$(OUTDIR)/ntalk.exe"
+LINK32_OBJS= \
+ "$(INTDIR)/test_reactorEx.obj"
+
+"$(OUTDIR)\ntalk.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+!ELSEIF "$(CFG)" == "ntalk - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "ntalk\Debug"
+# PROP BASE Intermediate_Dir "ntalk\Debug"
+# PROP BASE Target_Dir "ntalk"
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir ""
+# PROP Intermediate_Dir "debug"
+# PROP Target_Dir "ntalk"
+OUTDIR=.
+INTDIR=.\debug
+
+ALL : "$(OUTDIR)\test_reactorEx.exe"
+
+CLEAN :
+ -@erase ".\debug\vc40.pdb"
+ -@erase ".\debug\vc40.idb"
+ -@erase ".\test_reactorEx.exe"
+ -@erase ".\debug\test_reactorEx.obj"
+ -@erase ".\test_reactorEx.ilk"
+ -@erase ".\test_reactorEx.pdb"
+
+"$(INTDIR)" :
+ if not exist "$(INTDIR)/$(NULL)" mkdir "$(INTDIR)"
+
+# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /YX /c
+# ADD CPP /nologo /MDd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /YX /c
+CPP_PROJ=/nologo /MDd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE"\
+ /Fp"$(INTDIR)/ntalk.pch" /YX /Fo"$(INTDIR)/" /Fd"$(INTDIR)/" /c
+CPP_OBJS=.\debug/
+CPP_SBRS=
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+BSC32_FLAGS=/nologo /o"$(OUTDIR)/ntalk.bsc"
+BSC32_SBRS=
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib ace.lib /nologo /subsystem:console /debug /machine:I386 /out:"test_reactorEx.exe"
+LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
+ advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\
+ odbccp32.lib ace.lib /nologo /subsystem:console /incremental:yes\
+ /pdb:"$(OUTDIR)/test_reactorEx.pdb" /debug /machine:I386\
+ /out:"$(OUTDIR)/test_reactorEx.exe"
+LINK32_OBJS= \
+ "$(INTDIR)/test_reactorEx.obj"
+
+"$(OUTDIR)\test_reactorEx.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+!ELSEIF "$(CFG)" == "test_remove_handler - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "test_remove_handler\Release"
+# PROP BASE Intermediate_Dir "test_remove_handler\Release"
+# PROP BASE Target_Dir "test_remove_handler"
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "test_remove_handler\Release"
+# PROP Intermediate_Dir "test_remove_handler\Release"
+# PROP Target_Dir "test_remove_handler"
+OUTDIR=.\test_remove_handler\Release
+INTDIR=.\test_remove_handler\Release
+
+ALL : "$(OUTDIR)\test_remove_handler.exe"
+
+CLEAN :
+ -@erase ".\test_remove_handler\Release\test_remove_handler.exe"
+ -@erase ".\test_remove_handler\Release\test_remove_handler.obj"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c
+# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c
+CPP_PROJ=/nologo /ML /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE"\
+ /Fp"$(INTDIR)/test_remove_handler.pch" /YX /Fo"$(INTDIR)/" /c
+CPP_OBJS=.\test_remove_handler\Release/
+CPP_SBRS=
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+BSC32_FLAGS=/nologo /o"$(OUTDIR)/test_remove_handler.bsc"
+BSC32_SBRS=
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
+ advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\
+ odbccp32.lib /nologo /subsystem:console /incremental:no\
+ /pdb:"$(OUTDIR)/test_remove_handler.pdb" /machine:I386\
+ /out:"$(OUTDIR)/test_remove_handler.exe"
+LINK32_OBJS= \
+ "$(INTDIR)/test_remove_handler.obj"
+
+"$(OUTDIR)\test_remove_handler.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+!ELSEIF "$(CFG)" == "test_remove_handler - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "test_remove_handler\Debug"
+# PROP BASE Intermediate_Dir "test_remove_handler\Debug"
+# PROP BASE Target_Dir "test_remove_handler"
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir ""
+# PROP Intermediate_Dir "Debug"
+# PROP Target_Dir "test_remove_handler"
+OUTDIR=.
+INTDIR=.\Debug
+
+ALL : "$(OUTDIR)\test_remove_handler.exe"
+
+CLEAN :
+ -@erase ".\debug\vc40.pdb"
+ -@erase ".\debug\vc40.idb"
+ -@erase ".\test_remove_handler.exe"
+ -@erase ".\Debug\test_remove_handler.obj"
+ -@erase ".\test_remove_handler.ilk"
+ -@erase ".\test_remove_handler.pdb"
+
+"$(INTDIR)" :
+ if not exist "$(INTDIR)/$(NULL)" mkdir "$(INTDIR)"
+
+# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /YX /c
+# ADD CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /YX /c
+CPP_PROJ=/nologo /MLd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE"\
+ /Fp"$(INTDIR)/test_remove_handler.pch" /YX /Fo"$(INTDIR)/" /Fd"$(INTDIR)/" /c
+CPP_OBJS=.\Debug/
+CPP_SBRS=
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+BSC32_FLAGS=/nologo /o"$(OUTDIR)/test_remove_handler.bsc"
+BSC32_SBRS=
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib ace.lib /nologo /subsystem:console /debug /machine:I386
+LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
+ advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\
+ odbccp32.lib ace.lib /nologo /subsystem:console /incremental:yes\
+ /pdb:"$(OUTDIR)/test_remove_handler.pdb" /debug /machine:I386\
+ /out:"$(OUTDIR)/test_remove_handler.exe"
+LINK32_OBJS= \
+ "$(INTDIR)/test_remove_handler.obj"
+
+"$(OUTDIR)\test_remove_handler.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+!ENDIF
+
+.c{$(CPP_OBJS)}.obj:
+ $(CPP) $(CPP_PROJ) $<
+
+.cpp{$(CPP_OBJS)}.obj:
+ $(CPP) $(CPP_PROJ) $<
+
+.cxx{$(CPP_OBJS)}.obj:
+ $(CPP) $(CPP_PROJ) $<
+
+.c{$(CPP_SBRS)}.sbr:
+ $(CPP) $(CPP_PROJ) $<
+
+.cpp{$(CPP_SBRS)}.sbr:
+ $(CPP) $(CPP_PROJ) $<
+
+.cxx{$(CPP_SBRS)}.sbr:
+ $(CPP) $(CPP_PROJ) $<
+
+################################################################################
+# Begin Target
+
+# Name "ntalk - Win32 Release"
+# Name "ntalk - Win32 Debug"
+
+!IF "$(CFG)" == "ntalk - Win32 Release"
+
+!ELSEIF "$(CFG)" == "ntalk - Win32 Debug"
+
+!ENDIF
+
+################################################################################
+# Begin Source File
+
+SOURCE=.\test_reactorEx.cpp
+DEP_CPP_TEST_=\
+ {$(INCLUDE)}"\ace\ReactorEx.h"\
+ {$(INCLUDE)}"\ace\Proactor.h"\
+ {$(INCLUDE)}"\ace\SOCK_Connector.h"\
+ {$(INCLUDE)}"\ace\SOCK_Acceptor.h"\
+ {$(INCLUDE)}"\ace\Get_Opt.h"\
+ {$(INCLUDE)}"\ace\Time_Value.h"\
+ {$(INCLUDE)}"\ace\Service_Config.h"\
+ {$(INCLUDE)}"\ace\Synch.h"\
+ {$(INCLUDE)}"\ace\Task.h"\
+ {$(INCLUDE)}"\ace\OS.h"\
+ {$(INCLUDE)}"\ace\Timer_Queue.h"\
+ {$(INCLUDE)}"\ace\Event_Handler.h"\
+ {$(INCLUDE)}"\ace\Token.h"\
+ {$(INCLUDE)}"\ace\Local_Tokens.h"\
+ {$(INCLUDE)}"\ace\ReactorEx.i"\
+ {$(INCLUDE)}"\ace\Timer_Queue.i"\
+ {$(INCLUDE)}"\ace\ACE.h"\
+ {$(INCLUDE)}"\ace\Event_Handler.i"\
+ {$(INCLUDE)}"\ace\ACE.i"\
+ {$(INCLUDE)}"\ace\Log_Msg.h"\
+ {$(INCLUDE)}"\ace\Log_Record.h"\
+ {$(INCLUDE)}"\ace\Log_Priority.h"\
+ {$(INCLUDE)}"\ace\Log_Record.i"\
+ {$(INCLUDE)}"\ace\Token.i"\
+ {$(INCLUDE)}"\ace\Stack.h"\
+ {$(INCLUDE)}"\ace\Synch_Options.h"\
+ {$(INCLUDE)}"\ace\Map_Manager.h"\
+ {$(INCLUDE)}"\ace\Local_Tokens.i"\
+ {$(INCLUDE)}"\ace\Stack.i"\
+ {$(INCLUDE)}"\ace\Stack.cpp"\
+ {$(INCLUDE)}"\ace\Map_Manager.i"\
+ {$(INCLUDE)}"\ace\Map_Manager.cpp"\
+ {$(INCLUDE)}"\ace\Malloc.h"\
+ {$(INCLUDE)}"\ace\SV_Semaphore_Simple.h"\
+ {$(INCLUDE)}"\ace\Malloc.i"\
+ {$(INCLUDE)}"\ace\Malloc_T.h"\
+ {$(INCLUDE)}"\ace\Memory_Pool.h"\
+ {$(INCLUDE)}"\ace\SV_Semaphore_Simple.i"\
+ {$(INCLUDE)}"\ace\Trace.h"\
+ {$(INCLUDE)}"\ace\Malloc_T.i"\
+ {$(INCLUDE)}"\ace\Malloc_T.cpp"\
+ {$(INCLUDE)}"\ace\Signal.h"\
+ {$(INCLUDE)}"\ace\Mem_Map.h"\
+ {$(INCLUDE)}"\ace\SV_Semaphore_Complex.h"\
+ {$(INCLUDE)}"\ace\Memory_Pool.i"\
+ {$(INCLUDE)}"\ace\Set.h"\
+ {$(INCLUDE)}"\ace\Signal.i"\
+ {$(INCLUDE)}"\ace\Set.i"\
+ {$(INCLUDE)}"\ace\Set.cpp"\
+ {$(INCLUDE)}"\ace\Mem_Map.i"\
+ {$(INCLUDE)}"\ace\SV_Semaphore_Complex.i"\
+ {$(INCLUDE)}"\ace\Message_Block.h"\
+ {$(INCLUDE)}"\ace\Proactor.i"\
+ {$(INCLUDE)}"\ace\Message_Block.i"\
+ {$(INCLUDE)}"\ace\SOCK_Stream.h"\
+ {$(INCLUDE)}"\ace\SOCK_Connector.i"\
+ {$(INCLUDE)}"\ace\SOCK_IO.h"\
+ {$(INCLUDE)}"\ace\INET_Addr.h"\
+ {$(INCLUDE)}"\ace\SOCK_Stream.i"\
+ {$(INCLUDE)}"\ace\SOCK.h"\
+ {$(INCLUDE)}"\ace\SOCK_IO.i"\
+ {$(INCLUDE)}"\ace\Addr.h"\
+ {$(INCLUDE)}"\ace\IPC_SAP.h"\
+ {$(INCLUDE)}"\ace\SOCK.i"\
+ {$(INCLUDE)}"\ace\Addr.i"\
+ {$(INCLUDE)}"\ace\IPC_SAP.i"\
+ {$(INCLUDE)}"\ace\INET_Addr.i"\
+ {$(INCLUDE)}"\ace\SOCK_Acceptor.i"\
+ {$(INCLUDE)}"\ace\Get_Opt.i"\
+ {$(INCLUDE)}"\ace\config.h"\
+ {$(INCLUDE)}"\ace\Time_Value.i"\
+ {$(INCLUDE)}"\ace\Service_Object.h"\
+ {$(INCLUDE)}"\ace\Thread_Manager.h"\
+ {$(INCLUDE)}"\ace\Service_Config.i"\
+ {$(INCLUDE)}"\ace\Reactor.h"\
+ {$(INCLUDE)}"\ace\Svc_Conf_Tokens.h"\
+ {$(INCLUDE)}"\ace\Shared_Object.h"\
+ {$(INCLUDE)}"\ace\Service_Object.i"\
+ {$(INCLUDE)}"\ace\Shared_Object.i"\
+ {$(INCLUDE)}"\ace\Thread.h"\
+ {$(INCLUDE)}"\ace\Thread_Manager.i"\
+ {$(INCLUDE)}"\ace\Thread.i"\
+ {$(INCLUDE)}"\ace\Handle_Set.h"\
+ {$(INCLUDE)}"\ace\Pipe.h"\
+ {$(INCLUDE)}"\ace\Reactor.i"\
+ {$(INCLUDE)}"\ace\Handle_Set.i"\
+ {$(INCLUDE)}"\ace\Pipe.i"\
+ {$(INCLUDE)}"\ace\Synch.i"\
+ {$(INCLUDE)}"\ace\Synch_T.h"\
+ {$(INCLUDE)}"\ace\Synch_T.i"\
+ {$(INCLUDE)}"\ace\Synch_T.cpp"\
+ {$(INCLUDE)}"\ace\Message_Queue.h"\
+ {$(INCLUDE)}"\ace\Task.i"\
+ {$(INCLUDE)}"\ace\Task.cpp"\
+ {$(INCLUDE)}"\ace\IO_Cntl_Msg.h"\
+ {$(INCLUDE)}"\ace\Message_Queue.i"\
+ {$(INCLUDE)}"\ace\Message_Queue.cpp"\
+ {$(INCLUDE)}"\ace\Module.h"\
+ {$(INCLUDE)}"\ace\Module.i"\
+ {$(INCLUDE)}"\ace\Module.cpp"\
+ {$(INCLUDE)}"\ace\Stream_Modules.h"\
+ {$(INCLUDE)}"\ace\Stream_Modules.i"\
+ {$(INCLUDE)}"\ace\Stream_Modules.cpp"\
+ {$(INCLUDE)}"\sys\TYPES.H"\
+ {$(INCLUDE)}"\sys\STAT.H"\
+ {$(INCLUDE)}"\sys\TIMEB.H"\
+ {$(INCLUDE)}"\ace\OS.i"\
+
+NODEP_CPP_TEST_=\
+ ".\..\..\ace\ace\Sync_T.h"\
+ ".\..\..\ace\semLib.h"\
+
+
+"$(INTDIR)\test_reactorEx.obj" : $(SOURCE) $(DEP_CPP_TEST_) "$(INTDIR)"
+
+
+# End Source File
+# End Target
+################################################################################
+# Begin Target
+
+# Name "test_remove_handler - Win32 Release"
+# Name "test_remove_handler - Win32 Debug"
+
+!IF "$(CFG)" == "test_remove_handler - Win32 Release"
+
+!ELSEIF "$(CFG)" == "test_remove_handler - Win32 Debug"
+
+!ENDIF
+
+################################################################################
+# Begin Source File
+
+SOURCE=.\test_remove_handler.cpp
+DEP_CPP_TEST_R=\
+ {$(INCLUDE)}"\ace\ReactorEx.h"\
+ {$(INCLUDE)}"\ace\Service_Config.h"\
+ {$(INCLUDE)}"\ace\Synch.h"\
+ {$(INCLUDE)}"\ace\Timer_Queue.h"\
+ {$(INCLUDE)}"\ace\Time_Value.h"\
+ {$(INCLUDE)}"\ace\Event_Handler.h"\
+ {$(INCLUDE)}"\ace\Token.h"\
+ {$(INCLUDE)}"\ace\Local_Tokens.h"\
+ {$(INCLUDE)}"\ace\ReactorEx.i"\
+ {$(INCLUDE)}"\ace\Timer_Queue.i"\
+ {$(INCLUDE)}"\ace\config.h"\
+ {$(INCLUDE)}"\ace\Time_Value.i"\
+ {$(INCLUDE)}"\ace\Trace.h"\
+ {$(INCLUDE)}"\ace\ACE.h"\
+ {$(INCLUDE)}"\ace\Event_Handler.i"\
+ {$(INCLUDE)}"\ace\OS.h"\
+ {$(INCLUDE)}"\ace\ACE.i"\
+ {$(INCLUDE)}"\sys\TYPES.H"\
+ {$(INCLUDE)}"\sys\STAT.H"\
+ {$(INCLUDE)}"\sys\TIMEB.H"\
+ {$(INCLUDE)}"\ace\OS.i"\
+ {$(INCLUDE)}"\ace\Log_Msg.h"\
+ {$(INCLUDE)}"\ace\Log_Record.h"\
+ {$(INCLUDE)}"\ace\Log_Priority.h"\
+ {$(INCLUDE)}"\ace\Log_Record.i"\
+ {$(INCLUDE)}"\ace\Token.i"\
+ {$(INCLUDE)}"\ace\Stack.h"\
+ {$(INCLUDE)}"\ace\Synch_Options.h"\
+ {$(INCLUDE)}"\ace\Map_Manager.h"\
+ {$(INCLUDE)}"\ace\Local_Tokens.i"\
+ {$(INCLUDE)}"\ace\Stack.i"\
+ {$(INCLUDE)}"\ace\Stack.cpp"\
+ {$(INCLUDE)}"\ace\Map_Manager.i"\
+ {$(INCLUDE)}"\ace\Map_Manager.cpp"\
+ {$(INCLUDE)}"\ace\Malloc.h"\
+ {$(INCLUDE)}"\ace\SV_Semaphore_Simple.h"\
+ {$(INCLUDE)}"\ace\Malloc.i"\
+ {$(INCLUDE)}"\ace\Malloc_T.h"\
+ {$(INCLUDE)}"\ace\Memory_Pool.h"\
+ {$(INCLUDE)}"\ace\SV_Semaphore_Simple.i"\
+ {$(INCLUDE)}"\ace\Malloc_T.i"\
+ {$(INCLUDE)}"\ace\Malloc_T.cpp"\
+ {$(INCLUDE)}"\ace\Signal.h"\
+ {$(INCLUDE)}"\ace\Mem_Map.h"\
+ {$(INCLUDE)}"\ace\SV_Semaphore_Complex.h"\
+ {$(INCLUDE)}"\ace\Memory_Pool.i"\
+ {$(INCLUDE)}"\ace\Set.h"\
+ {$(INCLUDE)}"\ace\Signal.i"\
+ {$(INCLUDE)}"\ace\Set.i"\
+ {$(INCLUDE)}"\ace\Set.cpp"\
+ {$(INCLUDE)}"\ace\Mem_Map.i"\
+ {$(INCLUDE)}"\ace\SV_Semaphore_Complex.i"\
+ {$(INCLUDE)}"\ace\Service_Object.h"\
+ {$(INCLUDE)}"\ace\Thread_Manager.h"\
+ {$(INCLUDE)}"\ace\Proactor.h"\
+ {$(INCLUDE)}"\ace\Service_Config.i"\
+ {$(INCLUDE)}"\ace\Reactor.h"\
+ {$(INCLUDE)}"\ace\Svc_Conf_Tokens.h"\
+ {$(INCLUDE)}"\ace\Shared_Object.h"\
+ {$(INCLUDE)}"\ace\Service_Object.i"\
+ {$(INCLUDE)}"\ace\Shared_Object.i"\
+ {$(INCLUDE)}"\ace\Thread.h"\
+ {$(INCLUDE)}"\ace\Thread_Manager.i"\
+ {$(INCLUDE)}"\ace\Thread.i"\
+ {$(INCLUDE)}"\ace\Message_Block.h"\
+ {$(INCLUDE)}"\ace\Proactor.i"\
+ {$(INCLUDE)}"\ace\Message_Block.i"\
+ {$(INCLUDE)}"\ace\Handle_Set.h"\
+ {$(INCLUDE)}"\ace\Pipe.h"\
+ {$(INCLUDE)}"\ace\SOCK_Stream.h"\
+ {$(INCLUDE)}"\ace\Reactor.i"\
+ {$(INCLUDE)}"\ace\Handle_Set.i"\
+ {$(INCLUDE)}"\ace\Pipe.i"\
+ {$(INCLUDE)}"\ace\SOCK_IO.h"\
+ {$(INCLUDE)}"\ace\INET_Addr.h"\
+ {$(INCLUDE)}"\ace\SOCK_Stream.i"\
+ {$(INCLUDE)}"\ace\SOCK.h"\
+ {$(INCLUDE)}"\ace\SOCK_IO.i"\
+ {$(INCLUDE)}"\ace\Addr.h"\
+ {$(INCLUDE)}"\ace\IPC_SAP.h"\
+ {$(INCLUDE)}"\ace\SOCK.i"\
+ {$(INCLUDE)}"\ace\Addr.i"\
+ {$(INCLUDE)}"\ace\IPC_SAP.i"\
+ {$(INCLUDE)}"\ace\INET_Addr.i"\
+ {$(INCLUDE)}"\ace\Synch.i"\
+ {$(INCLUDE)}"\ace\Synch_T.h"\
+ {$(INCLUDE)}"\ace\Synch_T.i"\
+ {$(INCLUDE)}"\ace\Synch_T.cpp"\
+
+NODEP_CPP_TEST_R=\
+ ".\..\..\ace\semLib.h"\
+ ".\..\..\ace\ace\Sync_T.h"\
+
+
+"$(INTDIR)\test_remove_handler.obj" : $(SOURCE) $(DEP_CPP_TEST_R) "$(INTDIR)"
+
+
+# End Source File
+# End Target
+# End Project
+################################################################################
diff --git a/examples/Reactor/WFMO_Reactor/reactorex.mdp b/examples/Reactor/WFMO_Reactor/reactorex.mdp Binary files differnew file mode 100644 index 00000000000..0135cc67b75 --- /dev/null +++ b/examples/Reactor/WFMO_Reactor/reactorex.mdp diff --git a/examples/Reactor/WFMO_Reactor/test_reactorEx.cpp b/examples/Reactor/WFMO_Reactor/test_reactorEx.cpp new file mode 100644 index 00000000000..757e78c1e9e --- /dev/null +++ b/examples/Reactor/WFMO_Reactor/test_reactorEx.cpp @@ -0,0 +1,444 @@ +// ============================================================================ +// @(#)test_reactorEx.cpp 1.1 10/18/96 + +// +// = LIBRARY +// examples +// +// = FILENAME +// test_reactorEx.cpp +// +// = DESCRIPTION +// This test application tests a wide range of events that can be +// demultiplexed using various ACE utilities. Events used include ^C +// events, reading from STDIN, vanilla Win32 events, thread exits, +// ReactorEx notifications, proactive reads, and proactive writes. +// +// The proactive I/O events are demultiplexed by the ACE_Proactor. +// The thread exits, notications, and vanilla Win32 events are +// demultiplexed by the ACE_ReactorEx. To enable a single thread +// to run all these events, the Proactor is integrated with the +// ReactorEx. +// +// = AUTHOR +// Tim Harrison +// +// ============================================================================ + +#include "ace/ReactorEx.h" +#include "ace/Proactor.h" +#include "ace/SOCK_Connector.h" +#include "ace/SOCK_Acceptor.h" +#include "ace/Get_Opt.h" +#include "ace/Time_Value.h" +#include "ace/Service_Config.h" +#include "ace/Synch.h" +#include "ace/Task.h" +#include "ace/OS.h" + +typedef ACE_Task<ACE_MT_SYNCH> MT_TASK; + +class Peer_Handler : public MT_TASK + // = TITLE + // Connect to a server. Receive messages from STDIN_Handler + // and forward them to the server using proactive I/O. +{ +public: + Peer_Handler (int argc, char *argv[]); + + int open (void * =0); + // This method creates the network connection to the remote peer. + // It does blocking connects and accepts depending on whether a + // hostname was specified from the command line. + + virtual int handle_output_complete (ACE_Message_Block *msg, + long bytes_transfered); + // One of our asynchronous writes to the remote peer has completed. + // Make sure it succeeded and then delete the message. + + virtual int handle_input_complete (ACE_Message_Block *msg, + long bytes_transfered); + // The remote peer has sent us something. If it succeeded, print + // out the message and reinitiate a read. Otherwise, fail. In both + // cases, delete the message sent. + + virtual ACE_Message_Block *get_message (void); + // This is so the Proactor can get a message to read into. + + virtual ACE_HANDLE get_handle (void) const; + // This is so the Proactor can get our handle. + + virtual int handle_close (ACE_HANDLE, ACE_Reactor_Mask); + // We've been removed from the ReactorEx. + + virtual int handle_signal (int index, siginfo_t *, ucontext_t *); + // We've been signaled by the STDIN thread. Try to dequeue a + // message. + + void try_send (void); + // Try to dequeue a message. If successful, send it proactively to + // the remote peer. + + virtual int put (ACE_Message_Block *mb, + ACE_Time_Value *tv = 0); + // Enqueue the new mb and signal the main thread. + +private: + ACE_SOCK_Stream stream_; + // Socket that we have connected to the server. + + ACE_HANDLE new_msg_event_; + // Event that gets signaled when messages arrive. + + // = Remote peer info. + char *host_; + // Name of remote host. + + u_short port_; + // Port number for remote host. + + // = Make Task happy. + int close (u_long) { return 0; } +}; + +class STDIN_Handler : public ACE_Task<ACE_NULL_SYNCH> + // = TITLE + // Active Object. Reads from STDIN and passes message blocks to + // the peer handler. +{ +public: + STDIN_Handler (MT_TASK &ph); + + virtual int open (void * = 0); + // Activate object. + + virtual int close (u_long = 0); + // Shut down. + + int svc (void); + // Thread runs here. + +private: + MT_TASK &ph_; + // Send all input to ph_. + + static void handler (int signum); + // Handle a ^C. (Do nothing). + + int put (ACE_Message_Block *, ACE_Time_Value *) { return 0; } + // Make Task happy. + + void register_thread_exit_hook (void); + // Helper function to register with the ReactorEx for thread exit. + + virtual int handle_signal (int index, siginfo_t *, ucontext_t *); + // The STDIN thread has exited. This means the user hit ^C. We can + // end the event loop. +}; + +Peer_Handler::Peer_Handler (int argc, char *argv[]) + : host_ (0), + port_ (ACE_DEFAULT_SERVER_PORT) +{ + ACE_Get_Opt get_opt (argc, argv, "h:p:"); + int c; + + while ((c = get_opt ()) != EOF) + { + switch (c) + { + case 'h': + host_ = get_opt.optarg; + break; + case 'p': + port_ = ACE_OS::atoi (get_opt.optarg); + break; + } + } + + // Auto reset event. + new_msg_event_ = ::CreateEvent (NULL, FALSE, FALSE, NULL); + ACE_Service_Config::reactorEx ()-> + register_handler (this, new_msg_event_); +} + +// This method creates the network connection to the remote peer. It +// does blocking connects and accepts depending on whether a hostname +// was specified from the command line. + +int +Peer_Handler::open (void *) +{ + if (host_ != 0) // Connector + { + ACE_INET_Addr addr (port_, host_); + ACE_SOCK_Connector connector; + + // Establish connection with server. + if (connector.connect (stream_, addr) == -1) + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "connect"), -1); + + ACE_DEBUG ((LM_DEBUG, "connected.\n")); + } + else // Acceptor + { + ACE_SOCK_Acceptor acceptor; + ACE_INET_Addr local_addr (port_); + + if ((acceptor.open (local_addr) == -1) || + (acceptor.accept (this->stream_) == -1)) + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "accept failed"), -1); + + ACE_DEBUG ((LM_DEBUG, "accepted.\n")); + } + + return ACE_Service_Config::proactor ()->initiate + (this, ACE_Event_Handler::READ_MASK); +} + +// One of our asynchronous writes to the remote peer has completed. +// Make sure it succeeded and then delete the message. + +int +Peer_Handler::handle_output_complete (ACE_Message_Block *msg, + long bytes_transfered) +{ + if (bytes_transfered <= 0) + ACE_DEBUG ((LM_DEBUG, "%p bytes = %d\n", "Message failed", + bytes_transfered)); + + // This was allocated by the STDIN_Handler, queued, dequeued, + // passed to the proactor, and now passed back to us. + delete msg; + return 0; // Do not reinvoke a send. +} + +// The remote peer has sent us something. If it succeeded, print +// out the message and reinitiate a read. Otherwise, fail. In both +// cases, delete the message sent. + +int +Peer_Handler::handle_input_complete (ACE_Message_Block *msg, + long bytes_transfered) +{ + if ((bytes_transfered > 0) && (msg->length () > 0)) + { + msg->rd_ptr ()[bytes_transfered] = '\0'; + // Print out the message received from the server. + ACE_DEBUG ((LM_DEBUG, "%s", msg->rd_ptr ())); + delete msg; + return 1; // Reinvokes the recv() operation! + } + + delete msg; + // If a read failed, we will assume it's because the remote peer + // went away. We will end the event loop. Since we're in the main + // thread, we don't need to do a notify. + ACE_Service_Config::end_reactorEx_event_loop (); + return -1; // Close down. +} + +// This is so the Proactor can get a message to read into. + +ACE_Message_Block * +Peer_Handler::get_message (void) +{ + // An extra byte for NUL termination. + ACE_Message_Block *message = + new ACE_Message_Block (BUFSIZ + 1); + + message->size (BUFSIZ); + return message; +} + +// This is so the Proactor can get our handle. +ACE_HANDLE +Peer_Handler::get_handle (void) const +{ + return this->stream_.get_handle (); +} + +// We've been removed from the ReactorEx. +int +Peer_Handler::handle_close (ACE_HANDLE, ACE_Reactor_Mask) +{ + ACE_DEBUG ((LM_DEBUG, "Peer_Handler closing down\n")); + return 0; +} + +// We've been signaled by the STDIN thread. Try to dequeue a +// message. + +int +Peer_Handler::handle_signal (int, siginfo_t *, ucontext_t *) +{ + this->try_send (); + return 0; +} + +// Try to dequeue a message. If successful, send it proactively to +// the remote peer. + +void +Peer_Handler::try_send (void) +{ + ACE_Message_Block *mb; + + ACE_Time_Value tv (ACE_Time_Value::zero); + + if (this->getq (mb, &tv) != -1) + { + if (ACE_Service_Config::proactor ()-> + initiate (this, ACE_Event_Handler::WRITE_MASK, mb) == -1) + ACE_ERROR ((LM_ERROR, "%p Write initiate.\n", "Peer_Handler")); + } +} + +// Enqueue the new mb and signal the main thread. + +int +Peer_Handler::put (ACE_Message_Block *mb, ACE_Time_Value *tv) +{ + // Enqueue the mb. + int result = this->putq (mb, tv); + + // Signal the main thread. This will remain signaled until the main + // thread wakes up. + + if (::SetEvent (new_msg_event_) == 0) + ACE_ERROR ((LM_ERROR, "Pulse Failed!\n")); + + return result; +} + +void +STDIN_Handler::handler (int signum) +{ + ACE_DEBUG ((LM_DEBUG, "signal = %S\n", signum)); +} + +STDIN_Handler::STDIN_Handler (MT_TASK &ph) + : ph_ (ph) +{ + // Register for ^C from the console. We just need to catch the + // exception so that the kernel doesn't kill our process. + // Registering this signal handler just tells the kernel that we + // know what we're doing; to leave us alone. + ACE_OS::signal (SIGINT, ACE_SignalHandler (STDIN_Handler::handler)); +}; + +// Activate object. + +int +STDIN_Handler::open (void *) +{ + if (this->activate (THR_NEW_LWP | THR_DETACHED) == -1) + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "spawn"), -1); + + return 0; +} + +// Shut down. + +int +STDIN_Handler::close (u_long) +{ + ACE_DEBUG ((LM_DEBUG, "(%t) thread is exiting.\n")); + return 0; +} + +// Thread runs here. + +int +STDIN_Handler::svc (void) +{ + this->register_thread_exit_hook (); + + for (;;) + { + ACE_Message_Block *mb = new ACE_Message_Block (BUFSIZ); + + // Read from stdin into mb. + int read_result = ACE_OS::read (ACE_STDIN, + mb->rd_ptr (), + mb->size ()); + + // If read succeeds, put mb to peer handler, else end the loop. + if (read_result > 0) + { + mb->wr_ptr (read_result); + this->ph_.put (mb); + } + else + break; + } + + // handle_signal will get called. + return 42; +} + +// Register an exit hook with the reactorEx. All this junk is testing +// out how ACE_Thread::self (hthread_id&) doesn't work!! + +void +STDIN_Handler::register_thread_exit_hook (void) +{ + ACE_hthread_t handle; + + // Get a real handle to our thread. + ACE_Service_Config::thr_mgr ()->thr_self (handle); + + // Register ourselves to get called back when our thread exits. + + if (ACE_Service_Config::reactorEx ()-> + register_handler (this, handle) == -1) + ACE_ERROR ((LM_ERROR, "Exit_Hook Register failed.\n")); + + // We're in another thread, so we need to notify the ReactorEx so + // that it wakes up and waits on the new set of handles. + ACE_Service_Config::reactorEx ()->notify (); +} + +// The STDIN thread has exited. This means the user hit ^C. We can +// end the event loop and delete ourself. + +int +STDIN_Handler::handle_signal (int, siginfo_t *, ucontext_t *) +{ + ACE_DEBUG ((LM_DEBUG, "STDIN thread has exited.\n")); + ACE_Service_Config::end_reactorEx_event_loop (); + return 0; +} + +int +main (int argc, char *argv[]) +{ + // Open handler for remote peer communications this will run from + // the main thread. + Peer_Handler peer_handler (argc, argv); + + if (peer_handler.open () == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p open failed, errno = %d.\n", + "peer_handler", errno), 0); + + // Open active object for reading from stdin. + STDIN_Handler stdin_handler (peer_handler); + + if (stdin_handler.open () == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p open failed, errno = %d.\n", + "stdin_handler", errno), 0); + + // Register proactor with ReactorEx so that we can demultiplex + // "waitable" events and I/O operations from a single thread. + if (ACE_Service_Config::reactorEx ()->register_handler + (ACE_Service_Config::proactor ()) != 0) + ACE_ERROR_RETURN ((LM_ERROR, "%p failed to register Proactor.\n", + argv[0]), -1); + + // Run main event demultiplexor. + ACE_Service_Config::run_reactorEx_event_loop (); + + return 42; +} diff --git a/examples/Reactor/WFMO_Reactor/test_remove_handler.cpp b/examples/Reactor/WFMO_Reactor/test_remove_handler.cpp new file mode 100644 index 00000000000..fb61519b1e9 --- /dev/null +++ b/examples/Reactor/WFMO_Reactor/test_remove_handler.cpp @@ -0,0 +1,94 @@ +// ============================================================================ +// @(#)test_remove_handler.cpp 1.1 10/18/96 + +// +// = LIBRARY +// examples +// +// = FILENAME +// test_remove_handler.cpp +// +// = DESCRIPTION +// Tests the ReactorEx's ability to handle simultaneous events. If +// you pass anything on the command-line, then each handler +// requests to be removed from the ReactorEx after each event. +// This has a funky effect on the order in which handlers are +// serviced. So, if no parameters are passed in, the handlers +// should be serviced 1 through MAXIMUM_WAIT_OBJECTS. If handlers +// to request to be removed as signals occur, they will be serviced +// 1, MAX, MAX-1, ..., 2. This is because of a ReactorEx +// bookkeeping optimization. +// +// = AUTHOR +// Tim Harrison +// +// ============================================================================ + +#include "ace/ReactorEx.h" +#include "ace/Service_Config.h" +#include "ace/Synch.h" + +class Event_Handler : public ACE_Event_Handler +// = TITLE +// Generic Event Handler. +// +// = DESCRIPTION +// +// Creates event. Registers with ReactorEx. Signals event. If +// created with -close_down- it returns -1 from handle signal. +{ +public: + Event_Handler (int event_number, + int close_down) + : event_number_ (event_number), + close_down_ (close_down) + { + ACE_Service_Config::reactorEx ()->register_handler (this, + this->event_.handle ()); + this->event_.signal (); + } + + virtual int handle_signal (int index, siginfo_t *, ucontext_t *) + { + ACE_DEBUG ((LM_DEBUG, "event %d occured.\n", event_number_)); + + if (this->close_down_) + return -1; + else + return 0; + } + + virtual int handle_close (ACE_HANDLE, ACE_Reactor_Mask) + { + // ACE_DEBUG ((LM_DEBUG, "event handler %d closed.\n", event_number_)); + delete this; + return 0; + } + + virtual ACE_HANDLE get_handle (void) const + { + return event_.handle (); + } + +private: + int event_number_; + // Our event number. + + int close_down_; + // Shall we close down or not. + + ACE_Event event_; + // Signaled to shut down the handler. +}; + +int +main (int argc, char *argv[]) +{ + int close_down = arg > 1 ? 1 : 0; + + for (int i = 0; i < ACE_ReactorEx::MAX_SIZE; i++) + new Event_Handler (i, close_down); + + ACE_Service_Config::reactorEx ()->handle_events (); + return 42; +} |