summaryrefslogtreecommitdiff
path: root/ACE/examples/Reactor
diff options
context:
space:
mode:
Diffstat (limited to 'ACE/examples/Reactor')
-rw-r--r--ACE/examples/Reactor/Dgram/.cvsignore4
-rw-r--r--ACE/examples/Reactor/Dgram/CODgram.cpp254
-rw-r--r--ACE/examples/Reactor/Dgram/Dgram.cpp258
-rw-r--r--ACE/examples/Reactor/Dgram/Makefile.am51
-rw-r--r--ACE/examples/Reactor/Dgram/Reactor_Dgram.mpc18
-rw-r--r--ACE/examples/Reactor/FIFO/.cvsignore4
-rw-r--r--ACE/examples/Reactor/FIFO/Makefile.am56
-rw-r--r--ACE/examples/Reactor/FIFO/Reactor_FIFO.mpc18
-rw-r--r--ACE/examples/Reactor/FIFO/client.cpp23
-rw-r--r--ACE/examples/Reactor/FIFO/server.cpp89
-rw-r--r--ACE/examples/Reactor/Makefile.am20
-rw-r--r--ACE/examples/Reactor/Misc/.cvsignore16
-rw-r--r--ACE/examples/Reactor/Misc/Makefile.am137
-rw-r--r--ACE/examples/Reactor/Misc/Reactor_Misc.mpc57
-rw-r--r--ACE/examples/Reactor/Misc/notification.cpp385
-rw-r--r--ACE/examples/Reactor/Misc/pingpong.cpp302
-rw-r--r--ACE/examples/Reactor/Misc/test_demuxing.cpp384
-rw-r--r--ACE/examples/Reactor/Misc/test_early_timeouts.cpp114
-rw-r--r--ACE/examples/Reactor/Misc/test_event_handler_t.cpp47
-rw-r--r--ACE/examples/Reactor/Misc/test_reactors.cpp195
-rw-r--r--ACE/examples/Reactor/Misc/test_signals_1.cpp114
-rw-r--r--ACE/examples/Reactor/Misc/test_signals_2.cpp291
-rw-r--r--ACE/examples/Reactor/Misc/test_time_value.cpp83
-rw-r--r--ACE/examples/Reactor/Misc/test_timer_queue.cpp115
-rw-r--r--ACE/examples/Reactor/Multicast/.cvsignore4
-rw-r--r--ACE/examples/Reactor/Multicast/Log_Wrapper.cpp81
-rw-r--r--ACE/examples/Reactor/Multicast/Log_Wrapper.h68
-rw-r--r--ACE/examples/Reactor/Multicast/Makefile.am50
-rw-r--r--ACE/examples/Reactor/Multicast/README15
-rw-r--r--ACE/examples/Reactor/Multicast/Reactor_Multicast.mpc17
-rw-r--r--ACE/examples/Reactor/Multicast/client.cpp126
-rw-r--r--ACE/examples/Reactor/Multicast/server.cpp247
-rw-r--r--ACE/examples/Reactor/Ntalker/.cvsignore2
-rw-r--r--ACE/examples/Reactor/Ntalker/Makefile.am33
-rw-r--r--ACE/examples/Reactor/Ntalker/README17
-rw-r--r--ACE/examples/Reactor/Ntalker/Reactor_Ntalker.mpc6
-rw-r--r--ACE/examples/Reactor/Ntalker/ntalker.cpp231
-rw-r--r--ACE/examples/Reactor/Proactor/.cvsignore7
-rw-r--r--ACE/examples/Reactor/Proactor/Aio_Platform_Test_C.cpp137
-rw-r--r--ACE/examples/Reactor/Proactor/Makefile.am153
-rw-r--r--ACE/examples/Reactor/Proactor/Proactor.mpc59
-rw-r--r--ACE/examples/Reactor/Proactor/README75
-rw-r--r--ACE/examples/Reactor/Proactor/post_completions.cpp306
-rw-r--r--ACE/examples/Reactor/Proactor/simple_test_proactor.cpp269
-rw-r--r--ACE/examples/Reactor/Proactor/test_aiocb.cpp239
-rw-r--r--ACE/examples/Reactor/Proactor/test_aiocb_ace.cpp259
-rw-r--r--ACE/examples/Reactor/Proactor/test_aiosig.cpp294
-rw-r--r--ACE/examples/Reactor/Proactor/test_aiosig_ace.cpp358
-rw-r--r--ACE/examples/Reactor/Proactor/test_cancel.cpp246
-rw-r--r--ACE/examples/Reactor/Proactor/test_cancel.h47
-rw-r--r--ACE/examples/Reactor/Proactor/test_end_event_loop.cpp168
-rw-r--r--ACE/examples/Reactor/Proactor/test_multiple_loops.cpp140
-rw-r--r--ACE/examples/Reactor/Proactor/test_proactor.cpp679
-rw-r--r--ACE/examples/Reactor/Proactor/test_proactor.h56
-rw-r--r--ACE/examples/Reactor/Proactor/test_proactor2.cpp808
-rw-r--r--ACE/examples/Reactor/Proactor/test_proactor3.cpp864
-rw-r--r--ACE/examples/Reactor/Proactor/test_timeout.cpp130
-rw-r--r--ACE/examples/Reactor/Proactor/test_timeout_st.cpp99
-rw-r--r--ACE/examples/Reactor/Proactor/test_udp_proactor.cpp432
-rw-r--r--ACE/examples/Reactor/README20
-rw-r--r--ACE/examples/Reactor/TP_Reactor/AcceptHandler.cpp106
-rw-r--r--ACE/examples/Reactor/TP_Reactor/AcceptHandler.h75
-rw-r--r--ACE/examples/Reactor/TP_Reactor/Makefile.am53
-rw-r--r--ACE/examples/Reactor/TP_Reactor/README86
-rw-r--r--ACE/examples/Reactor/TP_Reactor/ReadHandler.cpp151
-rw-r--r--ACE/examples/Reactor/TP_Reactor/ReadHandler.h92
-rw-r--r--ACE/examples/Reactor/TP_Reactor/TP_Reactor.mpc18
-rw-r--r--ACE/examples/Reactor/TP_Reactor/client.cpp141
-rw-r--r--ACE/examples/Reactor/TP_Reactor/common.h29
-rw-r--r--ACE/examples/Reactor/TP_Reactor/run_test.pl41
-rw-r--r--ACE/examples/Reactor/TP_Reactor/server.cpp66
-rw-r--r--ACE/examples/Reactor/WFMO_Reactor/APC.cpp124
-rw-r--r--ACE/examples/Reactor/WFMO_Reactor/Abandoned.cpp141
-rw-r--r--ACE/examples/Reactor/WFMO_Reactor/Console_Input.cpp87
-rw-r--r--ACE/examples/Reactor/WFMO_Reactor/Directory_Changes.cpp128
-rw-r--r--ACE/examples/Reactor/WFMO_Reactor/Exceptions.cpp109
-rw-r--r--ACE/examples/Reactor/WFMO_Reactor/Handle_Close.cpp333
-rw-r--r--ACE/examples/Reactor/WFMO_Reactor/Makefile.am308
-rw-r--r--ACE/examples/Reactor/WFMO_Reactor/Multithreading.cpp262
-rw-r--r--ACE/examples/Reactor/WFMO_Reactor/Network_Events.cpp211
-rw-r--r--ACE/examples/Reactor/WFMO_Reactor/Prerun_State_Changes.cpp66
-rw-r--r--ACE/examples/Reactor/WFMO_Reactor/Registration.cpp169
-rw-r--r--ACE/examples/Reactor/WFMO_Reactor/Registry_Changes.cpp146
-rw-r--r--ACE/examples/Reactor/WFMO_Reactor/Removals.cpp114
-rw-r--r--ACE/examples/Reactor/WFMO_Reactor/Suspended_Removals.cpp173
-rw-r--r--ACE/examples/Reactor/WFMO_Reactor/Talker.cpp594
-rw-r--r--ACE/examples/Reactor/WFMO_Reactor/Timeouts.cpp83
-rw-r--r--ACE/examples/Reactor/WFMO_Reactor/WFMO_Reactor.mpc118
-rw-r--r--ACE/examples/Reactor/WFMO_Reactor/Window_Messages.cpp100
-rwxr-xr-xACE/examples/Reactor/WFMO_Reactor/run_test.pl68
90 files changed, 13969 insertions, 0 deletions
diff --git a/ACE/examples/Reactor/Dgram/.cvsignore b/ACE/examples/Reactor/Dgram/.cvsignore
new file mode 100644
index 00000000000..94126b14c4e
--- /dev/null
+++ b/ACE/examples/Reactor/Dgram/.cvsignore
@@ -0,0 +1,4 @@
+codgram
+codgram
+dgram
+dgram
diff --git a/ACE/examples/Reactor/Dgram/CODgram.cpp b/ACE/examples/Reactor/Dgram/CODgram.cpp
new file mode 100644
index 00000000000..f423c43fb8c
--- /dev/null
+++ b/ACE/examples/Reactor/Dgram/CODgram.cpp
@@ -0,0 +1,254 @@
+// $Id$
+
+// Exercise the <ACE_SOCK_CODgram> wrapper along with the
+// <ACE_Reactor>. This test simply ping-pongs datagrams back and
+// forth between the peer1 and peer2 processes. This test can
+// be run in two ways:
+//
+// 1. Stand-alone -- e.g.,
+//
+// % ./CODgram
+//
+// which will spawn a child process and run peer1 and peer2
+// in different processes on the same machine.
+//
+// 2. Distributed -- e.g.,
+//
+// # Peer1
+// % ./CODgram 10002 tango.cs.wustl.edu 10003 peer1
+//
+// # Peer1
+// % ./CODgram 10003 tango.cs.wustl.edu 10002 peer2
+//
+// which will run peer1 and peer2 in different processes
+// on the same or different machines. Note that you MUST
+// give the name "peer1" as the final argument to one and
+// only one of the programs so that the test will work properly.
+
+#include "ace/OS_main.h"
+#include "ace/OS_NS_string.h"
+#include "ace/OS_NS_unistd.h"
+#include "ace/Reactor.h"
+#include "ace/SOCK_CODgram.h"
+#include "ace/INET_Addr.h"
+#include "ace/Process.h"
+#include "ace/Log_Msg.h"
+
+ACE_RCSID(Dgram, CODgram, "$Id$")
+
+// Port used to receive for dgrams.
+static u_short port1;
+
+class Dgram_Endpoint : public ACE_Event_Handler
+{
+public:
+ Dgram_Endpoint (const ACE_INET_Addr &remote_addr,
+ const ACE_INET_Addr &local_addr);
+
+ // = Hook methods inherited from the <ACE_Event_Handler>.
+ 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);
+
+ virtual int handle_close (ACE_HANDLE handle,
+ ACE_Reactor_Mask close_mask);
+
+ int send (const char *buf, size_t len);
+ // Send the <buf> to the peer.
+
+private:
+ ACE_SOCK_CODgram endpoint_;
+ // Wrapper for sending/receiving dgrams.
+};
+
+int
+Dgram_Endpoint::send (const char *buf, size_t len)
+{
+ return this->endpoint_.send (buf, len);
+}
+
+int
+Dgram_Endpoint::handle_close (ACE_HANDLE handle,
+ ACE_Reactor_Mask)
+{
+ ACE_UNUSED_ARG (handle);
+
+ this->endpoint_.close ();
+ return 0;
+}
+
+Dgram_Endpoint::Dgram_Endpoint (const ACE_INET_Addr &remote_addr,
+ const ACE_INET_Addr &local_addr)
+ : endpoint_ (remote_addr, local_addr)
+{
+}
+
+ACE_HANDLE
+Dgram_Endpoint::get_handle (void) const
+{
+ return this->endpoint_.get_handle ();
+}
+
+int
+Dgram_Endpoint::handle_input (ACE_HANDLE)
+{
+ char buf[BUFSIZ];
+
+ ACE_DEBUG ((LM_DEBUG,
+ "(%P|%t) activity occurred on handle %d!\n",
+ this->endpoint_.get_handle ()));
+
+ ssize_t n = this->endpoint_.recv (buf, sizeof buf);
+
+ if (n == -1)
+ ACE_ERROR ((LM_ERROR,
+ "%p\n",
+ "handle_input"));
+ else
+ ACE_DEBUG ((LM_DEBUG,
+ "(%P|%t) buf of size %d = %*s\n",
+ n, n, buf));
+ return 0;
+}
+
+int
+Dgram_Endpoint::handle_timeout (const ACE_Time_Value &,
+ const void *)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ "(%P|%t) timed out for endpoint\n"));
+ return 0;
+}
+
+static int
+run_test (u_short localport,
+ const ACE_TCHAR *remotehost,
+ u_short remoteport,
+ const ACE_TCHAR *peer)
+{
+ ACE_INET_Addr remote_addr (remoteport,
+ remotehost);
+ ACE_INET_Addr local_addr (localport);
+
+ Dgram_Endpoint endpoint (remote_addr, local_addr);
+
+ // Read data from other side.
+ if (ACE_Reactor::instance ()->register_handler
+ (&endpoint,
+ ACE_Event_Handler::READ_MASK) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "ACE_Reactor::register_handler"),
+ -1);
+ char buf[BUFSIZ];
+ ACE_OS::strcpy (buf,
+ "Data to transmit");
+ size_t len = ACE_OS::strlen (buf);
+
+ // "peer1" is the "initiator."
+ if (ACE_OS::strncmp (peer, ACE_TEXT("peer1"), 5) == 0)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ "(%P|%t) sending data\n"));
+ for (size_t i = 0; i < 20; i++)
+ {
+ endpoint.send (buf, len);
+ ACE_DEBUG ((LM_DEBUG,
+ "(%P|%t) .\n"));
+ ACE_OS::sleep (1);
+ }
+ }
+
+ for (int i = 0; i < 40; i++)
+ {
+ // Wait up to 10 seconds for data.
+ ACE_Time_Value tv (10, 0);
+
+ if (ACE_Reactor::instance ()->handle_events (tv) <= 0)
+ ACE_ERROR_RETURN ((LM_DEBUG,
+ "(%P|%t) %p\n",
+ "handle_events"),
+ -1);
+ ACE_DEBUG ((LM_DEBUG,
+ "(%P|%t) return from handle events\n"));
+
+ endpoint.send (buf, len);
+
+ ACE_DEBUG ((LM_DEBUG,
+ "(%P|%t) .\n"));
+ }
+
+ if (ACE_Reactor::instance ()->remove_handler
+ (&endpoint,
+ ACE_Event_Handler::READ_MASK) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "ACE_Reactor::remove_handler"),
+ -1);
+ ACE_DEBUG ((LM_DEBUG,
+ "(%P|%t) exiting\n"));
+ return 0;
+}
+
+int
+ACE_TMAIN (int argc, ACE_TCHAR *argv[])
+{
+ // Estabish call backs and socket names.
+
+ port1 = argc > 1 ? ACE_OS::atoi (argv[1]) : ACE_DEFAULT_SERVER_PORT;
+ const ACE_TCHAR *remotehost = argc > 2 ? argv[2] : ACE_DEFAULT_SERVER_HOST;
+ const u_short port2 = argc > 3 ? ACE_OS::atoi (argv[3]) : port1 + 1;
+
+ // Providing the fourth command line argument indicates we don't
+ // want to spawn a new process. On Win32, we use this to exec the
+ // new program.
+ if (argc > 4)
+ run_test (port1,
+ remotehost,
+ port2,
+ argv[4]);
+ else
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ "(%P|%t) local port = %d, remote host = %s, remote port = %d\n",
+ port1,
+ remotehost,
+ port2));
+
+ ACE_Process_Options options;
+ options.command_line ("%s %d %s %d %c",
+ argv[0],
+ port1,
+ remotehost,
+ port2,
+ 'c');
+
+ // This has no effect on NT and will spawn a process that exec
+ // the above run_test function.
+ options.creation_flags (ACE_Process_Options::NO_EXEC);
+
+ ACE_Process new_process;
+
+ switch (new_process.spawn (options))
+ {
+ case -1:
+ return -1;
+
+ case 0:
+ run_test (port1,
+ remotehost,
+ port2,
+ ACE_TEXT("peer1"));
+ break;
+
+ default:
+ run_test (port2,
+ remotehost,
+ port1,
+ ACE_TEXT("peer2"));
+ new_process.wait ();
+ break;
+ }
+ }
+
+ return 0;
+}
diff --git a/ACE/examples/Reactor/Dgram/Dgram.cpp b/ACE/examples/Reactor/Dgram/Dgram.cpp
new file mode 100644
index 00000000000..c4c21e84186
--- /dev/null
+++ b/ACE/examples/Reactor/Dgram/Dgram.cpp
@@ -0,0 +1,258 @@
+// $Id$
+
+// Exercise the <ACE_SOCK_Dgram> wrapper along with the <ACE_Reactor>.
+// This test simply ping-pongs datagrams back and forth between the
+// peer1 and peer2 processes. This test can be run in two ways:
+//
+// 1. Stand-alone -- e.g.,
+//
+// % ./Dgram
+//
+// which will spawn a child process and run peer1 and peer2
+// in different processes on the same machine.
+//
+// 2. Distributed -- e.g.,
+//
+// # Peer1
+// % ./Dgram 10002 tango.cs.wustl.edu 10003 peer1
+//
+// # Peer1
+// % ./Dgram 10003 tango.cs.wustl.edu 10002 peer2
+//
+// which will run peer1 and peer2 in different processes
+// on the same or different machines. Note that you MUST
+// give the name "peer1" as the final argument to one and
+// only one of the programs so that the test will work properly.
+
+#include "ace/OS_main.h"
+#include "ace/OS_NS_string.h"
+#include "ace/OS_NS_unistd.h"
+#include "ace/Reactor.h"
+#include "ace/Process.h"
+#include "ace/SOCK_Dgram.h"
+#include "ace/INET_Addr.h"
+#include "ace/Log_Msg.h"
+
+ACE_RCSID(Dgram, Dgram, "$Id$")
+
+// Port used to receive for dgrams.
+static u_short port1;
+
+class Dgram_Endpoint : public ACE_Event_Handler
+{
+public:
+ Dgram_Endpoint (const ACE_INET_Addr &local_addr);
+
+ // = Hook methods inherited from the <ACE_Event_Handler>.
+ 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);
+ virtual int handle_close (ACE_HANDLE handle,
+ ACE_Reactor_Mask close_mask);
+
+ int send (const char *buf, size_t len, const ACE_INET_Addr &);
+ // Send the <buf> to the peer.
+
+private:
+ ACE_SOCK_Dgram endpoint_;
+ // Wrapper for sending/receiving dgrams.
+};
+
+int
+Dgram_Endpoint::send (const char *buf,
+ size_t len,
+ const ACE_INET_Addr &addr)
+{
+ return this->endpoint_.send (buf, len, addr);
+}
+
+Dgram_Endpoint::Dgram_Endpoint (const ACE_INET_Addr &local_addr)
+ : endpoint_ (local_addr)
+{
+}
+
+ACE_HANDLE
+Dgram_Endpoint::get_handle (void) const
+{
+ return this->endpoint_.get_handle ();
+}
+
+int
+Dgram_Endpoint::handle_close (ACE_HANDLE handle,
+ ACE_Reactor_Mask)
+{
+ ACE_UNUSED_ARG (handle);
+
+ this->endpoint_.close ();
+ delete this;
+ return 0;
+}
+
+int
+Dgram_Endpoint::handle_input (ACE_HANDLE)
+{
+ char buf[BUFSIZ];
+ ACE_INET_Addr from_addr;
+
+ ACE_DEBUG ((LM_DEBUG,
+ "(%P|%t) activity occurred on handle %d!\n",
+ this->endpoint_.get_handle ()));
+
+ ssize_t n = this->endpoint_.recv (buf,
+ sizeof buf,
+ from_addr);
+
+ if (n == -1)
+ ACE_ERROR ((LM_ERROR,
+ "%p\n",
+ "handle_input"));
+ else
+ ACE_DEBUG ((LM_DEBUG,
+ "(%P|%t) buf of size %d = %*s\n",
+ n,
+ n,
+ buf));
+ return 0;
+}
+
+int
+Dgram_Endpoint::handle_timeout (const ACE_Time_Value &,
+ const void *)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ "(%P|%t) timed out for endpoint\n"));
+ return 0;
+}
+
+static int
+run_test (u_short localport,
+ const ACE_TCHAR *remotehost,
+ u_short remoteport,
+ const ACE_TCHAR *peer)
+{
+ ACE_INET_Addr remote_addr (remoteport,
+ remotehost);
+ ACE_INET_Addr local_addr (localport);
+
+ Dgram_Endpoint *endpoint;
+
+ ACE_NEW_RETURN (endpoint,
+ Dgram_Endpoint (local_addr),
+ -1);
+
+ // Read data from other side.
+ if (ACE_Reactor::instance ()->register_handler
+ (endpoint,
+ ACE_Event_Handler::READ_MASK) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "ACE_Reactor::register_handler"),
+ -1);
+
+ char buf[BUFSIZ];
+ ACE_OS::strcpy (buf, "Data to transmit");
+ size_t len = ACE_OS::strlen (buf);
+
+ if (ACE_OS::strncmp (peer, ACE_TEXT("peer1"), 5) == 0)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ "(%P|%t) sending data\n"));
+
+ for (size_t i = 0; i < 20; i++)
+ {
+ endpoint->send (buf, len, remote_addr);
+ ACE_DEBUG ((LM_DEBUG,
+ "(%P|%t) .\n"));
+ ACE_OS::sleep (1);
+ }
+ }
+
+ for (int i = 0; i < 40; i++)
+ {
+ // Wait up to 10 seconds for data.
+ ACE_Time_Value tv (10, 0);
+
+ if (ACE_Reactor::instance ()->handle_events (tv) <= 0)
+ ACE_ERROR_RETURN ((LM_DEBUG,
+ "(%P|%t) %p\n",
+ "handle_events"),
+ -1);
+
+ ACE_DEBUG ((LM_DEBUG,
+ "(%P|%t) return from handle events\n"));
+
+ endpoint->send (buf, len, remote_addr);
+
+ ACE_DEBUG ((LM_DEBUG,
+ "(%P|%t) .\n"));
+ }
+
+ if (ACE_Reactor::instance ()->remove_handler
+ (endpoint,
+ ACE_Event_Handler::READ_MASK) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "ACE_Reactor::remove_handler"),
+ -1);
+ ACE_DEBUG ((LM_DEBUG,
+ "(%P|%t) exiting\n"));
+ return 0;
+}
+
+int
+ACE_TMAIN (int argc, ACE_TCHAR *argv[])
+{
+ // Estabish call backs and socket names.
+
+ port1 = argc > 1 ? ACE_OS::atoi (argv[1]) : ACE_DEFAULT_SERVER_PORT;
+ const ACE_TCHAR *remotehost = argc > 2 ? argv[2] : ACE_DEFAULT_SERVER_HOST;
+ const u_short port2 = argc > 3 ? ACE_OS::atoi (argv[3]) : port1 + 1;
+
+ // Providing the fourth command line argument indicate we don't want
+ // to spawn a new process. On Win32, we use this to exec the new
+ // program.
+ if (argc > 4)
+ run_test (port1, remotehost, port2, argv[4]);
+ else
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ "(%P|%t) local port = %d, remote host = %s, remote port = %d\n",
+ port1,
+ remotehost,
+ port2));
+
+ ACE_Process_Options options;
+ options.command_line ("%s %d %s %d %c",
+ argv[0],
+ port1,
+ remotehost,
+ port2,
+ 'c');
+
+ // This has no effect on NT and will spawn a process that exec
+ // the above run_test function.
+ options.creation_flags (ACE_Process_Options::NO_EXEC);
+
+ ACE_Process new_process;
+ switch (new_process.spawn (options))
+ {
+ case -1:
+ return -1;
+
+ case 0:
+ run_test (port1,
+ remotehost,
+ port2,
+ ACE_TEXT("peer1"));
+ break;
+
+ default:
+ run_test (port2,
+ remotehost,
+ port1,
+ ACE_TEXT("peer2"));
+ new_process.wait ();
+ break;
+ }
+ }
+ return 0;
+}
diff --git a/ACE/examples/Reactor/Dgram/Makefile.am b/ACE/examples/Reactor/Dgram/Makefile.am
new file mode 100644
index 00000000000..797f4b3d75e
--- /dev/null
+++ b/ACE/examples/Reactor/Dgram/Makefile.am
@@ -0,0 +1,51 @@
+## Process this file with automake to create Makefile.in
+##
+## $Id$
+##
+## This file was generated by MPC. Any changes made directly to
+## this file will be lost the next time it is generated.
+##
+## MPC Command:
+## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu
+
+ACE_BUILDDIR = $(top_builddir)
+ACE_ROOT = $(top_srcdir)
+
+
+## Makefile.Reactor_Dgram.am
+noinst_PROGRAMS = dgram
+
+dgram_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+dgram_SOURCES = \
+ Dgram.cpp
+
+dgram_LDADD = \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.Reactor_Dgram_CO.am
+
+if !BUILD_ACE_FOR_TAO
+noinst_PROGRAMS += codgram
+
+codgram_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+codgram_SOURCES = \
+ CODgram.cpp
+
+codgram_LDADD = \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_ACE_FOR_TAO
+
+## Clean up template repositories, etc.
+clean-local:
+ -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.*
+ -rm -f gcctemp.c gcctemp so_locations *.ics
+ -rm -rf cxx_repository ptrepository ti_files
+ -rm -rf templateregistry ir.out
+ -rm -rf ptrepository SunWS_cache Templates.DB
diff --git a/ACE/examples/Reactor/Dgram/Reactor_Dgram.mpc b/ACE/examples/Reactor/Dgram/Reactor_Dgram.mpc
new file mode 100644
index 00000000000..1040aedc184
--- /dev/null
+++ b/ACE/examples/Reactor/Dgram/Reactor_Dgram.mpc
@@ -0,0 +1,18 @@
+// -*- MPC -*-
+// $Id$
+
+project(*CO) : aceexe {
+ avoids += ace_for_tao
+ exename = codgram
+ Source_Files {
+ CODgram.cpp
+ }
+}
+
+project : aceexe {
+ exename = dgram
+ Source_Files {
+ Dgram.cpp
+ }
+}
+
diff --git a/ACE/examples/Reactor/FIFO/.cvsignore b/ACE/examples/Reactor/FIFO/.cvsignore
new file mode 100644
index 00000000000..955ffdc75d5
--- /dev/null
+++ b/ACE/examples/Reactor/FIFO/.cvsignore
@@ -0,0 +1,4 @@
+client
+client
+server
+server
diff --git a/ACE/examples/Reactor/FIFO/Makefile.am b/ACE/examples/Reactor/FIFO/Makefile.am
new file mode 100644
index 00000000000..5540e860968
--- /dev/null
+++ b/ACE/examples/Reactor/FIFO/Makefile.am
@@ -0,0 +1,56 @@
+## Process this file with automake to create Makefile.in
+##
+## $Id$
+##
+## This file was generated by MPC. Any changes made directly to
+## this file will be lost the next time it is generated.
+##
+## MPC Command:
+## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu
+
+ACE_BUILDDIR = $(top_builddir)
+ACE_ROOT = $(top_srcdir)
+
+noinst_PROGRAMS =
+
+## Makefile.Reactor_FIFO_Client.am
+
+if !BUILD_ACE_FOR_TAO
+noinst_PROGRAMS += client
+
+client_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+client_SOURCES = \
+ client.cpp
+
+client_LDADD = \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_ACE_FOR_TAO
+
+## Makefile.Reactor_FIFO_Server.am
+
+if !BUILD_ACE_FOR_TAO
+noinst_PROGRAMS += server
+
+server_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+server_SOURCES = \
+ server.cpp
+
+server_LDADD = \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_ACE_FOR_TAO
+
+## Clean up template repositories, etc.
+clean-local:
+ -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.*
+ -rm -f gcctemp.c gcctemp so_locations *.ics
+ -rm -rf cxx_repository ptrepository ti_files
+ -rm -rf templateregistry ir.out
+ -rm -rf ptrepository SunWS_cache Templates.DB
diff --git a/ACE/examples/Reactor/FIFO/Reactor_FIFO.mpc b/ACE/examples/Reactor/FIFO/Reactor_FIFO.mpc
new file mode 100644
index 00000000000..072ec5412b8
--- /dev/null
+++ b/ACE/examples/Reactor/FIFO/Reactor_FIFO.mpc
@@ -0,0 +1,18 @@
+// -*- MPC -*-
+// $Id$
+
+project(*client) : aceexe {
+ avoids += ace_for_tao
+ exename = client
+ Source_Files {
+ client.cpp
+ }
+}
+
+project(*server) : aceexe {
+ avoids += ace_for_tao
+ exename = server
+ Source_Files {
+ server.cpp
+ }
+}
diff --git a/ACE/examples/Reactor/FIFO/client.cpp b/ACE/examples/Reactor/FIFO/client.cpp
new file mode 100644
index 00000000000..daa8d3304ad
--- /dev/null
+++ b/ACE/examples/Reactor/FIFO/client.cpp
@@ -0,0 +1,23 @@
+// $Id$
+
+#include "ace/FIFO_Send_Msg.h"
+#include "ace/Log_Msg.h"
+#include "ace/OS_NS_stropts.h"
+
+ACE_RCSID(FIFO, client, "$Id$")
+
+int
+ACE_TMAIN (int, ACE_TCHAR *[])
+{
+ char buf[] = "hello world";
+ ACE_Str_Buf msg (buf, sizeof buf);
+
+ ACE_FIFO_Send_Msg fifo_sender (ACE_DEFAULT_RENDEZVOUS,
+ O_WRONLY | O_CREAT,
+ ACE_DEFAULT_FILE_PERMS);
+
+ if (fifo_sender.send (msg) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "send error for fifo"), -1);
+ else
+ return 0;
+}
diff --git a/ACE/examples/Reactor/FIFO/server.cpp b/ACE/examples/Reactor/FIFO/server.cpp
new file mode 100644
index 00000000000..b6e91dd5046
--- /dev/null
+++ b/ACE/examples/Reactor/FIFO/server.cpp
@@ -0,0 +1,89 @@
+// $Id$
+
+#include "ace/Service_Config.h"
+#include "ace/Reactor.h"
+#include "ace/Event_Handler.h"
+#include "ace/FIFO_Recv_Msg.h"
+#include "ace/Log_Msg.h"
+#include "ace/OS_NS_unistd.h"
+#include "ace/OS_NS_stropts.h"
+
+ACE_RCSID(FIFO, server, "$Id$")
+
+class FIFO_Recv_Handler : public ACE_Event_Handler
+{
+public:
+ FIFO_Recv_Handler (void);
+ ~FIFO_Recv_Handler (void);
+
+ virtual ACE_HANDLE get_handle (void) const;
+ virtual int handle_input (ACE_HANDLE fd);
+
+private:
+ ACE_FIFO_Recv_Msg fifo_reader_;
+};
+
+FIFO_Recv_Handler::FIFO_Recv_Handler (void)
+{
+ ACE_OS::unlink (ACE_DEFAULT_RENDEZVOUS);
+
+ // Make sure to open the FIFO with the "persistent" flag enabled
+ // (which is the default).
+ if (this->fifo_reader_.open (ACE_DEFAULT_RENDEZVOUS) == -1)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("open")));
+
+ // Register with the Reactor.
+ if (ACE_Reactor::instance ()->register_handler
+ (this, ACE_Event_Handler::READ_MASK) == -1)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("register_handler")));
+}
+
+ACE_HANDLE
+FIFO_Recv_Handler::get_handle (void) const
+{
+ return this->fifo_reader_.get_handle ();
+}
+
+FIFO_Recv_Handler::~FIFO_Recv_Handler (void)
+{
+ this->fifo_reader_.close ();
+ this->fifo_reader_.remove ();
+}
+
+int
+FIFO_Recv_Handler::handle_input (ACE_HANDLE)
+{
+ char buf[BUFSIZ];
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("handle_input\n")));
+
+ ACE_Str_Buf msg (buf, 0, sizeof buf);
+
+ ssize_t n = this->fifo_reader_.recv (msg);
+
+ if (n < 0)
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("recv")), -1);
+ else
+ {
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("msg.len = %d, n = %d\n"), msg.len, n));
+
+ if (msg.len > 0)
+ {
+ // Do some work in here...
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("msg.buf = %C\n"), msg.buf));
+ }
+ return 0;
+ }
+}
+
+int
+ACE_TMAIN (int, ACE_TCHAR *argv[])
+{
+ ACE_Service_Config daemon (argv[0]);
+
+ FIFO_Recv_Handler fr_handler;
+
+ ACE_Reactor::instance ()->run_reactor_event_loop ();
+
+ return 0;
+}
diff --git a/ACE/examples/Reactor/Makefile.am b/ACE/examples/Reactor/Makefile.am
new file mode 100644
index 00000000000..24d9217302d
--- /dev/null
+++ b/ACE/examples/Reactor/Makefile.am
@@ -0,0 +1,20 @@
+## Process this file with automake to create Makefile.in
+##
+## $Id$
+##
+## This file was generated by MPC. Any changes made directly to
+## this file will be lost the next time it is generated.
+##
+## MPC Command:
+## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu
+
+SUBDIRS = \
+ Dgram \
+ FIFO \
+ Misc \
+ Multicast \
+ Ntalker \
+ Proactor \
+ TP_Reactor \
+ WFMO_Reactor
+
diff --git a/ACE/examples/Reactor/Misc/.cvsignore b/ACE/examples/Reactor/Misc/.cvsignore
new file mode 100644
index 00000000000..f7cc1865efa
--- /dev/null
+++ b/ACE/examples/Reactor/Misc/.cvsignore
@@ -0,0 +1,16 @@
+demuxing
+demuxing
+early_timeouts
+early_timeouts
+notification
+notification
+pingpong
+pingpong
+reactors
+reactors
+signals_1
+signals_1
+signals_2
+signals_2
+timer_queue
+timer_queue
diff --git a/ACE/examples/Reactor/Misc/Makefile.am b/ACE/examples/Reactor/Misc/Makefile.am
new file mode 100644
index 00000000000..47111585f87
--- /dev/null
+++ b/ACE/examples/Reactor/Misc/Makefile.am
@@ -0,0 +1,137 @@
+## Process this file with automake to create Makefile.in
+##
+## $Id$
+##
+## This file was generated by MPC. Any changes made directly to
+## this file will be lost the next time it is generated.
+##
+## MPC Command:
+## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu
+
+ACE_BUILDDIR = $(top_builddir)
+ACE_ROOT = $(top_srcdir)
+
+## Makefile.Reactor_Misc_Demuxing.am
+noinst_PROGRAMS = demuxing
+
+demuxing_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+demuxing_SOURCES = \
+ test_demuxing.cpp
+
+demuxing_LDADD = \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.Reactor_Misc_Early_Timeouts.am
+noinst_PROGRAMS += early_timeouts
+
+early_timeouts_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+early_timeouts_SOURCES = \
+ test_early_timeouts.cpp
+
+early_timeouts_LDADD = \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.Reactor_Misc_Event_Handler_t.am
+noinst_PROGRAMS += event_handler_t
+
+event_handler_t_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+event_handler_t_SOURCES = \
+ test_event_handler_t.cpp
+
+event_handler_t_LDADD = \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.Reactor_Misc_Notification.am
+noinst_PROGRAMS += notification
+
+notification_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+notification_SOURCES = \
+ notification.cpp
+
+notification_LDADD = \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.Reactor_Misc_Pingpong.am
+noinst_PROGRAMS += pingpong
+
+pingpong_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+pingpong_SOURCES = \
+ pingpong.cpp
+
+pingpong_LDADD = \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.Reactor_Misc_Reactors.am
+noinst_PROGRAMS += reactors
+
+reactors_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+reactors_SOURCES = \
+ test_reactors.cpp
+
+reactors_LDADD = \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.Reactor_Misc_Signals_1.am
+noinst_PROGRAMS += signals_1
+
+signals_1_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+signals_1_SOURCES = \
+ test_signals_1.cpp
+
+signals_1_LDADD = \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.Reactor_Misc_Signals_2.am
+noinst_PROGRAMS += signals_2
+
+signals_2_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+signals_2_SOURCES = \
+ test_signals_2.cpp
+
+signals_2_LDADD = \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.Reactor_Misc_Timer_Queue.am
+noinst_PROGRAMS += timer_queue
+
+timer_queue_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+timer_queue_SOURCES = \
+ test_timer_queue.cpp
+
+timer_queue_LDADD = \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Clean up template repositories, etc.
+clean-local:
+ -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.*
+ -rm -f gcctemp.c gcctemp so_locations *.ics
+ -rm -rf cxx_repository ptrepository ti_files
+ -rm -rf templateregistry ir.out
+ -rm -rf ptrepository SunWS_cache Templates.DB
diff --git a/ACE/examples/Reactor/Misc/Reactor_Misc.mpc b/ACE/examples/Reactor/Misc/Reactor_Misc.mpc
new file mode 100644
index 00000000000..c056a909bd8
--- /dev/null
+++ b/ACE/examples/Reactor/Misc/Reactor_Misc.mpc
@@ -0,0 +1,57 @@
+// -*- MPC -*-
+// $Id$
+
+project(*event_handler_t) : aceexe {
+ exename = event_handler_t
+ Source_Files {
+ test_event_handler_t.cpp
+ }
+}
+project(*demuxing) : aceexe {
+ exename = demuxing
+ Source_Files {
+ test_demuxing.cpp
+ }
+}
+project(*early_timeouts) : aceexe {
+ exename = early_timeouts
+ Source_Files {
+ test_early_timeouts.cpp
+ }
+}
+project(*notification) : aceexe {
+ exename = notification
+ Source_Files {
+ notification.cpp
+ }
+}
+project(*pingpong) : aceexe {
+ exename = pingpong
+ Source_Files {
+ pingpong.cpp
+ }
+}
+project(*reactors) : aceexe {
+ exename = reactors
+ Source_Files {
+ test_reactors.cpp
+ }
+}
+project(*signals_1) : aceexe {
+ exename = signals_1
+ Source_Files {
+ test_signals_1.cpp
+ }
+}
+project(*signals_2) : aceexe {
+ exename = signals_2
+ Source_Files {
+ test_signals_2.cpp
+ }
+}
+project(*timer_queue) : aceexe {
+ exename = timer_queue
+ Source_Files {
+ test_timer_queue.cpp
+ }
+}
diff --git a/ACE/examples/Reactor/Misc/notification.cpp b/ACE/examples/Reactor/Misc/notification.cpp
new file mode 100644
index 00000000000..a04663b28ad
--- /dev/null
+++ b/ACE/examples/Reactor/Misc/notification.cpp
@@ -0,0 +1,385 @@
+// $Id$
+
+#include "ace/OS_NS_unistd.h"
+#include "ace/Service_Config.h"
+#include "ace/Reactor.h"
+#include "ace/Thread_Manager.h"
+#include "ace/Thread.h"
+#include "ace/Signal.h"
+
+ACE_RCSID(Misc, notification, "$Id$")
+
+#if defined (ACE_HAS_THREADS)
+#if defined (CHORUS)
+// Chorus does not have signal, so we'll stop after a number of rounds.
+#define MAX_ITERATIONS 3
+#else
+#define MAX_ITERATIONS 10000
+#endif /* CHORUS */
+
+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 (long delay,
+ long interval,
+ size_t n_threads,
+ size_t max_iterations);
+ // Constructor.
+
+ Thread_Handler (size_t id,
+ size_t max_iterations);
+
+ ~Thread_Handler (void);
+ // Destructor.
+
+ 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 (ACE_Time_Value *tv = 0);
+ // 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.
+
+ size_t iterations_;
+
+ static sig_atomic_t shutdown_;
+ // Shutting down.
+
+ // = 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_;
+};
+
+// Shutdown flag.
+sig_atomic_t Thread_Handler::shutdown_ = 0;
+
+// 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 (size_t id,
+ size_t max_iterations)
+ : id_ (id),
+ iterations_ (max_iterations)
+{
+}
+
+Thread_Handler::~Thread_Handler (void)
+{
+ // Cleanup resources so that we don't crash and burn when shutdown.
+ ACE_Event_Handler::remove_stdin_handler (ACE_Reactor::instance (),
+ ACE_Thread_Manager::instance ());
+ ACE_Reactor::instance ()->cancel_timer (this);
+}
+
+Thread_Handler::Thread_Handler (
+ long delay,
+ long interval,
+ size_t n_threads,
+ size_t max_iterations)
+ : iterations_ (max_iterations)
+{
+ ACE_Sig_Set sig_set;
+
+ sig_set.sig_add (SIGQUIT);
+ sig_set.sig_add (SIGINT);
+
+ delay_.set (delay);
+ interval_.set (interval);
+ this->id_ = 0;
+
+ if (ACE_Event_Handler::register_stdin_handler (this,
+ ACE_Reactor::instance (),
+ ACE_Thread_Manager::instance ()) == -1)
+ ACE_ERROR ((LM_ERROR,
+ "%p\n",
+ "register_stdin_handler"));
+ else if (ACE_Reactor::instance ()->register_handler (sig_set,
+ this) == -1)
+ ACE_ERROR ((LM_ERROR,
+ "(%t) %p\n",
+ "register_handler"));
+ else if (ACE_Reactor::instance ()->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 to block all the signal in the
+ // <sig_set>, which is inherited by the threads it spawns.
+ ACE_Sig_Guard guard (&sig_set);
+
+ // Create N new threads of control Thread_Handlers.
+
+ for (size_t i = 0; i < n_threads; i++)
+ {
+ Thread_Handler *th;
+
+ ACE_NEW (th,
+ Thread_Handler (i + 1,
+ this->iterations_));
+
+ if (ACE_Thread::spawn (reinterpret_cast<ACE_THR_FUNC> (&Thread_Handler::svc_run),
+ reinterpret_cast<void *> (th),
+ THR_NEW_LWP | THR_DETACHED) != 0)
+ ACE_ERROR ((LM_ERROR,
+ "%p\n",
+ "ACE_Thread::spawn"));
+ }
+
+ // The destructor of <guard> unblocks the signal set so that only
+ // this thread receives them!
+}
+
+int
+Thread_Handler::notify (ACE_Time_Value *timeout)
+{
+ // Just do something to test the ACE_Reactor's multi-thread
+ // capabilities...
+
+ if (ACE_Reactor::instance ()->notify
+ (this,
+ ACE_Event_Handler::EXCEPT_MASK,
+ timeout) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "(%t) %p\n",
+ "notification::notify:exception"),
+ -1);
+ else if (ACE_Reactor::instance ()->notify
+ (this,
+ ACE_Event_Handler::WRITE_MASK,
+ timeout) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "(%t) %p\n",
+ "notification::notify:write"),
+ -1);
+ return 0;
+}
+
+// Test stdin handling that uses <select> to demultiplex HANDLEs.
+// Input is only handled by the main thread.
+
+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,
+ "input to (%t) %*s",
+ n,
+ buf));
+
+ ACE_DEBUG ((LM_DEBUG,
+ "%d more input to kill\n",
+ this->iterations_));
+
+ // Only wait up to 10 milliseconds to notify the Reactor.
+ ACE_Time_Value timeout (0,
+ 10 * 1000);
+
+ if (this->notify (&timeout) == -1)
+ ACE_ERROR ((LM_DEBUG,
+ "(%t), %p\n",
+ "notification::handle_input:notify"));
+ return 0;
+ }
+ else
+ return -1;
+}
+
+// Perform a task that will test the ACE_Reactor's multi-threading
+// capabilities in separate threads.
+
+int
+Thread_Handler::svc (void)
+{
+ ACE_Time_Value sleep_timeout (0,
+ // Transform this into microseconds and divide by 2.
+ (Thread_Handler::interval_.sec () * ACE_ONE_SECOND_IN_USECS) / 2);
+
+ for (int i = this->iterations_;
+ i > 0;
+ --i)
+ {
+ if (this->shutdown_ != 0)
+ break;
+
+ // Block for delay_.secs () / 2, then notify the Reactor.
+ ACE_OS::sleep (sleep_timeout);
+
+ // Wait up to 10 milliseconds to notify the Reactor.
+ ACE_Time_Value timeout (0,
+ 10 * 1000);
+ if (this->notify (&timeout) == -1)
+ ACE_ERROR ((LM_ERROR,
+ "(%t) %p\n",
+ "notify"));
+ }
+
+ ACE_Reactor::instance ()->remove_handler (this,
+ ALL_EVENTS_MASK);
+ ACE_DEBUG ((LM_DEBUG,
+ "(%t) exiting svc\n"));
+ return 0;
+}
+
+// Test signal handling.
+
+int
+Thread_Handler::handle_signal (int signum, siginfo_t *, ucontext_t *)
+{
+ // @@ Note that this code is not portable to all OS platforms since
+ // it uses print statements within signal handler context.
+ 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));
+ this->shutdown_ = 1;
+ ACE_Reactor::end_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), iterations = %d\n",
+ time.sec (),
+ time.usec (),
+ this->iterations_));
+
+ if (--this->iterations_ <= 0
+ || Thread_Handler::interval_.sec () == 0)
+ ACE_Reactor::end_event_loop ();
+
+ return 0;
+}
+
+// Called by the ACE_Reactor when it receives a notification.
+
+int
+Thread_Handler::handle_exception (ACE_HANDLE)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ "(%t) exception to id %d, iteration = %d\n",
+ this->id_,
+ this->iterations_));
+ return 0;
+}
+
+// Called by the ACE_Reactor when it receives a notification.
+
+int
+Thread_Handler::handle_output (ACE_HANDLE)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ "(%t) output to id %d, iteration = %d\n",
+ this->id_,
+ // This decrement must come last since
+ // <handle_exception> is called before <handle_output>!
+ this->iterations_--));
+ return 0;
+}
+
+// "Shim" function that integrates C thread API with C++.
+
+void *
+Thread_Handler::svc_run (void *eh)
+{
+ Thread_Handler *this_handler =
+ reinterpret_cast<Thread_Handler *> (eh);
+
+ if (this_handler->svc () == 0)
+ return 0;
+ else
+ return reinterpret_cast<void *> (-1);
+}
+
+int
+ACE_TMAIN (int argc, ACE_TCHAR *argv[])
+{
+ ACE_LOG_MSG->open (argv[0]);
+
+ if (argc < 4)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("usage: %s delay interval n_threads [iterations]\n"),
+ argv[0]));
+ ACE_OS::exit (1);
+ }
+
+ int delay = ACE_OS::atoi (argv[1]);
+ int interval = ACE_OS::atoi (argv[2]);
+ size_t n_threads = ACE_OS::atoi (argv[3]);
+ size_t max_iterations = argc > 4 ? ACE_OS::atoi (argv[4]) : MAX_ITERATIONS;
+
+ Thread_Handler thr_handler (delay,
+ interval,
+ n_threads,
+ max_iterations);
+
+ ACE_Reactor::instance ()->run_reactor_event_loop ();
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("exiting from main\n")));
+ return 0;
+}
+#else
+int
+main (int, char *[])
+{
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "threads must be supported to run this application\n"), -1);
+}
+#endif /* ACE_HAS_THREADS */
diff --git a/ACE/examples/Reactor/Misc/pingpong.cpp b/ACE/examples/Reactor/Misc/pingpong.cpp
new file mode 100644
index 00000000000..f4a3bc0630e
--- /dev/null
+++ b/ACE/examples/Reactor/Misc/pingpong.cpp
@@ -0,0 +1,302 @@
+// $Id$
+
+/* Simple program that illustrates many features of the ACE_Reactor:
+
+ 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/Reactor.h"
+#include "ace/Pipe.h"
+#include "ace/Log_Msg.h"
+#include "ace/ACE.h"
+#include "ace/Test_and_Set.h"
+#include "ace/OS_NS_string.h"
+#include "ace/Null_Mutex.h"
+#include "ace/OS_NS_unistd.h"
+#if defined (ACE_WIN32) || defined (CHORUS)
+# include "ace/Barrier.h"
+# include "ace/Thread.h"
+#endif
+
+ACE_RCSID(Misc, pingpong, "$Id$")
+
+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 *);
+ virtual int handle_close (ACE_HANDLE handle,
+ ACE_Reactor_Mask close_mask);
+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)
+ : buflen_ (ACE_OS::strlen (b) + 1 + (2 * sizeof (int))),
+ pid_ (ACE_OS::getpid ()),
+ handle_ (f)
+{
+ *((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_close (ACE_HANDLE,
+ ACE_Reactor_Mask)
+{
+ delete this; // Cleanup when we're removed from the reactor.
+ return 0;
+}
+
+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 != (ssize_t) this->buflen_)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) reading [%d] %p\n"),
+ handle_,
+ ACE_TEXT ("read")),
+ -1);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) reading <%d> (%d) [%d] = %C\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_,
+ this->buflen_);
+ if (n == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("[%d] %p\n"),
+ handle_,
+ ACE_TEXT ("read")),
+ -1);
+ n -= (2 * sizeof (int));
+ char *buf = this->buf_ + (2 * sizeof (int));
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) reading <%d> = %*C\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,
+ ACE_TEXT ("(%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,
+ ACE_TEXT ("(%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 ACE_TCHAR *string_name;
+
+// Wait for 10 seconds and then shut down.
+static const ACE_Time_Value SHUTDOWN_TIME (10);
+
+static void
+run_svc (ACE_HANDLE handle)
+{
+ Ping_Pong *callback = 0;
+ ACE_NEW (callback,
+ Ping_Pong (ACE_TEXT_ALWAYS_CHAR (string_name),
+ handle));
+
+ ACE_Reactor reactor;
+
+ // 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
+#if !defined (CHORUS)
+ || reactor.register_handler (SIGINT,
+ callback) == -1
+#endif /* CHORUS */
+ || reactor.schedule_timer (callback,
+ 0,
+ SHUTDOWN_TIME) == -1)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("reactor")));
+ ACE_OS::exit (1);
+ }
+
+ // Main event loop (one per process).
+
+ while (callback->is_set () == 0)
+ if (reactor.handle_events () == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("handle_events")));
+}
+
+#if defined (ACE_WIN32) || defined (CHORUS)
+static ACE_Barrier barrier (3);
+
+static void *
+worker (void *arg)
+{
+ ACE_HANDLE handle = (ACE_HANDLE) arg;
+
+ run_svc (handle);
+
+ // Wait for the threads to exit.
+ barrier.wait ();
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) %n: shutting down tester\n")));
+ return 0;
+}
+#endif /* ACE_WIN32 */
+
+int
+ACE_TMAIN (int argc, ACE_TCHAR *argv[])
+{
+ if (argc != 2)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("usage: pingpong <string>\n")),
+ -1);
+
+ ACE_LOG_MSG->open (argv[0]);
+
+ string_name = argv[1];
+
+ ACE_HANDLE handles[2];
+
+ // Create a pipe and initialize the handles.
+ ACE_Pipe pipe (handles);
+
+#if defined (ACE_WIN32) || defined (CHORUS)
+ 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,
+ ACE_TEXT ("%p\n%a"),
+ ACE_TEXT ("spawn"),
+ 1));
+ barrier.wait ();
+#else
+ pid_t pid = ACE_OS::fork (argv[0]);
+
+ if (pid == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("%p\n%a"),
+ ACE_TEXT ("fork"),
+ 1));
+ run_svc (handles[pid == 0]);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) %n: shutting down tester\n")));
+#endif /* ACE_WIN32 */
+
+ if (pipe.close () == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("close")));
+ return 0;
+}
diff --git a/ACE/examples/Reactor/Misc/test_demuxing.cpp b/ACE/examples/Reactor/Misc/test_demuxing.cpp
new file mode 100644
index 00000000000..6badd849757
--- /dev/null
+++ b/ACE/examples/Reactor/Misc/test_demuxing.cpp
@@ -0,0 +1,384 @@
+// $Id$
+
+// Perform an extensive test of all the ACE_Reactor's event handler
+// dispatching mechanisms. These mechanisms illustrate how I/O,
+// timeout, and signal events, as well as ACE_Message_Queues, can all
+// be handled within the same demultiplexing and dispatching
+// 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/ACE.h"
+#include "ace/Service_Config.h"
+#include "ace/Reactor.h"
+#include "ace/Task.h"
+#include "ace/Reactor_Notification_Strategy.h"
+#include "ace/Signal.h"
+#include "ace/OS_NS_fcntl.h"
+#include "ace/OS_NS_unistd.h"
+
+ACE_RCSID(Misc, test_demuxing, "$Id$")
+
+// Default is to have a 2 second timeout.
+static int timeout = 2;
+
+class Sig_Handler : public ACE_Event_Handler
+{
+ // = TITLE
+ // 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.
+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 (int 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_ != ACE_INVALID_HANDLE);
+
+ // Register signal handler object. Note that NULL_MASK is used to
+ // keep the ACE_Reactor from calling us back on the "/dev/null"
+ // descriptor. NULL_MASK just reserves a "slot" in the Reactor's
+ // internal demuxing table, but doesn't cause it to dispatch the
+ // event handler directly. Instead, we use the signal handler to do
+ // this.
+ ACE_Reactor_Mask mask = ACE_Event_Handler::NULL_MASK;
+ if (ACE_Reactor::instance ()->register_handler
+ (this,
+ 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_Reactor::instance ()->register_handler
+ (sig_set, this) == -1)
+ ACE_ERROR ((LM_ERROR,
+ "%p\n%a",
+ "register_handler",
+ 1));
+}
+
+// Called by the ACE_Reactor to extract the handle.
+
+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,
+ "(%t) 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,
+ "(%t) 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. Note
+// that 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 *)
+{
+ switch (signum)
+ {
+#if !defined (ACE_WIN32)
+ case SIGALRM:
+ // Rearm the alarm.
+ ACE_OS::alarm (4);
+ break;
+#endif /* !ACE_WIN32 */
+ 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, i.e., the behavior triggered by the signal is handled
+ // in the main event loop, rather than in the signal handler.
+ return ACE_Reactor::instance ()->ready_ops
+ (this->handle_,
+ ACE_Event_Handler::READ_MASK,
+ ACE_Reactor::ADD_MASK);
+#if defined (ACE_WIN32)
+ case SIGTERM:
+#else
+ case SIGQUIT:
+#endif /* ACE_WIN32 */
+ ACE_Reactor::end_event_loop ();
+ break;
+ default:
+ ACE_ERROR_RETURN ((LM_ERROR, "invalid signal"), -1);
+ break;
+ /* NOTREACHED */
+ }
+ return 0;
+}
+
+class STDIN_Handler : public ACE_Event_Handler
+{
+ // = TITLE
+ // This class illustrates that the ACE_Reactor can handle signals,
+ // STDIO, and timeouts using the same mechanisms.
+public:
+ STDIN_Handler (void);
+ ~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_Event_Handler::register_stdin_handler (this,
+ ACE_Reactor::instance (),
+ ACE_Thread_Manager::instance ()) == -1)
+ ACE_ERROR ((LM_ERROR,
+ "%p\n",
+ "register_stdin_handler"));
+
+ // Register the <STDIN_Handler> to be dispatched once every
+ // <timeout> seconds starting in <timeout> seconds. This example
+ // uses the "interval timer" feature of the <ACE_Reactor>'s timer
+ // queue.
+ else if (ACE_Reactor::instance ()->schedule_timer
+ (this,
+ 0,
+ ACE_Time_Value (timeout),
+ ACE_Time_Value (timeout)) == -1)
+ ACE_ERROR ((LM_ERROR,
+ "%p\n%a",
+ "schedule_timer",
+ 1));
+}
+
+STDIN_Handler::~STDIN_Handler (void)
+{
+ if (ACE_Event_Handler::remove_stdin_handler (ACE_Reactor::instance (),
+ ACE_Thread_Manager::instance ()) == -1)
+ ACE_ERROR ((LM_ERROR,
+ "%p\n",
+ "remove_stdin_handler"));
+ else if (ACE_Reactor::instance ()->cancel_timer
+ (this) == -1)
+ ACE_ERROR ((LM_ERROR,
+ "%p\n%a",
+ "cancel_timer",
+ 1));
+}
+
+int
+STDIN_Handler::handle_timeout (const ACE_Time_Value &tv,
+ const void *)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ "(%t) timeout occurred at %d sec, %d usec\n",
+ tv.sec (),
+ tv.usec ()));
+ return 0;
+}
+
+// Read from input handle and write to stdout handle.
+
+int
+STDIN_Handler::handle_input (ACE_HANDLE handle)
+{
+ char buf[BUFSIZ];
+ ssize_t n = ACE_OS::read (handle, buf, sizeof buf);
+
+ switch (n)
+ {
+ case -1:
+ if (errno == EINTR)
+ return 0;
+ /* NOTREACHED */
+ else
+ ACE_ERROR ((LM_ERROR,
+ "%p\n",
+ "read"));
+ /* FALLTHROUGH */
+ case 0:
+ ACE_Reactor::end_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;
+}
+
+class Message_Handler : public ACE_Task <ACE_SYNCH>
+{
+public:
+ Message_Handler (void);
+
+ virtual int handle_input (ACE_HANDLE);
+ // Called back within the context of the <ACE_Reactor> Singleton to
+ // dequeue and process the message on the <ACE_Message_Queue>.
+
+ virtual int svc (void);
+ // Run the "event-loop" periodically putting messages to our
+ // internal <Message_Queue> that we inherit from <ACE_Task>.
+
+private:
+ ACE_Reactor_Notification_Strategy notification_strategy_;
+ // This strategy will notify the <ACE_Reactor> Singleton when a new
+ // message is enqueued.
+};
+
+Message_Handler::Message_Handler (void)
+ : notification_strategy_ (ACE_Reactor::instance (),
+ this,
+ ACE_Event_Handler::READ_MASK)
+{
+ // Set this to the Reactor notification strategy.
+ this->msg_queue ()->notification_strategy (&this->notification_strategy_);
+
+ if (this->activate ())
+ ACE_ERROR ((LM_ERROR,
+ "%p\n",
+ "activate"));
+}
+
+int
+Message_Handler::svc (void)
+{
+ for (int i = 0;; i++)
+ {
+ ACE_Message_Block *mb;
+
+ ACE_NEW_RETURN (mb,
+ ACE_Message_Block (1),
+ 0);
+
+ mb->msg_priority (i);
+ ACE_OS::sleep (1);
+
+ // Note that this putq() call with automagically invoke the
+ // notify() hook of our ACE_Reactor_Notification_Strategy,
+ // thereby informing the <ACE_Reactor> Singleton to call our
+ // <handle_input> method.
+ if (this->putq (mb) == -1)
+ {
+ if (errno == ESHUTDOWN)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "(%t) queue is deactivated"), 0);
+ else
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "(%t) %p\n",
+ "putq"),
+ -1);
+ }
+ }
+
+ ACE_NOTREACHED (return 0);
+}
+
+int
+Message_Handler::handle_input (ACE_HANDLE)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ "(%t) Message_Handler::handle_input\n"));
+
+ ACE_Message_Block *mb;
+
+ if (this->getq (mb, (ACE_Time_Value *) &ACE_Time_Value::zero) == -1)
+ ACE_ERROR ((LM_ERROR,
+ "(%t) %p\n",
+ "dequeue_head"));
+ else
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ "(%t) priority = %d\n",
+ mb->msg_priority ()));
+ mb->release ();
+ }
+
+ return 0;
+}
+
+int
+ACE_TMAIN (int argc, ACE_TCHAR *argv[])
+{
+ ACE_Service_Config daemon (argv [0]);
+
+ // Optionally start the alarm.
+ if (argc > 1)
+ {
+ ACE_OS::alarm (4);
+ timeout = ACE_OS::atoi (argv[1]);
+ }
+
+ // Signal handler.
+ Sig_Handler sh;
+
+ // Define an I/O handler object.
+ STDIN_Handler ioh;
+
+ // Define a message handler.
+ Message_Handler mh;
+
+ // Loop handling signals and I/O events until SIGQUIT occurs.
+
+ while (ACE_Reactor::instance ()->event_loop_done () == 0)
+ ACE_Reactor::instance ()->run_reactor_event_loop ();
+
+ // Deactivate the message queue.
+ mh.msg_queue ()->deactivate ();
+
+ // Wait for the thread to exit.
+ ACE_Thread_Manager::instance ()->wait ();
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) leaving main\n")));
+ return 0;
+}
diff --git a/ACE/examples/Reactor/Misc/test_early_timeouts.cpp b/ACE/examples/Reactor/Misc/test_early_timeouts.cpp
new file mode 100644
index 00000000000..4c7193d9a67
--- /dev/null
+++ b/ACE/examples/Reactor/Misc/test_early_timeouts.cpp
@@ -0,0 +1,114 @@
+// $Id$
+
+// ================================================================
+//
+// = LIBRARY
+// examples/Reactor/Misc/
+//
+// = FILENAME
+// test_early_timeouts.cpp
+//
+// = DESCRIPTION
+// On some platforms, select() returns before the time value
+// specified. This tests counts the number of times this happens
+// and the max early timeout.
+//
+// = AUTHOR
+// Irfan Pyarali <irfan@cs.wustl.edu>
+//
+// ================================================================
+
+#include "ace/Handle_Set.h"
+#include "ace/Pipe.h"
+#include "ace/Log_Msg.h"
+#include "ace/Time_Value.h"
+#include "ace/OS_NS_sys_time.h"
+#include "ace/OS_NS_sys_select.h"
+
+ACE_RCSID(Misc, test_early_timeouts, "$Id$")
+
+int
+ACE_TMAIN (int, ACE_TCHAR *[])
+{
+ // Mumber of seconds this test should run
+ int runtime_in_seconds = 10;
+
+ // Iterations
+ int iterations = runtime_in_seconds * 10;
+
+ // 100 millisecond timeout
+ ACE_Time_Value timeout (0, 100000);
+
+ // Time before starting select
+ ACE_Time_Value starting_time_of_day;
+
+ // Time before starting select
+ ACE_Time_Value ending_time_of_day;
+
+ // Number of times the timer expired early
+ int no_of_early_timers = 0;
+
+ // Maximum early timeout
+ ACE_Time_Value maximum_early_timeout;
+
+ //
+ // Dummy handle and handle set
+ // Note that some OS do not like "empty selects"
+ //
+
+ // Dummy handle set
+ ACE_Handle_Set dummy_handle_set;
+
+ // Dummy pipe
+ ACE_Pipe dummy_pipe;
+ int result = dummy_pipe.open ();
+ ACE_ASSERT (result == 0);
+ ACE_UNUSED_ARG (result); // To avoid compile warning with ACE_NDEBUG.
+
+ for (int i = 1; i <= iterations; i++)
+ {
+ // Add dummy handle to dummy set
+ dummy_handle_set.set_bit (dummy_pipe.read_handle ());
+
+ // Note the time before select
+ starting_time_of_day = ACE_OS::gettimeofday ();
+
+ // Wait for timeout
+ result = ACE_OS::select ((int) dummy_pipe.read_handle (), dummy_handle_set, 0, 0, &timeout);
+ ACE_ASSERT (result == 0);
+
+ // Note the time after select
+ ending_time_of_day = ACE_OS::gettimeofday ();
+
+ // Expected ending time
+ ACE_Time_Value expected_ending_time_of_day =
+ starting_time_of_day + timeout;
+
+ // If the timer expired early
+ if (ending_time_of_day < expected_ending_time_of_day)
+ {
+ // How early
+ ACE_Time_Value early_timeout = expected_ending_time_of_day - ending_time_of_day;
+
+ // Increment number of early timers
+ no_of_early_timers++;
+
+ // Check max early timeout
+ if (early_timeout > maximum_early_timeout)
+ {
+ maximum_early_timeout = early_timeout;
+ }
+ }
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ "There were %d early timers out of %d calls to select() (%f%%)\n"
+ "The max early timeout was: %dsec %dusec\n",
+ no_of_early_timers,
+ iterations,
+ float (no_of_early_timers) / iterations * 100,
+ maximum_early_timeout.sec (),
+ maximum_early_timeout.usec ()));
+
+ return 0;
+}
diff --git a/ACE/examples/Reactor/Misc/test_event_handler_t.cpp b/ACE/examples/Reactor/Misc/test_event_handler_t.cpp
new file mode 100644
index 00000000000..4261859784e
--- /dev/null
+++ b/ACE/examples/Reactor/Misc/test_event_handler_t.cpp
@@ -0,0 +1,47 @@
+// $Id$
+
+#include "ace/Event_Handler_T.h"
+#include "ace/Log_Msg.h"
+
+ACE_RCSID(Misc, test_event_handler_t, "$Id$")
+
+#if defined (ACE_HAS_TEMPLATE_TYPEDEFS)
+
+class ACE_Test_Sig_Handler
+{
+public:
+ ACE_Test_Sig_Handler (void) {}
+ virtual ~ACE_Test_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 (int /* signum */,
+ siginfo_t * = 0,
+ ucontext_t * = 0)
+ {
+ return 0;
+ }
+};
+
+int
+ACE_TMAIN (int, ACE_TCHAR *[])
+{
+ typedef ACE_Event_Handler_T<ACE_Test_Sig_Handler> EH_SH;
+
+ // Tie the ACE_Event_Handler_T together with the methods from ACE_Test_Sig_Handler.
+ EH_SH tied_sh (new ACE_Test_Sig_Handler, 1,
+ &ACE_Test_Sig_Handler::get_handle,
+ &ACE_Test_Sig_Handler::handle_async_io,
+ &ACE_Test_Sig_Handler::shutdown,
+ &ACE_Test_Sig_Handler::signal_handler);
+ return 0;
+}
+
+#else
+int
+ACE_TMAIN (int, ACE_TCHAR *[])
+{
+ ACE_ERROR_RETURN ((LM_ERROR, "your platform does not support template typedefs\n"), 1);
+}
+#endif /* ACE_HAS_TEMPLATE_TYPEDEFS */
diff --git a/ACE/examples/Reactor/Misc/test_reactors.cpp b/ACE/examples/Reactor/Misc/test_reactors.cpp
new file mode 100644
index 00000000000..a08580672e0
--- /dev/null
+++ b/ACE/examples/Reactor/Misc/test_reactors.cpp
@@ -0,0 +1,195 @@
+// $Id$
+
+// Perform a torture test of multiple ACE_Reactors and ACE_Tasks in
+// the same process... Thanks to Detlef Becker for contributing this.
+
+#include "ace/Reactor.h"
+#include "ace/Service_Config.h"
+#include "ace/Task.h"
+#include "ace/Atomic_Op.h"
+
+ACE_RCSID(Misc, test_reactors, "$Id$")
+
+#if defined (ACE_HAS_THREADS)
+
+#include "ace/Recursive_Thread_Mutex.h"
+
+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 svc (void);
+
+ virtual int handle_input (ACE_HANDLE handle);
+ virtual int handle_close (ACE_HANDLE fd,
+ ACE_Reactor_Mask close_mask);
+
+private:
+ int handled_;
+
+ static int task_count_;
+};
+
+int Test_Task::task_count_ = 0;
+
+static ACE_Atomic_Op<ACE_Thread_Mutex, int> 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)
+{
+ this->reactor ((ACE_Reactor *) args);
+ return this->activate (THR_NEW_LWP);
+}
+
+int
+Test_Task::close (u_long)
+{
+ 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::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 (this->reactor ()->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,
+ ACE_Reactor_Mask)
+{
+ ACE_DEBUG ((LM_DEBUG, "(%t) handle_close\n"));
+ return 0;
+}
+
+int
+Test_Task::handle_input (ACE_HANDLE)
+{
+ 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_, done_count.value ()));
+ }
+
+ ACE_OS::thr_yield ();
+ return -1;
+}
+
+static void *
+worker (void *args)
+{
+ 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, "(%t) %p\n", "reactor"), 0);
+ /* NOTREACHED */
+ case 0:
+ ACE_ERROR_RETURN ((LM_ERROR, "(%t) timeout\n"), 0);
+ /* NOTREACHED */
+ }
+
+ // ACE_DEBUG ((LM_DEBUG, "(%t) done with handle_events\n"));
+
+ }
+
+ ACE_NOTREACHED(return 0);
+}
+
+int
+ACE_TMAIN (int, ACE_TCHAR *[])
+{
+ ACE_Reactor *react1 = ACE_Reactor::instance ();
+ 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_Thread_Manager::instance ()->spawn
+ (ACE_THR_FUNC (worker), (void *) react1, THR_NEW_LWP) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "spawn"), -1);
+
+ else if (ACE_Thread_Manager::instance ()->spawn
+ (ACE_THR_FUNC (worker), (void *) react2, THR_NEW_LWP) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "spawn"), -1);
+
+ ACE_Thread_Manager::instance ()->wait ();
+ ACE_DEBUG ((LM_DEBUG, "(%t) done\n"));
+
+ return 0;
+}
+
+#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/ACE/examples/Reactor/Misc/test_signals_1.cpp b/ACE/examples/Reactor/Misc/test_signals_1.cpp
new file mode 100644
index 00000000000..b0410f572c1
--- /dev/null
+++ b/ACE/examples/Reactor/Misc/test_signals_1.cpp
@@ -0,0 +1,114 @@
+// $Id$
+
+// This simple program illustrates the difference between handling
+// signals via the Reactor (which doesn't cause the event loop to
+// terminate) and signals that aren't handled via the Reactor (which
+// do).
+
+#include "ace/Service_Config.h"
+#include "ace/Reactor.h"
+#include "ace/Log_Msg.h"
+#include "ace/Signal.h"
+
+ACE_RCSID(Misc, test_signals_1, "$Id$")
+
+// Number of times to allow signal to execute until we quit.
+static size_t count = 10;
+
+static void
+my_signal_function (int sig)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ "Executed non-ACE signal handler for signal %S\n",
+ sig));
+}
+
+class My_Handler : public ACE_Event_Handler
+{
+public:
+ virtual int handle_signal (int sig,
+ siginfo_t *,
+ ucontext_t *)
+ {
+ // @@ Note that this code is not portable to all OS platforms
+ // since it uses print statements within signal handler context.
+ ACE_DEBUG ((LM_DEBUG,
+ "Executed ACE signal handler for signal %S, count = %d\n",
+ sig,
+ count));
+ count--;
+
+ if (count == 0)
+ ACE_Reactor::end_event_loop ();
+
+ return 0;
+ }
+
+ virtual int handle_timeout (const ACE_Time_Value &,
+ const void *arg)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ "%s\n",
+ (const char *) arg));
+ return 0;
+ }
+};
+
+int
+ACE_TMAIN (int argc, ACE_TCHAR *argv[])
+{
+ // First you need a handler for the timeout.
+ My_Handler my_handler;
+
+ // This is the timeout period in seconds.
+ ACE_Time_Value period (ACE_DEFAULT_TIMEOUT);
+
+ if (argc > 1)
+ period.set (ACE_OS::atoi (argv[1]), 0);
+
+ // Set up the periodic interval timer.
+ if (ACE_Reactor::instance ()->schedule_timer
+ (&my_handler,
+ "hello",
+ period,
+ period) == -1)
+ ACE_ERROR_RETURN ((LM_DEBUG,
+ "%p\n",
+ "schedule_timer"),
+ -1);
+
+ // Set up an ACE signal handler.
+
+ if (ACE_Reactor::instance ()->register_handler
+ (SIGINT,
+ &my_handler) == -1)
+ ACE_ERROR_RETURN ((LM_DEBUG,
+ "%p\n",
+ "register_handler"),
+ -1);
+
+ // Set up a non-ACE signal handler. When this goes off, the Reactor
+ // should return from its <run_event_loop> method.
+ ACE_Sig_Action sig ((ACE_SignalHandler) my_signal_function,
+ SIGQUIT);
+ ACE_UNUSED_ARG (sig);
+
+ ACE_DEBUG ((LM_DEBUG,
+ "starting event loop that runs until you've typed ^C a total of 10 times or ^\\ once.\n"));
+
+ // This call executes the reactor events until we're finished.
+ int result = ACE_Reactor::run_event_loop ();
+
+ ACE_DEBUG ((LM_DEBUG,
+ "result = %d\n",
+ result));
+
+ // Make sure to remove my_handler before exiting main() since
+ // otherwise weird things can happen...
+ if (ACE_Reactor::instance ()->cancel_timer (&my_handler) == -1)
+ ACE_ERROR_RETURN ((LM_DEBUG,
+ "%p\n",
+ "cancel_timer"),
+ -1);
+ return 0;
+}
diff --git a/ACE/examples/Reactor/Misc/test_signals_2.cpp b/ACE/examples/Reactor/Misc/test_signals_2.cpp
new file mode 100644
index 00000000000..466ab58482f
--- /dev/null
+++ b/ACE/examples/Reactor/Misc/test_signals_2.cpp
@@ -0,0 +1,291 @@
+// $Id$
+
+// Test the ability of the Reactor/Signal_Handler to register multiple
+// 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/Reactor.h"
+#include "ace/WFMO_Reactor.h"
+#include "ace/Select_Reactor.h"
+#include "ace/Log_Msg.h"
+#include "ace/Signal.h"
+
+ACE_RCSID(Misc, test_signals_2, "$Id$")
+
+class Sig_Handler_1 : public ACE_Event_Handler
+{
+public:
+ Sig_Handler_1 (ACE_Reactor &reactor, const 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"));
+ }
+
+ // @@ Note that this code is not portable to all OS platforms since
+ // it does print statements within the signal 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:
+ const 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, const 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_));
+ }
+ return 0;
+ }
+};
+
+static void
+external_handler (int signum)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ "\nsignal %S occurred in external handler!",
+ signum));
+}
+
+#if !defined (HPUX)
+int
+ACE_TMAIN (int argc, ACE_TCHAR *[])
+{
+ // If argc > 1 then allow multiple handlers per-signal, else just
+ // allow 1 handler per-signal.
+ ACE_Sig_Handlers multi_handlers;
+
+#if defined (ACE_WIN32)
+ ACE_WFMO_Reactor reactor_impl (argc > 1
+ ? &multi_handlers
+ : (ACE_Sig_Handler *) 0);
+#else
+ ACE_Select_Reactor reactor_impl (argc > 1
+ ? &multi_handlers
+ : (ACE_Sig_Handler *) 0);
+#endif /* ACE_WIN32 */
+ ACE_Reactor reactor (&reactor_impl);
+
+ 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");
+ Sig_Handler_1 h2 (reactor, "doody");
+ Sig_Handler_2 h3 (reactor, "tutty");
+ Sig_Handler_2 h4 (reactor, "fruity");
+
+ // Wait for user to type SIGINT and SIGQUIT.
+
+ for (;;)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ "\nwaiting for SIGINT or SIGQUIT\n"));
+
+ if (reactor.handle_events () == -1)
+ ACE_ERROR ((LM_ERROR,
+ "%p\n",
+ "handle_events"));
+ }
+
+ ACE_NOTREACHED (return 0);
+}
+#else
+int
+main (int, char *[])
+{
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "The HP C++ compiler is too lame to support this feature\n"),
+ -1);
+}
+#endif /* HPUX */
diff --git a/ACE/examples/Reactor/Misc/test_time_value.cpp b/ACE/examples/Reactor/Misc/test_time_value.cpp
new file mode 100644
index 00000000000..a1c1c874b78
--- /dev/null
+++ b/ACE/examples/Reactor/Misc/test_time_value.cpp
@@ -0,0 +1,83 @@
+// $Id$
+
+// FUZZ: disable check_for_streams_include
+#include "ace/streams.h"
+
+#include "ace/Log_Msg.h"
+#include "ace/Time_Value.h"
+
+ACE_RCSID(Misc, test_time_value, "$Id$")
+
+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 << my_abs (int (tv.sec ())) << "."
+// << setw (6) << setfill ('0')
+ << my_abs (int (tv.usec ()));
+ return stream;
+}
+
+int
+main (int, char *[])
+{
+ 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);
+
+# if defined (ACE_NDEBUG)
+ ACE_UNUSED_ARG (tv1);
+ ACE_UNUSED_ARG (tv2);
+ ACE_UNUSED_ARG (tv3);
+ ACE_UNUSED_ARG (tv4);
+ ACE_UNUSED_ARG (tv5);
+ ACE_UNUSED_ARG (tv6);
+# endif /* ACE_NDEBUG */
+
+ 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/ACE/examples/Reactor/Misc/test_timer_queue.cpp b/ACE/examples/Reactor/Misc/test_timer_queue.cpp
new file mode 100644
index 00000000000..64138e13daf
--- /dev/null
+++ b/ACE/examples/Reactor/Misc/test_timer_queue.cpp
@@ -0,0 +1,115 @@
+// $Id$
+
+#include "ace/OS_NS_sys_time.h"
+#include "ace/Timer_Heap.h"
+#include "ace/Timer_List.h"
+#include "ace/Timer_Queue.h"
+#include "ace/Log_Msg.h"
+#include "ace/Recursive_Thread_Mutex.h"
+#include "ace/Null_Mutex.h"
+
+ACE_RCSID(Misc, test_timer_queue, "$Id$")
+
+class Example_Handler : public ACE_Event_Handler
+{
+public:
+ Example_Handler (void)
+ : count_ (1)
+ {}
+
+ virtual int handle_timeout (const ACE_Time_Value &, const void *arg)
+ {
+ int *times = (int *) arg;
+
+ ACE_DEBUG ((LM_DEBUG,
+ "yow, the time has come and gone %d times %d, Horatio!\n",
+ this->count_++,
+ *times));
+ delete times;
+ return 0;
+ }
+
+private:
+ int count_;
+};
+
+static void
+test_functionality (ACE_Timer_Queue *tq)
+{
+ Example_Handler eh;
+
+ ACE_ASSERT (tq->is_empty ());
+ ACE_ASSERT (ACE_Time_Value::zero == ACE_Time_Value (0));
+ const void *timer_act = 0;
+
+ ACE_NEW (timer_act, int (1));
+ long timer_id1 = tq->schedule (&eh, timer_act, ACE_OS::gettimeofday ());
+
+ // Use timer_id outside of an assert, so that we don't get compile
+ // warnings with ACE_NDEBUG about it being unused.
+ if (timer_id1 == -1)
+ ACE_ERROR ((LM_ERROR, "%p\n", "schedule () failed"));
+ ACE_ASSERT (timer_id1 != -1);
+
+ ACE_NEW (timer_act, int (42));
+ long result = tq->schedule (&eh, timer_act, ACE_OS::gettimeofday ());
+ ACE_ASSERT (result != -1);
+ ACE_NEW (timer_act, int (42));
+ result = tq->schedule (&eh, timer_act, ACE_OS::gettimeofday ());
+ ACE_ASSERT (result != -1);
+
+ result = tq->cancel (timer_id1, &timer_act);
+ ACE_ASSERT (result == 1);
+ delete (int *) timer_act;
+ result = tq->is_empty ();
+ ACE_ASSERT (!result);
+
+ result = tq->expire ();
+ ACE_ASSERT (result == 2);
+
+ ACE_NEW (timer_act, int (4));
+ timer_id1 = tq->schedule (&eh, timer_act, ACE_OS::gettimeofday ());
+ ACE_ASSERT (timer_id1 != -1);
+ ACE_NEW (timer_act, int (5));
+ long timer_id2 = tq->schedule (&eh, timer_act, ACE_OS::gettimeofday ());
+ ACE_ASSERT (timer_id2 != -1);
+
+ result = tq->cancel (timer_id1, &timer_act);
+ ACE_ASSERT (result == 1);
+ delete (int *) timer_act;
+ result = tq->cancel (timer_id2, &timer_act);
+ ACE_ASSERT (result == 1);
+ delete (int *) timer_act;
+ result = tq->is_empty ();
+ ACE_ASSERT (result == 1);
+ result = tq->expire ();
+ ACE_ASSERT (result == 0);
+}
+
+struct Timer_Queues
+{
+ ACE_Timer_Queue *queue_;
+ // Pointer to the subclass of <ACE_Timer_Queue> that we're testing.
+
+ const char *name_;
+ // Name of the Queue that we're testing.
+};
+
+static Timer_Queues timer_queues[] =
+{
+ { new ACE_Timer_List, "ACE_Timer_List" },
+ { new ACE_Timer_Heap, "ACE_Timer_Heap" },
+ { 0, 0 },
+};
+
+int
+ACE_TMAIN (int, ACE_TCHAR *[])
+{
+ for (int i = 0; timer_queues[i].name_ != 0; i++)
+ {
+ test_functionality (timer_queues[i].queue_);
+ delete timer_queues[i].queue_;
+ }
+
+ return 0;
+}
diff --git a/ACE/examples/Reactor/Multicast/.cvsignore b/ACE/examples/Reactor/Multicast/.cvsignore
new file mode 100644
index 00000000000..955ffdc75d5
--- /dev/null
+++ b/ACE/examples/Reactor/Multicast/.cvsignore
@@ -0,0 +1,4 @@
+client
+client
+server
+server
diff --git a/ACE/examples/Reactor/Multicast/Log_Wrapper.cpp b/ACE/examples/Reactor/Multicast/Log_Wrapper.cpp
new file mode 100644
index 00000000000..055b57b9975
--- /dev/null
+++ b/ACE/examples/Reactor/Multicast/Log_Wrapper.cpp
@@ -0,0 +1,81 @@
+// $Id$
+
+// client.C
+
+#include "Log_Wrapper.h"
+#include "ace/OS_NS_unistd.h"
+#include "ace/OS_NS_sys_utsname.h"
+#include "ace/OS_NS_string.h"
+#include "ace/OS_NS_netdb.h"
+
+ACE_RCSID(Multicast, Log_Wrapper, "$Id$")
+
+Log_Wrapper::Log_Wrapper (void)
+{
+ sequence_number_ = 0;
+ this->log_msg_.app_id = ACE_OS::getpid ();
+}
+
+Log_Wrapper::~Log_Wrapper (void)
+{
+}
+
+// Set the log_msg_ host address.
+
+int
+Log_Wrapper::open (const int port, const char *mcast_addr)
+{
+ struct hostent *host_info;
+ ACE_utsname host_data;
+
+ if (ACE_OS::uname (&host_data) < 0)
+ return -1;
+
+#if defined (ACE_LACKS_UTSNAME_T)
+ if ((host_info = ACE_OS::gethostbyname
+ (ACE_TEXT_ALWAYS_CHAR(host_data.nodename))) == NULL)
+#else
+ if ((host_info = ACE_OS::gethostbyname (host_data.nodename)) == NULL)
+#endif
+ 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!
+ server_ = ACE_INET_Addr (port, mcast_addr);
+
+ if (logger_.subscribe (server_) == -1)
+ perror("can't subscribe to multicast group"), exit(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 (Log_Priority type, char *message)
+{
+ sequence_number_++;
+
+ this->log_msg_.type = type;
+ this->log_msg_.time = time (0);
+ this->log_msg_.msg_length = ACE_OS::strlen(message)+1;
+ this->log_msg_.sequence_number = htonl(sequence_number_);
+
+ iovec iovp[2];
+ iovp[0].iov_base = reinterpret_cast<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);
+
+ // success.
+ return 0;
+}
+
diff --git a/ACE/examples/Reactor/Multicast/Log_Wrapper.h b/ACE/examples/Reactor/Multicast/Log_Wrapper.h
new file mode 100644
index 00000000000..10458f706bc
--- /dev/null
+++ b/ACE/examples/Reactor/Multicast/Log_Wrapper.h
@@ -0,0 +1,68 @@
+/* -*- C++ -*- */
+// $Id$
+
+// log_wrapper.h
+
+#include "ace/Profile_Timer.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "ace/INET_Addr.h"
+#include "ace/SOCK_Dgram_Mcast.h"
+
+#ifndef _LOG_WRAPPER_H
+#define _LOG_WRAPPER_H
+
+class Log_Wrapper
+ // = TITLE
+ // Provide a wrapper around sending log messages via IP
+ // multicast.
+{
+public:
+ Log_Wrapper (void);
+ ~Log_Wrapper (void);
+
+ // = Types of logging messages.
+ enum Log_Priority
+ {
+ LM_MESSAGE,
+ LM_DEBUG,
+ LM_WARNING,
+ LM_ERROR,
+ LM_EMERG
+ };
+
+ int open (const int port, const char* mcast_addr);
+ // Subscribe to a given UDP multicast group
+
+ int log_message (Log_Priority type, char *message);
+ // send a string to the logger
+
+ // = Format of the logging record.
+ struct Log_Record
+ {
+ u_long sequence_number;
+ Log_Priority type;
+ long host;
+ long time;
+ long app_id;
+ long msg_length;
+ };
+
+private:
+ ACE_INET_Addr server_;
+ // Server address where records are logged.
+
+ u_long sequence_number_;
+ // Keep track of the sequence.
+
+ Log_Record log_msg_;
+ // One record used for many log messages.
+
+ ACE_SOCK_Dgram_Mcast logger_;
+ // A logger object.
+};
+
+#endif /* _LOG_WRAPPER_H */
diff --git a/ACE/examples/Reactor/Multicast/Makefile.am b/ACE/examples/Reactor/Multicast/Makefile.am
new file mode 100644
index 00000000000..60d65e7ebe8
--- /dev/null
+++ b/ACE/examples/Reactor/Multicast/Makefile.am
@@ -0,0 +1,50 @@
+## Process this file with automake to create Makefile.in
+##
+## $Id$
+##
+## This file was generated by MPC. Any changes made directly to
+## this file will be lost the next time it is generated.
+##
+## MPC Command:
+## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu
+
+ACE_BUILDDIR = $(top_builddir)
+ACE_ROOT = $(top_srcdir)
+
+## Makefile.Reactor_Multicast_Client.am
+noinst_PROGRAMS = client
+
+client_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+client_SOURCES = \
+ Log_Wrapper.cpp \
+ client.cpp \
+ Log_Wrapper.h
+
+client_LDADD = \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.Reactor_Multicast_Server.am
+noinst_PROGRAMS += server
+
+server_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+server_SOURCES = \
+ Log_Wrapper.cpp \
+ server.cpp \
+ Log_Wrapper.h
+
+server_LDADD = \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Clean up template repositories, etc.
+clean-local:
+ -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.*
+ -rm -f gcctemp.c gcctemp so_locations *.ics
+ -rm -rf cxx_repository ptrepository ti_files
+ -rm -rf templateregistry ir.out
+ -rm -rf ptrepository SunWS_cache Templates.DB
diff --git a/ACE/examples/Reactor/Multicast/README b/ACE/examples/Reactor/Multicast/README
new file mode 100644
index 00000000000..85f64cc8120
--- /dev/null
+++ b/ACE/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/ACE/examples/Reactor/Multicast/Reactor_Multicast.mpc b/ACE/examples/Reactor/Multicast/Reactor_Multicast.mpc
new file mode 100644
index 00000000000..a15c53340e4
--- /dev/null
+++ b/ACE/examples/Reactor/Multicast/Reactor_Multicast.mpc
@@ -0,0 +1,17 @@
+// -*- MPC -*-
+// $Id$
+
+project(*client) : aceexe {
+ exename = client
+ Source_Files {
+ client.cpp
+ Log_Wrapper.cpp
+ }
+}
+project(*server) : aceexe {
+ exename = server
+ Source_Files {
+ server.cpp
+ Log_Wrapper.cpp
+ }
+}
diff --git a/ACE/examples/Reactor/Multicast/client.cpp b/ACE/examples/Reactor/Multicast/client.cpp
new file mode 100644
index 00000000000..25b18c2ae6c
--- /dev/null
+++ b/ACE/examples/Reactor/Multicast/client.cpp
@@ -0,0 +1,126 @@
+// $Id$
+
+// This program reads in messages from stdin and sends them to a
+// Log_Wrapper.
+
+#include "ace/OS_main.h"
+#include "ace/OS_NS_stdlib.h"
+#include "ace/OS_NS_string.h"
+#include "ace/OS_NS_unistd.h"
+#include "ace/OS_Memory.h"
+#include "ace/Get_Opt.h"
+#include "ace/Log_Msg.h"
+#include "Log_Wrapper.h"
+
+ACE_RCSID(Multicast, client, "$Id$")
+
+// Multi-cast address.
+static const char *MCAST_ADDR = ACE_DEFAULT_MULTICAST_ADDR;
+
+// UDP port.
+static const int UDP_PORT = ACE_DEFAULT_MULTICAST_PORT;
+
+// Maximum message size.
+static int max_message_size = BUFSIZ;
+
+// Number of times to send message of max_message_size.
+static int iterations = 0;
+
+static void
+parse_args (int argc, ACE_TCHAR *argv[])
+{
+ ACE_LOG_MSG->open (argv[0]);
+
+ // Start at argv[1]
+ ACE_Get_Opt getopt (argc, argv, ACE_TEXT("m:ui:"), 1);
+
+ for (int c; (c = getopt ()) != -1; )
+ switch (c)
+ {
+ case 'm':
+ max_message_size = ACE_OS::atoi (getopt.opt_arg ()) * BUFSIZ;
+ break;
+ case 'i':
+ iterations = ACE_OS::atoi (getopt.opt_arg ());
+ break;
+ case 'u':
+ // usage fallthrough
+ default:
+ ACE_ERROR ((LM_ERROR,
+ "%n: -m max_message_size (in k) -i iterations\n%a",
+ 1));
+ /* NOTREACHED */
+ }
+}
+
+int
+ACE_TMAIN (int argc, ACE_TCHAR **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.
+ if (log.open (UDP_PORT, MCAST_ADDR) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "%p\n" "open"), -1);
+
+ char *buf;
+ ACE_NEW_RETURN (buf, char[max_message_size], -1);
+
+ // 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)
+ ACE_ERROR_RETURN ((LM_ERROR, "%p\n" "log"), -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;
+
+ // Continually read messages from stdin and log them.
+
+ for (int count = 1;;)
+ {
+ if (user_prompt)
+ ACE_DEBUG ((LM_DEBUG, "\nEnter message ('Q':quit):\n"));
+
+ ssize_t nbytes = ACE_OS::read (ACE_STDIN, buf, max_message_size);
+
+ if (nbytes <= 0)
+ break; // End of file or error.
+ buf[nbytes - 1] = '\0';
+
+ // Quitting?
+ if (user_prompt)
+ {
+ if (buf[0] == 'Q' || buf[0] == 'q')
+ break;
+ }
+ else // Keep from overrunning the receiver.
+ ACE_OS::sleep (1);
+
+ // Send the message to the logger.
+ if (log.log_message (Log_Wrapper::LM_DEBUG, buf) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "%p\n" "log_message"), -1);
+ ACE_DEBUG ((LM_DEBUG, "finished sending message %d\n", count++));
+ }
+ }
+
+ ACE_DEBUG ((LM_DEBUG, "Client done.\n"));
+ return 0;
+}
diff --git a/ACE/examples/Reactor/Multicast/server.cpp b/ACE/examples/Reactor/Multicast/server.cpp
new file mode 100644
index 00000000000..65e39b97d1a
--- /dev/null
+++ b/ACE/examples/Reactor/Multicast/server.cpp
@@ -0,0 +1,247 @@
+// $Id$
+
+// server.cpp (written by Tim Harrison)
+
+// Listens to multicast address for client log messages. Prints
+// Mbits/sec received from client.
+
+#include "ace/OS_main.h"
+#include "ace/SOCK_Dgram.h"
+#include "ace/INET_Addr.h"
+#include "ace/SOCK_Dgram_Mcast.h"
+#include "ace/Reactor.h"
+#include "ace/Log_Msg.h"
+#include "Log_Wrapper.h"
+#include "ace/OS_NS_string.h"
+#include "ace/OS_NS_unistd.h"
+#include "ace/os_include/os_netdb.h"
+
+ACE_RCSID(Multicast, server, "$Id$")
+
+#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 int handle_timeout (const ACE_Time_Value &tv,
+ const void *arg);
+
+ virtual ACE_HANDLE get_handle (void) const;
+
+ ACE_Time_Value *wait_time (void);
+
+private:
+ char *message_;
+ Log_Wrapper::Log_Record *log_record_;
+ char buf_[4 * BUFSIZ];
+ char hostname_[MAXHOSTNAMELEN];
+
+ int initialized_;
+ int count_;
+ long 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_;
+};
+
+static const char MCAST_ADDR[] = ACE_DEFAULT_MULTICAST_ADDR;
+static const int UDP_PORT = ACE_DEFAULT_MULTICAST_PORT;
+static const int DURATION = 5;
+
+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)
+ : initialized_ (0),
+ count_ (1),
+ interval_ (time_interval),
+ mcast_addr_ (port, mcast_addr),
+ total_bytes_received_ (0)
+{
+ // Use ACE_SOCK_Dgram_Mcast factory to subscribe to multicast group.
+
+ if (ACE_OS::hostname (this->hostname_,
+ MAXHOSTNAMELEN) == -1)
+ ACE_ERROR ((LM_ERROR,
+ "%p\n",
+ "hostname"));
+
+ else if (this->mcast_dgram_.subscribe (this->mcast_addr_) == -1)
+ ACE_ERROR ((LM_ERROR,
+ "%p\n",
+ "subscribe"));
+ else
+ {
+ // Point to NULL so that we block in the beginning.
+ this->how_long_ = 0;
+
+ this->log_record_ = (Log_Wrapper::Log_Record *) &buf_;
+ this->message_ = &buf_[sizeof (Log_Wrapper::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_timeout (const ACE_Time_Value &,
+ const void *arg)
+{
+ ACE_DEBUG ((LM_DEBUG, "\t%d timeout%s occurred for %s.\n",
+ this->count_,
+ this->count_ == 1 ? "" : "s",
+ (char *) arg));
+
+ // Don't let the timeouts continue if there's no activity since
+ // otherwise we use up a lot of CPU time unnecessarily.
+ if (this->count_ == 5)
+ {
+ reactor ()->cancel_timer (this);
+ this->initialized_ = 0;
+
+ ACE_DEBUG ((LM_DEBUG,
+ "\tcancelled timeout for %s to avoid busy waiting.\n",
+ (char *) arg));
+ }
+
+ this->count_++;
+ return 0;
+}
+
+int
+Server_Events::handle_input (ACE_HANDLE)
+{
+ // Receive message from multicast group.
+ iovec iovp[2];
+ iovp[0].iov_base = buf_;
+ iovp[0].iov_len = sizeof (log_record_);
+ iovp[1].iov_base = &buf_[sizeof (log_record_)];
+ iovp[1].iov_len = 4 * BUFSIZ - sizeof (log_record_);
+
+ ssize_t retcode =
+ this->mcast_dgram_.recv (iovp,
+ 2,
+ this->remote_addr_);
+ if (retcode != -1)
+ {
+ total_messages_received_++;
+ total_bytes_received_ += retcode;
+ last_sequence_number_ =
+ ntohl (log_record_->sequence_number);
+
+ for (char *message_end = this->message_ + ACE_OS::strlen (this->message_) - 1;
+ ACE_OS::strchr ("\r\n \t", *message_end) != 0;
+ )
+ {
+ *message_end-- = '\0';
+ if (message_end == this->message_)
+ break;
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ "sequence number = %d\n",
+ last_sequence_number_));
+ ACE_DEBUG ((LM_DEBUG,
+ "message = '%s'\n",
+ this->message_));
+
+ if (this->initialized_ == 0)
+ {
+ // Restart the timer since we've received events again.
+ if (reactor()->schedule_timer (this,
+ (void *) this->hostname_,
+ ACE_Time_Value::zero,
+ ACE_Time_Value (DURATION)) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "%p\n",
+ "schedule_timer"),
+ -1);
+ this->initialized_ = 1;
+ }
+
+ this->count_ = 1;
+ return 0;
+ }
+ else
+ return -1;
+}
+
+int
+ACE_TMAIN (int, ACE_TCHAR *[])
+{
+ // Instantiate a server which will receive messages for DURATION
+ // 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));
+
+ ACE_DEBUG ((LM_DEBUG,
+ "starting up server\n"));
+
+ for (;;)
+ reactor.handle_events (server_events.wait_time ());
+
+ ACE_NOTREACHED (return 0;)
+}
+#else
+int
+main (int, 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/ACE/examples/Reactor/Ntalker/.cvsignore b/ACE/examples/Reactor/Ntalker/.cvsignore
new file mode 100644
index 00000000000..a9350d173bf
--- /dev/null
+++ b/ACE/examples/Reactor/Ntalker/.cvsignore
@@ -0,0 +1,2 @@
+ntalker
+ntalker
diff --git a/ACE/examples/Reactor/Ntalker/Makefile.am b/ACE/examples/Reactor/Ntalker/Makefile.am
new file mode 100644
index 00000000000..6efc3521a32
--- /dev/null
+++ b/ACE/examples/Reactor/Ntalker/Makefile.am
@@ -0,0 +1,33 @@
+## Process this file with automake to create Makefile.in
+##
+## $Id$
+##
+## This file was generated by MPC. Any changes made directly to
+## this file will be lost the next time it is generated.
+##
+## MPC Command:
+## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu
+
+ACE_BUILDDIR = $(top_builddir)
+ACE_ROOT = $(top_srcdir)
+
+## Makefile.Reactor_Ntalker.am
+noinst_PROGRAMS = ntalker
+
+ntalker_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+ntalker_SOURCES = \
+ ntalker.cpp
+
+ntalker_LDADD = \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Clean up template repositories, etc.
+clean-local:
+ -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.*
+ -rm -f gcctemp.c gcctemp so_locations *.ics
+ -rm -rf cxx_repository ptrepository ti_files
+ -rm -rf templateregistry ir.out
+ -rm -rf ptrepository SunWS_cache Templates.DB
diff --git a/ACE/examples/Reactor/Ntalker/README b/ACE/examples/Reactor/Ntalker/README
new file mode 100644
index 00000000000..191cef9256f
--- /dev/null
+++ b/ACE/examples/Reactor/Ntalker/README
@@ -0,0 +1,17 @@
+This test program illustrates how the ACE datagram multicast feature
+works. To run the test simply do the following on multiple machines:
+
+# Machine 1
+% ./ntalker
+
+# Machine 2
+% ./ntalker
+
+# Machine 3
+% ./ntalker
+
+Then, on one (or all) of the machines, type input into the keyboard.
+This input will be multicast to all the machines using IP multicast
+via the ACE_SOCK_Dgram_Mcast wrapper.
+
+When you want to shut down the sender, just type ^D.
diff --git a/ACE/examples/Reactor/Ntalker/Reactor_Ntalker.mpc b/ACE/examples/Reactor/Ntalker/Reactor_Ntalker.mpc
new file mode 100644
index 00000000000..ef2fb84d9a0
--- /dev/null
+++ b/ACE/examples/Reactor/Ntalker/Reactor_Ntalker.mpc
@@ -0,0 +1,6 @@
+// -*- MPC -*-
+// $Id$
+
+project : aceexe {
+ exename = ntalker
+}
diff --git a/ACE/examples/Reactor/Ntalker/ntalker.cpp b/ACE/examples/Reactor/Ntalker/ntalker.cpp
new file mode 100644
index 00000000000..80873ead1a9
--- /dev/null
+++ b/ACE/examples/Reactor/Ntalker/ntalker.cpp
@@ -0,0 +1,231 @@
+// $Id$
+
+// Listens to multicast address. After first message received, will
+// listen for 5 more seconds. Prints Mbits/sec received from client.
+
+#include "ace/OS_main.h"
+#include "ace/OS_NS_unistd.h"
+#include "ace/INET_Addr.h"
+#include "ace/SOCK_Dgram_Mcast.h"
+#include "ace/Reactor.h"
+#include "ace/Get_Opt.h"
+#include "ace/Thread_Manager.h"
+#include "ace/Service_Config.h"
+
+ACE_RCSID(Ntalker, ntalker, "$Id$")
+
+#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 ACE_TCHAR *INTERFACE = 0;
+static const char *MCAST_ADDR = ACE_DEFAULT_MULTICAST_ADDR;
+static const u_short UDP_PORT = ACE_DEFAULT_MULTICAST_PORT;
+
+class Handler : public ACE_Event_Handler
+{
+ // = TITLE
+ // Handle both multicast and stdin events.
+public:
+ // = Initialization and termination methods.
+ Handler (u_short udp_port,
+ const char *ip_addr,
+ const ACE_TCHAR *a_interface,
+ ACE_Reactor & );
+ // Constructor.
+
+ ~Handler (void);
+ // Destructor.
+
+ // Event demuxer hooks.
+ virtual int handle_input (ACE_HANDLE);
+ virtual int handle_close (ACE_HANDLE,
+ ACE_Reactor_Mask);
+ virtual ACE_HANDLE get_handle (void) const;
+
+private:
+ ACE_SOCK_Dgram_Mcast mcast_;
+ // Multicast wrapper.
+};
+
+ACE_HANDLE
+Handler::get_handle (void) const
+{
+ return this->mcast_.get_handle ();
+}
+
+int
+Handler::handle_input (ACE_HANDLE h)
+{
+ char buf[BUFSIZ];
+
+ if (h == ACE_STDIN)
+ {
+ ssize_t result = ACE_OS::read (h, buf, BUFSIZ);
+
+ if (result > 0)
+ {
+ if (this->mcast_.send (buf, result) != result)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "%p\n",
+ "send error"),
+ -1);
+ return 0;
+ }
+ else if (result == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "%p\n",
+ "can't read from STDIN"),
+ -1);
+ else // result == 0
+ {
+ ACE_Reactor::end_event_loop ();
+ return -1;
+ }
+ }
+ else
+ {
+ ACE_INET_Addr remote_addr;
+
+ // Receive message from multicast group.
+ ssize_t result = this->mcast_.recv (buf,
+ sizeof buf,
+ remote_addr);
+
+ if (result != -1)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ "received datagram from host %s on port %d bytes = %d\n",
+ remote_addr.get_host_name (),
+ remote_addr.get_port_number (),
+ result));
+ ACE_OS::write (ACE_STDERR, buf, result);
+ ACE_DEBUG ((LM_DEBUG,
+ "\n"));
+ return 0;
+ }
+
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "%p\n",
+ "something amiss"),
+ -1);
+ }
+}
+
+int
+Handler::handle_close (ACE_HANDLE h, ACE_Reactor_Mask)
+{
+ if (h == ACE_STDIN)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ "STDIN_Events handle removed from reactor.\n"));
+ if (ACE_Reactor::instance ()->remove_handler
+ (this, ACE_Event_Handler::READ_MASK) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "%p\n",
+ "remove_handler"),
+ -1);
+ }
+ else
+ ACE_DEBUG ((LM_DEBUG,
+ "Mcast_Events handle removed from reactor.\n"));
+ return 0;
+}
+
+Handler::~Handler (void)
+{
+ if (this->mcast_.unsubscribe () == -1)
+ ACE_ERROR ((LM_ERROR,
+ "%p\n",
+ "unsubscribe fails"));
+}
+
+Handler::Handler (u_short udp_port,
+ const char *ip_addr,
+ const ACE_TCHAR *a_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, a_interface) == -1)
+ {
+ ACE_ERROR ((LM_ERROR,
+ "%p\n",
+ "can't subscribe to multicast group"));
+ }
+ // Disable loopbacks.
+ // if (this->mcast_.set_option (IP_MULTICAST_LOOP, 0) == -1 )
+ // ACE_OS::perror (" can't disable loopbacks " ), ACE_OS::exit (1);
+
+ // Register callbacks with the ACE_Reactor.
+ else if (reactor.register_handler (this->mcast_.get_handle (),
+ this,
+ ACE_Event_Handler::READ_MASK) == -1)
+ ACE_ERROR ((LM_ERROR,
+ "%p\n",
+ "can't register with Reactor\n"));
+ // Register the STDIN handler.
+ else if (ACE_Event_Handler::register_stdin_handler (this,
+ ACE_Reactor::instance (),
+ ACE_Thread_Manager::instance ()) == -1)
+ ACE_ERROR ((LM_ERROR,
+ "%p\n",
+ "register_stdin_handler"));
+}
+
+static void
+parse_args (int argc, ACE_TCHAR *argv[])
+{
+ ACE_Get_Opt get_opt (argc, argv, ACE_TEXT("i:u"));
+
+ int c;
+
+ while ((c = get_opt ()) != -1)
+ switch (c)
+ {
+ case 'i':
+ INTERFACE = get_opt.opt_arg ();
+ break;
+ case 'u':
+ // Usage fallthrough.
+ default:
+ ACE_DEBUG ((LM_DEBUG,
+ "%s -i interface\n",
+ argv[0]));
+ ACE_OS::exit (1);
+ }
+}
+
+int
+ACE_TMAIN (int argc, ACE_TCHAR *argv[])
+{
+ parse_args (argc, argv);
+
+ Handler handler (UDP_PORT,
+ MCAST_ADDR,
+ INTERFACE,
+ *ACE_Reactor::instance ());
+
+ // Run the event loop.
+ ACE_Reactor::run_event_loop ();
+
+ ACE_DEBUG ((LM_DEBUG,
+ "talker Done.\n"));
+ return 0;
+}
+
+#else
+int
+ACE_TMAIN (int, ACE_TCHAR *argv[])
+{
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "error: %s must be run on a platform that support IP multicast\n",
+ argv[0]),
+ 0);
+}
+#endif /* ACE_HAS_IP_MULTICAST */
+
diff --git a/ACE/examples/Reactor/Proactor/.cvsignore b/ACE/examples/Reactor/Proactor/.cvsignore
new file mode 100644
index 00000000000..34179361b75
--- /dev/null
+++ b/ACE/examples/Reactor/Proactor/.cvsignore
@@ -0,0 +1,7 @@
+test_cancel
+test_end_event_loop
+test_multiple_loops
+test_post_completions
+test_proactor
+test_timeout
+test_udp_proactor
diff --git a/ACE/examples/Reactor/Proactor/Aio_Platform_Test_C.cpp b/ACE/examples/Reactor/Proactor/Aio_Platform_Test_C.cpp
new file mode 100644
index 00000000000..be720fdef40
--- /dev/null
+++ b/ACE/examples/Reactor/Proactor/Aio_Platform_Test_C.cpp
@@ -0,0 +1,137 @@
+// $Id$
+// ============================================================================
+//
+// = FILENAME
+// aio_platform_test_c.cpp
+//
+// = DESCRITPTION
+// Testing the platform for POSIX Asynchronous I/O. This is the C
+// version of the $ACE_ROOT/tests/Aio_Platform_Test.cpp. Useful
+// to send bug reports.
+//
+// = AUTHOR
+// Programming for the Real World. Bill O. GallMeister.
+// Modified by Alexander Babu Arulanthu <alex@cs.wustl.edu>
+//
+// =====================================================================
+
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <signal.h>
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+
+#include <limits.h>
+
+#include <aio.h>
+
+int do_sysconf (void);
+int have_asynchio (void);
+
+static int file_handle = -1;
+char mb1 [BUFSIZ + 1];
+char mb2 [BUFSIZ + 1];
+aiocb aiocb1, aiocb2;
+sigset_t completion_signal;
+
+// For testing the <aio> stuff.
+int test_aio_calls (void);
+int issue_aio_calls (void);
+int query_aio_completions (void);
+int setup_signal_delivery (void);
+int do_sysconf (void);
+int have_asynchio (void);
+
+int
+do_sysconf (void)
+{
+ // Call sysconf to find out runtime values.
+ errno = 0;
+#if defined (_SC_LISTIO_AIO_MAX)
+ printf ("Runtime value of LISTIO_AIO_MAX is %d, errno = %d\n",
+ sysconf(_SC_LISTIO_AIO_MAX),
+ errno);
+#else
+ printf ("Runtime value of AIO_LISTIO_MAX is %d, errno = %d\n",
+ sysconf(_SC_AIO_LISTIO_MAX),
+ errno);
+#endif
+
+ errno = 0;
+ printf ("Runtime value of AIO_MAX is %d, errno = %d\n",
+ sysconf (_SC_AIO_MAX),
+ errno);
+
+ errno = 0;
+ printf ("Runtime value of _POSIX_ASYNCHRONOUS_IO is %d, errno = %d\n",
+ sysconf (_SC_ASYNCHRONOUS_IO),
+ errno);
+
+ errno = 0;
+ printf ("Runtime value of _POSIX_REALTIME_SIGNALS is %d, errno = %d\n",
+ sysconf (_SC_REALTIME_SIGNALS),
+ errno);
+
+ errno = 0;
+ printf ("Runtime value of RTSIG_MAX %d, Errno = %d\n",
+ sysconf (_SC_RTSIG_MAX),
+ errno);
+
+ errno = 0;
+ printf ("Runtime value of SIGQUEUE_MAX %d, Errno = %d\n",
+ sysconf (_SC_SIGQUEUE_MAX),
+ errno);
+ return 0;
+}
+
+int
+have_asynchio (void)
+{
+#if defined (_POSIX_ASYNCHRONOUS_IO)
+ // POSIX Asynch IO is present in this system.
+#if defined (_POSIX_ASYNC_IO)
+ // If this is defined and it is not -1, POSIX_ASYNCH is supported
+ // everywhere in the system.
+#if _POSIX_ASYNC_IO == -1
+ printf ("_POSIX_ASYNC_IO = -1.. ASYNCH IO NOT supported at all\n");
+ return -1;
+#else /* Not _POSIX_ASYNC_IO == -1 */
+ printf ("_POSIX_ASYNC_IO = %d\n ASYNCH IO is supported FULLY\n",
+ _POSIX_ASYNC_IO);
+#endif /* _POSIX_ASYNC_IO == -1 */
+
+#else /* Not defined _POSIX_ASYNC_IO */
+ printf ("_POSIX_ASYNC_IO is not defined.\n");
+ printf ("AIO might *not* be supported on some paths\n");
+#endif /* _POSIX_ASYNC_IO */
+
+ // System defined POSIX Values.
+ printf ("System claims to have POSIX_ASYNCHRONOUS_IO\n");
+
+ printf ("_POSIX_AIO_LISTIO_MAX = %d\n", _POSIX_AIO_LISTIO_MAX);
+ printf ("_POSIX_AIO_MAX = %d\n", _POSIX_AIO_MAX);
+
+ // Check and print the run time values.
+ do_sysconf ();
+
+ return 0;
+
+#else /* Not _POSIX_ASYNCHRONOUS_IO */
+ printf ("No support._POSIX_ASYNCHRONOUS_IO itself is not defined\n");
+ return -1;
+#endif /* _POSIX_ASYNCHRONOUS_IO */
+}
+
+int
+main (int, char *[])
+{
+ if (have_asynchio () == 0)
+ printf ("Test successful\n");
+ else
+ printf ("Test not successful\n");
+ return 0;
+}
diff --git a/ACE/examples/Reactor/Proactor/Makefile.am b/ACE/examples/Reactor/Proactor/Makefile.am
new file mode 100644
index 00000000000..7f1bc4b8a57
--- /dev/null
+++ b/ACE/examples/Reactor/Proactor/Makefile.am
@@ -0,0 +1,153 @@
+## Process this file with automake to create Makefile.in
+##
+## $Id$
+##
+## This file was generated by MPC. Any changes made directly to
+## this file will be lost the next time it is generated.
+##
+## MPC Command:
+## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu
+
+ACE_BUILDDIR = $(top_builddir)
+ACE_ROOT = $(top_srcdir)
+
+noinst_PROGRAMS =
+
+## Makefile.Proactor_Cancel.am
+
+if !BUILD_ACE_FOR_TAO
+noinst_PROGRAMS += test_cancel
+
+test_cancel_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+test_cancel_SOURCES = \
+ test_cancel.cpp \
+ test_cancel.h
+
+test_cancel_LDADD = \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_ACE_FOR_TAO
+
+## Makefile.Proactor_End_Event_Loops.am
+
+if !BUILD_ACE_FOR_TAO
+noinst_PROGRAMS += test_end_event_loop
+
+test_end_event_loop_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+test_end_event_loop_SOURCES = \
+ test_end_event_loop.cpp \
+ test_cancel.h \
+ test_proactor.h
+
+test_end_event_loop_LDADD = \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_ACE_FOR_TAO
+
+## Makefile.Proactor_Multiple_Loops.am
+
+if !BUILD_ACE_FOR_TAO
+noinst_PROGRAMS += test_multiple_loops
+
+test_multiple_loops_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+test_multiple_loops_SOURCES = \
+ test_multiple_loops.cpp \
+ test_cancel.h \
+ test_proactor.h
+
+test_multiple_loops_LDADD = \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_ACE_FOR_TAO
+
+## Makefile.Proactor_Post_Completions.am
+
+if !BUILD_ACE_FOR_TAO
+noinst_PROGRAMS += test_post_completions
+
+test_post_completions_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+test_post_completions_SOURCES = \
+ post_completions.cpp \
+ test_cancel.h \
+ test_proactor.h
+
+test_post_completions_LDADD = \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_ACE_FOR_TAO
+
+## Makefile.Proactor_Proactor.am
+
+if !BUILD_ACE_FOR_TAO
+noinst_PROGRAMS += test_proactor
+
+test_proactor_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+test_proactor_SOURCES = \
+ test_proactor.cpp \
+ test_proactor.h
+
+test_proactor_LDADD = \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_ACE_FOR_TAO
+
+## Makefile.Proactor_Timeout.am
+
+if !BUILD_ACE_FOR_TAO
+noinst_PROGRAMS += test_timeout
+
+test_timeout_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+test_timeout_SOURCES = \
+ test_timeout.cpp \
+ test_cancel.h \
+ test_proactor.h
+
+test_timeout_LDADD = \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_ACE_FOR_TAO
+
+## Makefile.Proactor_Udp_Proactor.am
+
+if !BUILD_ACE_FOR_TAO
+noinst_PROGRAMS += test_udp_proactor
+
+test_udp_proactor_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+test_udp_proactor_SOURCES = \
+ test_udp_proactor.cpp \
+ test_cancel.h \
+ test_proactor.h
+
+test_udp_proactor_LDADD = \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_ACE_FOR_TAO
+
+## Clean up template repositories, etc.
+clean-local:
+ -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.*
+ -rm -f gcctemp.c gcctemp so_locations *.ics
+ -rm -rf cxx_repository ptrepository ti_files
+ -rm -rf templateregistry ir.out
+ -rm -rf ptrepository SunWS_cache Templates.DB
diff --git a/ACE/examples/Reactor/Proactor/Proactor.mpc b/ACE/examples/Reactor/Proactor/Proactor.mpc
new file mode 100644
index 00000000000..c2c52207ca1
--- /dev/null
+++ b/ACE/examples/Reactor/Proactor/Proactor.mpc
@@ -0,0 +1,59 @@
+// -*- MPC -*-
+// $Id$
+
+project(*cancel) : aceexe {
+ avoids += ace_for_tao
+ exename = test_cancel
+ Source_Files {
+ test_cancel.cpp
+ }
+}
+
+project(*end_event_loops) : aceexe {
+ avoids += ace_for_tao
+ exename = test_end_event_loop
+ Source_Files {
+ test_end_event_loop.cpp
+ }
+}
+
+project(*multiple_loops) : aceexe {
+ avoids += ace_for_tao
+ exename = test_multiple_loops
+ Source_Files {
+ test_multiple_loops.cpp
+ }
+}
+
+project(*post_completions) : aceexe {
+ avoids += ace_for_tao
+ exename = test_post_completions
+ Source_Files {
+ post_completions.cpp
+ }
+}
+
+project(*proactor) : aceexe {
+ avoids += ace_for_tao
+ exename = test_proactor
+ Source_Files {
+ test_proactor.cpp
+ }
+}
+
+project(*timeout) : aceexe {
+ avoids += ace_for_tao
+ exename = test_timeout
+ Source_Files {
+ test_timeout.cpp
+ }
+}
+
+project(*udp_proactor) : aceexe {
+ avoids += ace_for_tao
+ exename = test_udp_proactor
+ Source_Files {
+ test_udp_proactor.cpp
+ }
+}
+
diff --git a/ACE/examples/Reactor/Proactor/README b/ACE/examples/Reactor/Proactor/README
new file mode 100644
index 00000000000..29f2a0b1832
--- /dev/null
+++ b/ACE/examples/Reactor/Proactor/README
@@ -0,0 +1,75 @@
+$Id$
+
+This README file lists all the example applications for the Proactor framework.
+
+Test/Example Applications for Proactor:
+=========================================
+
+The following tests are available.
+
+o $ACE_ROOT/tests/Aio_Platform_Test.cpp : Tests basic limits
+ pertaining to the POSIX features
+
+o $ACE_ROOT/examples/Reactor/Proactor/test_aiocb.cpp :
+ This is a C++ program for testing the AIOCB (AIO Control
+ Blocks) based completion approach which uses <aio_suspend> for
+ completion querying.
+
+o $ACE_ROOT/examples/Reactor/Proactor/test_aiosig.cpp : This is a
+ C++ program for testing the Signal based completion approach
+ that uses <sigtimedwait> for completion querying.
+
+o $ACE_ROOT/examples/Reactor/Proactor/test_aiocb_ace.cpp: Portable
+ version of test_aiocb.cpp. (Same as test_aiocb.cpp, but uses
+ ACE_DEBUGs instead of printf's and ACE_Message_Blocks instead
+ of char*'s.
+
+o $ACE_ROOT/examples/Reactor/Proactor/test_aiosig_ace.cpp: Portable
+ version of test_aiosig.cpp. (Same as test_aiosig.cpp, but uses
+ ACE_DEBUGs instead of printf's and ACE_Message_Blocks instead
+ of char*'s.
+
+o test_proactor.cpp (with ACE_POSIX_AIOCB_Proactor) : Test for
+ ACE_Proactor which uses AIOCB (AIO Control Blocks) based
+ completions strategy Proactor. (#define
+ ACE_POSIX_AIOCB_PROACTOR in the config file, but this is the
+ default option)
+
+o test_proactor.cpp (with ACE_POSIX_SIG_Proactor) : Test for
+ ACE_Proactor which uses real time signal based completion
+ strategy proactor. (#define ACE_POSIX_SIG_PROACTOR in the
+ config file)
+
+o test_multiple_loops.cpp : This example application shows how
+ to write programs that combine the Proactor and Reactor event
+ loops. This is possible only on WIN32 platform.
+
+o test_timeout.cpp : Multithreaded application testing the Timers
+ mechanism of the Proactor.
+
+o test_timeout_st.cpp : Single-threaded version of test_timeout.cpp.
+
+o post_completions.cpp : Tests the completion posting mechanism of
+ the Proactor.
+
+o test_end_event_loop.cpp : Tests the event loop mechanism of the
+ Proactor.
+
+o test_cancel.cpp : Tests <cancel> interface of the
+ Asynch_Operation class.
+
+Behavior of POSIX AIO of various platforms:
+==========================================
+
+Sun 5.6 : POSIX4 Real-Time signals implementation is broken in
+ this platform.
+ Only POSIX AIOCB Proactor works in this platform.
+ Therefore, it is not possible to use multiple threads
+ with in the framework.
+
+Sun 5.7 : AIOCB and SIG Proactors work fine.
+
+LynxOS 3.0.0 : <pthread_sigmask> is not available in this
+ platform. So, only AIOCB Proactor works here.
+
+
diff --git a/ACE/examples/Reactor/Proactor/post_completions.cpp b/ACE/examples/Reactor/Proactor/post_completions.cpp
new file mode 100644
index 00000000000..e6545241953
--- /dev/null
+++ b/ACE/examples/Reactor/Proactor/post_completions.cpp
@@ -0,0 +1,306 @@
+// $Id$
+// ============================================================================
+//
+// = FILENAME
+// post_completions.cpp
+//
+// = DESCRITPTION
+// This program demonstrates how to post fake completions to The
+// Proactor. It also shows the how to specify the particular
+// real-time signals to post completions. The Real-time signal
+// based completion strategy is implemented with
+// ACE_POSIX_SIG_PROACTOR.
+// (So, it can be used only if both ACE_HAS_AIO_CALLS and
+// ACE_HAS_POSIX_REALTIME_SIGNALS are defined.)
+// Since it is faking results, you have to pay by knowing and
+// using platform-specific implementation objects for Asynchronous
+// Result classes.
+// This example shows using an arbitrary result class for faking
+// completions. You can also use the predefined Result classes for
+// faking. The factory methods in the Proactor class create the
+// Result objects.
+//
+// = COMPILATION
+// make
+//
+// = RUN
+// ./post_completions
+//
+// = AUTHOR
+// Alexander Babu Arulanthu <alex@cs.wustl.edu>
+//
+// =====================================================================
+
+#include "ace/OS_NS_unistd.h"
+#include "ace/OS_main.h"
+#include "ace/Proactor.h"
+#include "ace/Task.h"
+#include "ace/WIN32_Proactor.h"
+#include "ace/POSIX_Proactor.h"
+#include "ace/Atomic_Op.h"
+#include "ace/Thread_Mutex.h"
+
+// Keep track of how many completions are still expected.
+static ACE_Atomic_Op <ACE_SYNCH_MUTEX, size_t> Completions_To_Go;
+
+
+#if (defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)) || \
+ defined (ACE_HAS_AIO_CALLS)
+// This only works on Win32 platforms and on Unix platforms supporting
+// POSIX aio calls.
+
+#if defined (ACE_HAS_AIO_CALLS)
+#define RESULT_CLASS ACE_POSIX_Asynch_Result
+#elif defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)
+#define RESULT_CLASS ACE_WIN32_Asynch_Result
+#endif /* ACE_HAS_AIO_CALLS */
+
+class My_Result : public RESULT_CLASS
+{
+ // = TITLE
+ //
+ // Result Object that we will post to the Proactor.
+ //
+ // = DESCRIPTION
+ //
+
+public:
+ My_Result (ACE_Handler &handler,
+ const void *act,
+ int signal_number,
+ size_t sequence_number)
+ : RESULT_CLASS (handler.proxy (),
+ act,
+ ACE_INVALID_HANDLE,
+ 0, // Offset
+ 0, // OffsetHigh
+ 0, // Priority
+ signal_number),
+ sequence_number_ (sequence_number)
+ {}
+ // Constructor.
+
+ virtual ~My_Result (void)
+ {}
+ // Destructor.
+
+ void complete (size_t,
+ int success,
+ const void *completion_key,
+ u_long error)
+ // This is the method that will be called by the Proactor for
+ // dispatching the completion. This method generally calls one of
+ // the call back hood methods defined in the ACE_Handler
+ // class. But, we will just handle the completions here.
+ {
+ this->success_ = success;
+ this->completion_key_ = completion_key;
+ this->error_ = error;
+
+ size_t to_go = --Completions_To_Go;
+
+ // Print the completion details.
+ ACE_DEBUG ((LM_DEBUG,
+ "(%t) Completion sequence number %d, success : %d, error : %d, signal_number : %d, %u more to go\n",
+ this->sequence_number_,
+ this->success_,
+ this->error_,
+ this->signal_number (),
+ to_go));
+
+ // Sleep for a while.
+ ACE_OS::sleep (4);
+ }
+
+private:
+ size_t sequence_number_;
+ // Sequence number for the result object.
+};
+
+class My_Handler : public ACE_Handler
+{
+ // = TITLE
+ //
+ // Handler class for faked completions.
+ //
+ // = DESCRIPTION
+ //
+
+public:
+ My_Handler (void) {}
+ // Constructor.
+
+ virtual ~My_Handler (void) {}
+ // Destructor.
+};
+
+class My_Task: public ACE_Task <ACE_NULL_SYNCH>
+{
+ // = TITLE
+ //
+ // Contains thread functions which execute event loops. Each
+ // thread waits for a different signal.
+ //
+public:
+ My_Task (void) {}
+ // Constructor.
+
+ virtual ~My_Task (void) {}
+ // Destructor.
+
+ int open (void *proactor)
+ {
+ // Store the proactor.
+ this->proactor_ = (ACE_Proactor *) proactor;
+
+ // Activate the Task.
+ this->activate (THR_NEW_LWP, 5);
+ return 0;
+ }
+
+ int svc (void)
+ {
+ // Handle events for 13 seconds.
+ ACE_Time_Value run_time (13);
+
+ ACE_DEBUG ((LM_DEBUG, "(%t):Starting svc routine\n"));
+
+ if (this->proactor_->handle_events (run_time) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "(%t):%p.\n", "Worker::svc"), -1);
+
+ ACE_DEBUG ((LM_DEBUG, "(%t) work complete\n"));
+
+ return 0;
+ }
+
+private:
+ ACE_Proactor *proactor_;
+ // Proactor for this task.
+};
+
+int
+ACE_TMAIN (int argc, ACE_TCHAR *argv[])
+{
+ ACE_UNUSED_ARG (argc);
+ ACE_UNUSED_ARG (argv);
+
+ ACE_DEBUG ((LM_DEBUG,
+ "(%P | %t):Test starts \n"));
+
+ // = Get two POSIX_SIG_Proactors, one with SIGRTMIN and one with
+ // SIGRTMAX.
+
+ ACE_Proactor proactor1;
+ // Proactor1. SIGRTMIN Proactor. (default).
+
+ // = Proactor2. SIGRTMAX Proactor.
+#if defined (ACE_HAS_AIO_CALLS) && defined (ACE_HAS_POSIX_REALTIME_SIGNALS)
+
+ ACE_DEBUG ((LM_DEBUG, "Using ACE_POSIX_SIG_Proactor\n"));
+
+ sigset_t signal_set;
+ // Signal set that we want to mask.
+
+ // Clear the signal set.
+ if (sigemptyset (&signal_set) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "Error:%p\n",
+ "sigemptyset failed"),
+ 1);
+
+ // Add the SIGRTMAX to the signal set.
+ if (sigaddset (&signal_set, ACE_SIGRTMAX) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "Error:%p\n",
+ "sigaddset failed"),
+ 1);
+
+ // Make the POSIX Proactor.
+ ACE_POSIX_SIG_Proactor posix_proactor (signal_set);
+ // Get the Proactor interface out of it.
+ ACE_Proactor proactor2 (&posix_proactor);
+#else /* ACE_HAS_AIO_CALLS && ACE_HAS_POSIX_REALTIME_SIGNALS */
+ ACE_Proactor proactor2;
+#endif /* ACE_HAS_AIO_CALLS && ACE_HAS_POSIX_REALTIME_SIGNALS */
+
+ // = Create Tasks. One pool of threads to handle completions on
+ // SIGRTMIN and the other one to handle completions on SIGRTMAX.
+ My_Task task1, task2;
+ task1.open (&proactor1);
+ task2.open (&proactor2);
+
+ // Handler for completions.
+ My_Handler handler;
+
+ // = Create a few MyResult objects and post them to Proactor.
+ const size_t NrCompletions (10);
+ My_Result *result_objects [NrCompletions];
+ int signal_number = ACE_SIGRTMAX;
+ size_t ri = 0;
+
+ Completions_To_Go = NrCompletions;
+
+ // Creation.
+ for (ri = 0; ri < NrCompletions; ri++)
+ {
+ // Use RTMIN and RTMAX proactor alternatively, to post
+ // completions.
+ if (ri % 2)
+ signal_number = ACE_SIGRTMIN;
+ else
+ signal_number = ACE_SIGRTMAX;
+ // Create the result.
+ ACE_NEW_RETURN (result_objects [ri],
+ My_Result (handler,
+ 0,
+ signal_number,
+ ri),
+ 1);
+ }
+ ACE_OS::sleep(5);
+ // Post all the result objects.
+ ACE_Proactor *proactor;
+ for (ri = 0; ri < NrCompletions; ri++)
+ {
+ // Use RTMIN and RTMAX Proactor alternatively, to post
+ // completions.
+ if (ri % 2)
+ proactor = &proactor1;
+ else
+ proactor = &proactor2;
+ if (result_objects [ri]->post_completion (proactor->implementation ())
+ == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "Test failed\n"),
+ 1);
+ }
+
+ ACE_Thread_Manager::instance ()->wait ();
+
+ int status = 0;
+ size_t to_go = Completions_To_Go.value ();
+ if (size_t (0) != to_go)
+ {
+ ACE_ERROR ((LM_ERROR,
+ "Fail! Expected all completions to finish but %u to go\n",
+ to_go));
+ status = 1;
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ "(%P | %t):Test ends\n"));
+ return status;
+}
+
+#else /* ACE_WIN32 && !ACE_HAS_WINCE || ACE_HAS_AIO_CALLS && !ACE_POSIX_AIOCB_PROACTOR*/
+
+int
+main (int, char *[])
+{
+ ACE_DEBUG ((LM_DEBUG,
+ "This example cannot work with AIOCB_Proactor.\n"));
+ return 1;
+}
+
+#endif /* ACE_WIN32 && !ACE_HAS_WINCE || ACE_HAS_AIO_CALLS && !ACE_POSIX_AIOCB_PROACTOR*/
+
diff --git a/ACE/examples/Reactor/Proactor/simple_test_proactor.cpp b/ACE/examples/Reactor/Proactor/simple_test_proactor.cpp
new file mode 100644
index 00000000000..1f4557d7df5
--- /dev/null
+++ b/ACE/examples/Reactor/Proactor/simple_test_proactor.cpp
@@ -0,0 +1,269 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// examples
+//
+// = FILENAME
+// simple_test_proactor.cpp
+//
+// = DESCRIPTION
+// Very simple version of test_proactor.cpp.
+//
+// = AUTHOR
+// Alexander Babu Arulanthu (alex@cs.wustl.edu)
+//
+// ============================================================================
+
+#include "ace/Service_Config.h"
+#include "ace/Proactor.h"
+#include "ace/Asynch_IO.h"
+#include "ace/Asynch_IO_Impl.h"
+#include "ace/Message_Block.h"
+#include "ace/Get_Opt.h"
+#include "ace/OS_main.h"
+
+ACE_RCSID(Proactor, test_proactor, "simple_test_proactor.cpp,v 1.1 1999/05/18 22:15:30 alex Exp")
+
+#if ((defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)) || (defined (ACE_HAS_AIO_CALLS)))
+ // This only works on Win32 platforms and on Unix platforms supporting
+ // POSIX aio calls.
+
+static ACE_TCHAR *file = ACE_TEXT("simple_test_proactor.cpp");
+static ACE_TCHAR *dump_file = ACE_TEXT("simple_output");
+
+class Simple_Tester : public ACE_Handler
+{
+ // = TITLE
+ //
+ // Simple_Tester
+ //
+ // = DESCRIPTION
+ //
+ // The class will be created by main(). This class reads a block
+ // from the file and write that to the dump file.
+
+public:
+ Simple_Tester (void);
+ // Constructor.
+
+ ~Simple_Tester (void);
+
+ int open (void);
+ // Open the operations and initiate read from the file.
+
+protected:
+ // = These methods are called by the freamwork.
+
+ virtual void handle_read_file (const ACE_Asynch_Read_File::Result &result);
+ // This is called when asynchronous reads from the socket complete.
+
+ virtual void handle_write_file (const ACE_Asynch_Write_File::Result &result);
+ // This is called when asynchronous writes from the socket complete.
+
+private:
+ int initiate_read_file (void);
+
+ ACE_Asynch_Read_File rf_;
+ // rf (read file): for writing from the file.
+
+ ACE_Asynch_Write_File wf_;
+ // ws (write File): for writing to the file.
+
+ ACE_HANDLE input_file_;
+ // File to read from.
+
+ ACE_HANDLE dump_file_;
+ // File for dumping data.
+
+ // u_long file_offset_;
+ // Current file offset
+
+ // u_long file_size_;
+ // File size
+};
+
+
+Simple_Tester::Simple_Tester (void)
+ : input_file_ (ACE_INVALID_HANDLE),
+ dump_file_ (ACE_INVALID_HANDLE)
+{
+}
+
+Simple_Tester::~Simple_Tester (void)
+{
+ ACE_OS::close (this->input_file_);
+ ACE_OS::close (this->dump_file_);
+}
+
+
+int
+Simple_Tester::open (void)
+{
+ // Initialize stuff
+
+ // Open input file (in OVERLAPPED mode)
+ this->input_file_ = ACE_OS::open (file,
+ GENERIC_READ | FILE_FLAG_OVERLAPPED);
+ if (this->input_file_ == ACE_INVALID_HANDLE)
+ ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "ACE_OS::open"), -1);
+
+ // Open dump file (in OVERLAPPED mode)
+ this->dump_file_ = ACE_OS::open (dump_file,
+ O_CREAT | O_RDWR | O_TRUNC | FILE_FLAG_OVERLAPPED,
+ 0644);
+ if (this->dump_file_ == ACE_INVALID_HANDLE)
+ ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "ACE_OS::open"), -1);
+
+ // Open ACE_Asynch_Read_File
+ if (this->rf_.open (*this, this->input_file_) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "ACE_Asynch_Read_File::open"), -1);
+
+ // Open ACE_Asynch_Write_File
+ if (this->wf_.open (*this, this->dump_file_) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "ACE_Asynch_Write_File::open"), -1);
+
+ ACE_DEBUG ((LM_DEBUG,
+ "Simple_Tester::open: Files and Asynch Operations opened sucessfully\n"));
+
+
+ // Start an asynchronous read file
+ if (this->initiate_read_file () == -1)
+ return -1;
+
+ return 0;
+}
+
+
+int
+Simple_Tester::initiate_read_file (void)
+{
+ // Create Message_Block
+ ACE_Message_Block *mb = 0;
+ ACE_NEW_RETURN (mb, ACE_Message_Block (BUFSIZ + 1), -1);
+
+ // Inititiate an asynchronous read from the file
+ if (this->rf_.read (*mb,
+ mb->size () - 1) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "ACE_Asynch_Read_File::read"), -1);
+
+ ACE_DEBUG ((LM_DEBUG,
+ "Simple_Tester:initiate_read_file: Asynch Read File issued sucessfully\n"));
+
+ return 0;
+}
+
+void
+Simple_Tester::handle_read_file (const ACE_Asynch_Read_File::Result &result)
+{
+ ACE_DEBUG ((LM_DEBUG, "handle_read_file called\n"));
+
+ result.message_block ().rd_ptr ()[result.bytes_transferred ()] = '\0';
+
+ ACE_DEBUG ((LM_DEBUG, "********************\n"));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "bytes_to_read", result.bytes_to_read ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "handle", result.handle ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "bytes_transfered", result.bytes_transferred ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "act", (u_long) result.act ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "success", result.success ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "completion_key", (u_long) result.completion_key ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "error", result.error ()));
+ ACE_DEBUG ((LM_DEBUG, "********************\n"));
+ // Watch out if you need to enable this... the ACE_Log_Record::MAXLOGMSGLEN
+ // value controls to max length of a log record, and a large output
+ // buffer may smash it.
+#if 0
+ ACE_DEBUG ((LM_DEBUG, "%s = %s\n",
+ "message_block",
+ result.message_block ().rd_ptr ()));
+#endif /* 0 */
+
+ if (result.success ())
+ {
+ // Read successful: write this to the file.
+ if (this->wf_.write (result.message_block (),
+ result.bytes_transferred ()) == -1)
+ {
+ ACE_ERROR ((LM_ERROR, "%p\n", "ACE_Asynch_Write_File::write"));
+ return;
+ }
+ }
+}
+
+void
+Simple_Tester::handle_write_file (const ACE_Asynch_Write_File::Result &result)
+{
+ ACE_DEBUG ((LM_DEBUG, "handle_write_File called\n"));
+
+ // Reset pointers
+ result.message_block ().rd_ptr (result.message_block ().rd_ptr () - result.bytes_transferred ());
+
+ result.message_block ().rd_ptr ()[result.bytes_transferred ()] = '\0';
+
+ ACE_DEBUG ((LM_DEBUG, "********************\n"));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "bytes_to_write", result.bytes_to_write ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "handle", result.handle ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "bytes_transfered", result.bytes_transferred ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "act", (u_long) result.act ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "success", result.success ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "completion_key", (u_long) result.completion_key ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "error", result.error ()));
+ ACE_DEBUG ((LM_DEBUG, "********************\n"));
+ // Watch out if you need to enable this... the ACE_Log_Record::MAXLOGMSGLEN
+ // value controls to max length of a log record, and a large output
+ // buffer may smash it.
+#if 0
+ ACE_DEBUG ((LM_DEBUG, "%s = %s\n",
+ "message_block",
+ result.message_block ().rd_ptr ()));
+#endif /* 0 */
+ ACE_Proactor::end_event_loop ();
+}
+
+static int
+parse_args (int argc, ACE_TCHAR *argv[])
+{
+ ACE_Get_Opt get_opt (argc, argv, ACE_TEXT("f:d:"));
+ int c;
+
+ while ((c = get_opt ()) != EOF)
+ switch (c)
+ {
+ case 'f':
+ file = get_opt.opt_arg ();
+ break;
+ case 'd':
+ dump_file = get_opt.opt_arg ();
+ break;
+ default:
+ ACE_ERROR ((LM_ERROR, "%p.\n",
+ "usage :\n"
+ "-d <dumpfile>\n"
+ "-f <file>\n"));
+ return -1;
+ }
+
+ return 0;
+}
+
+int
+ACE_TMAIN (int argc, ACE_TCHAR *argv[])
+{
+ if (parse_args (argc, argv) == -1)
+ return -1;
+
+ Simple_Tester Simple_Tester;
+
+ if (Simple_Tester.open () == -1)
+ return -1;
+
+ int success = 1;
+
+ // dispatch events
+ success = !(ACE_Proactor::run_event_loop () == -1);
+
+ return success ? 0 : 1;
+}
+
+#endif /* ACE_WIN32 && !ACE_HAS_WINCE || ACE_HAS_AIO_CALLS*/
diff --git a/ACE/examples/Reactor/Proactor/test_aiocb.cpp b/ACE/examples/Reactor/Proactor/test_aiocb.cpp
new file mode 100644
index 00000000000..c9c0d280f1b
--- /dev/null
+++ b/ACE/examples/Reactor/Proactor/test_aiocb.cpp
@@ -0,0 +1,239 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// proactor
+//
+// = FILENAME
+// test_aiocb.cpp
+//
+// = DESCRIPTION
+// Checkout $ACE_ROOT/examples/Reactor/Proactor/test_aiocb_ace.cpp,
+// which is the ACE'ified version of this program.
+//
+// = COMPILE and RUN
+// % CC -g -o test_aiocb -lrt test_aiocb.cpp
+// % ./test_aiocb
+//
+// = AUTHOR
+// Alexander Babu Arulanthu <alex@cs.wustl.edu>
+//
+// ============================================================================
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <signal.h>
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+#include <iostream.h>
+
+#include <aio.h>
+
+class Test_Aio
+{
+public:
+ Test_Aio (void);
+ // Default constructor.
+
+ int init (void);
+ // Initting the output file and the buffer.
+
+ int do_aio (void);
+ // Doing the testing stuff.
+
+ ~Test_Aio (void);
+ // Destructor.
+private:
+ int out_fd_;
+ // Output file descriptor.
+
+ struct aiocb *aiocb_write_;
+ // For writing to the file.
+
+ struct aiocb *aiocb_read_;
+ // Reading stuff from the file.
+
+ char *buffer_write_;
+ // The buffer to be written to the out_fd.
+
+ char *buffer_read_;
+ // The buffer to be read back from the file.
+};
+
+Test_Aio::Test_Aio (void)
+ : aiocb_write_ (new struct aiocb),
+ aiocb_read_ (new struct aiocb),
+ buffer_write_ (0),
+ buffer_read_ (0)
+{
+}
+
+Test_Aio::~Test_Aio (void)
+{
+ delete aiocb_write_;
+ delete aiocb_read_;
+ delete buffer_write_;
+ delete buffer_read_;
+}
+
+// Init the output file and init the buffer.
+int
+Test_Aio::init (void)
+{
+ // Open the output file.
+ this->out_fd_ = open ("test_aio.log", O_RDWR | O_CREAT | O_TRUNC, 0666);
+ if (this->out_fd_ == 0)
+ {
+ cout << "Error : Opening file" << endl;
+ return -1;
+ }
+
+ // Init the buffers.
+ this->buffer_write_ = strdup ("Welcome to the world of AIO... AIO Rules !!!");
+ cout << "The buffer : " << this->buffer_write_ << endl;
+ this->buffer_read_ = new char [strlen (this->buffer_write_) + 1];
+ return 0;
+}
+
+// Set the necessary things for the AIO stuff.
+// Write the buffer asynchly.hmm Disable signals.
+// Go on aio_suspend. Wait for completion.
+// Print out the result.
+int
+Test_Aio::do_aio (void)
+{
+ // = Write to the file.
+
+ // Setup AIOCB.
+ this->aiocb_write_->aio_fildes = this->out_fd_;
+ this->aiocb_write_->aio_offset = 0;
+ this->aiocb_write_->aio_buf = this->buffer_write_;
+ this->aiocb_write_->aio_nbytes = strlen (this->buffer_write_);
+ this->aiocb_write_->aio_reqprio = 0;
+ this->aiocb_write_->aio_sigevent.sigev_notify = SIGEV_NONE;
+ //this->this->aiocb_.aio_sigevent.sigev_signo = SIGRTMAX;
+ this->aiocb_write_->aio_sigevent.sigev_value.sival_ptr =
+ (void *) this->aiocb_write_;
+
+ // Fire off the aio write.
+ if (aio_write (this->aiocb_write_) != 0)
+ {
+ perror ("aio_write");
+ return -1;
+ }
+
+ // = Read from that file.
+
+ // Setup AIOCB.
+ this->aiocb_read_->aio_fildes = this->out_fd_;
+ this->aiocb_read_->aio_offset = 0;
+ this->aiocb_read_->aio_buf = this->buffer_read_;
+ this->aiocb_read_->aio_nbytes = strlen (this->buffer_write_);
+ this->aiocb_read_->aio_reqprio = 0;
+ this->aiocb_read_->aio_sigevent.sigev_notify = SIGEV_NONE;
+ //this->this->aiocb_.aio_sigevent.sigev_signo = SIGRTMAX;
+ this->aiocb_read_->aio_sigevent.sigev_value.sival_ptr =
+ (void *) this->aiocb_read_;
+
+ // Fire off the aio write. If it doesnt get queued, carry on to get
+ // the completion for the first one.
+ if (aio_read (this->aiocb_read_) < 0)
+ perror ("aio_read");
+
+ // Wait for the completion on aio_suspend.
+ struct aiocb *list_aiocb[2];
+ list_aiocb [0] = this->aiocb_write_;
+ list_aiocb [1] = this->aiocb_read_;
+
+ // Do suspend till all the aiocbs in the list are done.
+ int done = 0;
+ int return_val = 0;
+ while (!done)
+ {
+ return_val = aio_suspend (list_aiocb,
+ 2,
+ 0);
+ cerr << "Return value :" << return_val << endl;
+
+ // Analyze return and error values.
+ if (list_aiocb[0] != 0)
+ {
+ if (aio_error (list_aiocb [0]) != EINPROGRESS)
+ {
+ if (aio_return (list_aiocb [0]) == -1)
+ {
+ perror ("aio_return");
+ return -1;
+ }
+ else
+ {
+ // Successful. Store the pointer somewhere and make the
+ // entry NULL in the list.
+ this->aiocb_write_ = list_aiocb [0];
+ list_aiocb [0] = 0;
+ }
+ }
+ else
+ cout << "AIO write in progress" << endl;
+ }
+
+ if (list_aiocb[1] != 0)
+ {
+ if (aio_error (list_aiocb [1]) != EINPROGRESS)
+ {
+ int read_return = aio_return (list_aiocb[1]);
+ if (read_return == -1)
+ {
+ perror ("aio_return");
+ return -1;
+ }
+ else
+ {
+ // Successful. Store the pointer somewhere and make the
+ // entry NULL in the list.
+ this->aiocb_read_ = list_aiocb [1];
+ list_aiocb [1] = 0;
+ this->buffer_read_[read_return] = '\0';
+ }
+ }
+ else
+ cout << "AIO read in progress" << endl;
+ }
+
+ // Is it done?
+ if ((list_aiocb [0] == 0) && (list_aiocb [1] == 0))
+ done = 1;
+ }
+
+ cout << "Both the AIO operations done." << endl;
+ cout << "The buffer is :" << this->buffer_read_ << endl;
+
+ return 0;
+}
+
+int
+main (int argc, char **argv)
+{
+ Test_Aio test_aio;
+
+ if (test_aio.init () != 0)
+ {
+ printf ("AIOCB test failed:\n"
+ "ACE_POSIX_AIOCB_PROACTOR may not work in this platform\n");
+ return -1;
+ }
+
+ if (test_aio.do_aio () != 0)
+ {
+ printf ("AIOCB test failed:\n"
+ "ACE_POSIX_AIOCB_PROACTOR may not work in this platform\n");
+ return -1;
+ }
+ printf ("AIOCB test successful:\n"
+ "ACE_POSIX_AIOCB_PROACTOR should work in this platform\n");
+ return 0;
+}
diff --git a/ACE/examples/Reactor/Proactor/test_aiocb_ace.cpp b/ACE/examples/Reactor/Proactor/test_aiocb_ace.cpp
new file mode 100644
index 00000000000..17705de1f03
--- /dev/null
+++ b/ACE/examples/Reactor/Proactor/test_aiocb_ace.cpp
@@ -0,0 +1,259 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// proactor
+//
+// = FILENAME
+// test_aiocb_ace.cpp
+//
+// = DESCRIPTION
+// This program helps you to test the <aio_*> calls on a
+// platform.
+//
+// Before running this test, make sure the platform can
+// support POSIX <aio_> calls, using
+// ACE_ROOT/tests/Aio_Platform_Test.
+//
+// This program tests the AIOCB (AIO Control Blocks) based
+// completion approach which uses <aio_suspend> for completion
+// querying.
+//
+// If this test is successful, ACE_POSIX_AIOCB_PROACTOR
+// can be used on this platform.
+//
+// = COMPILE and RUN
+// % make
+// % ./test_aiocb_ace
+//
+// = AUTHOR
+// Alexander Babu Arulanthu <alex@cs.wustl.edu>
+//
+// ============================================================================
+
+#include "ace/ACE.h"
+#include "ace/Log_Msg.h"
+#include "ace/os_include/os_aio.h"
+#include "ace/OS_NS_string.h"
+
+class Test_Aio
+{
+public:
+ Test_Aio (void);
+ // Default constructor.
+
+ int init (void);
+ // Initting the output file and the buffer.
+
+ int do_aio (void);
+ // Doing the testing stuff.
+
+ ~Test_Aio (void);
+ // Destructor.
+private:
+ int out_fd_;
+ // Output file descriptor.
+
+ struct aiocb *aiocb_write_;
+ // For writing to the file.
+
+ struct aiocb *aiocb_read_;
+ // Reading stuff from the file.
+
+ char *buffer_write_;
+ // The buffer to be written to the out_fd.
+
+ char *buffer_read_;
+ // The buffer to be read back from the file.
+};
+
+Test_Aio::Test_Aio (void)
+ : aiocb_write_ (0),
+ aiocb_read_ (0),
+ buffer_write_ (0),
+ buffer_read_ (0)
+{
+ ACE_NEW (this->aiocb_write_,
+ struct aiocb);
+ ACE_NEW (this->aiocb_read_,
+ struct aiocb);
+}
+
+Test_Aio::~Test_Aio (void)
+{
+ delete aiocb_write_;
+ delete aiocb_read_;
+ delete buffer_write_;
+ delete buffer_read_;
+}
+
+// Init the output file and init the buffer.
+int
+Test_Aio::init (void)
+{
+ // Open the output file.
+ this->out_fd_ = ACE_OS::open ("test_aio.log",
+ O_RDWR | O_CREAT | O_TRUNC,
+ 0666);
+ if (this->out_fd_ == 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "Error: Opening file\n"),
+ -1);
+
+ // Init the buffers.
+ this->buffer_write_ = ACE::strnew ("Welcome to the world of AIO... AIO Rules !!!");
+ ACE_DEBUG ((LM_DEBUG,
+ "The buffer : %s\n",
+ this->buffer_write_));
+
+ // Allocate memory for the read buffer.
+ ACE_NEW_RETURN (this->buffer_read_,
+ char [ACE_OS::strlen (this->buffer_write_)],
+ -1);
+
+ return 0;
+}
+
+// Set the necessary things for the AIO stuff.
+// Write the buffer asynchly.hmm Disable signals.
+// Go on aio_suspend. Wait for completion.
+// Print out the result.
+int
+Test_Aio::do_aio (void)
+{
+ // = Write to the file.
+
+ // Setup AIOCB.
+ this->aiocb_write_->aio_fildes = this->out_fd_;
+ this->aiocb_write_->aio_offset = 0;
+ this->aiocb_write_->aio_buf = this->buffer_write_;
+ this->aiocb_write_->aio_nbytes = ACE_OS::strlen (this->buffer_write_);
+ this->aiocb_write_->aio_reqprio = 0;
+ this->aiocb_write_->aio_sigevent.sigev_notify = SIGEV_NONE;
+ //this->this->aiocb_.aio_sigevent.sigev_signo = SIGRTMAX;
+ this->aiocb_write_->aio_sigevent.sigev_value.sival_ptr =
+ (void *) this->aiocb_write_;
+
+ // Fire off the aio write.
+ if (aio_write (this->aiocb_write_) != 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "%p\n",
+ "aio_write"),
+ -1);
+
+ // = Read from that file.
+
+ // Setup AIOCB.
+ this->aiocb_read_->aio_fildes = this->out_fd_;
+ this->aiocb_read_->aio_offset = 0;
+ this->aiocb_read_->aio_buf = this->buffer_read_;
+ this->aiocb_read_->aio_nbytes = ACE_OS::strlen (this->buffer_write_);
+ this->aiocb_read_->aio_reqprio = 0;
+ this->aiocb_read_->aio_sigevent.sigev_notify = SIGEV_NONE;
+ //this->this->aiocb_.aio_sigevent.sigev_signo = SIGRTMAX;
+ this->aiocb_read_->aio_sigevent.sigev_value.sival_ptr =
+ (void *) this->aiocb_read_;
+
+ // Fire off the aio write. If it doesnt get queued, carry on to get
+ // the completion for the first one.
+ if (aio_read (this->aiocb_read_) < 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "%p\n",
+ "aio_read"),
+ -1);
+
+ // Wait for the completion on aio_suspend.
+ struct aiocb *list_aiocb[2];
+ list_aiocb [0] = this->aiocb_write_;
+ list_aiocb [1] = this->aiocb_read_;
+
+ // Do suspend till all the aiocbs in the list are done.
+ int to_finish = 2;
+ int return_val = 0;
+ while (to_finish > 0)
+ {
+ return_val = aio_suspend (list_aiocb,
+ to_finish,
+ 0);
+ ACE_DEBUG ((LM_DEBUG,
+ "Result of <aio_suspend> : %d\n",
+ return_val));
+
+ // Analyze return and error values.
+ if (to_finish > 1)
+ {
+ if (aio_error (list_aiocb [1]) != EINPROGRESS)
+ {
+ if (aio_return (list_aiocb [1]) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "%p\n",
+ "aio_return, item 1"),
+ -1);
+ else
+ {
+ // Successful. Remember we have one less thing to finish.
+ --to_finish;
+ list_aiocb [1] = 0;
+ }
+ }
+ else
+ ACE_DEBUG ((LM_DEBUG,
+ "aio_error says aio 1 is in progress\n"));
+ }
+
+ if (aio_error (list_aiocb [0]) != EINPROGRESS)
+ {
+ if (aio_return (list_aiocb [0]) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "%p\n",
+ "aio_return, item 0"),
+ -1);
+ else
+ {
+ // Successful. Store the pointer somewhere and bump the
+ // read entry up to the front, if it is still not done.
+ --to_finish;
+ list_aiocb [0] = this->aiocb_read_;
+ }
+ }
+ else
+ ACE_DEBUG ((LM_DEBUG,
+ "aio_error says aio 0 is in progress\n"));
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ "Both the AIO operations done.\n"
+ "The buffer is : %s\n",
+ this->buffer_read_));
+
+ return 0;
+}
+
+int
+main (int argc, char **argv)
+{
+
+ ACE_UNUSED_ARG (argc);
+ ACE_UNUSED_ARG (argv);
+
+ Test_Aio test_aio;
+
+ if (test_aio.init () != 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "AIOCB test failed:\n"
+ "ACE_POSIX_AIOCB_PROACTOR may not work in this platform\n"),
+ -1);
+
+ if (test_aio.do_aio () != 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "AIOCB test failed:\n"
+ "ACE_POSIX_AIOCB_PROACTOR may not work in this platform\n"),
+ -1);
+
+ ACE_DEBUG ((LM_DEBUG,
+ "AIOCB test successful:\n"
+ "ACE_POSIX_AIOCB_PROACTOR should work in this platform\n"));
+
+ return 0;
+}
diff --git a/ACE/examples/Reactor/Proactor/test_aiosig.cpp b/ACE/examples/Reactor/Proactor/test_aiosig.cpp
new file mode 100644
index 00000000000..1746a10a49c
--- /dev/null
+++ b/ACE/examples/Reactor/Proactor/test_aiosig.cpp
@@ -0,0 +1,294 @@
+// $Id$
+// ============================================================================
+//
+// = FILENAME
+// test_aiosig.cpp
+//
+// = DESCRITPTION
+// Check out test_aiosig_ace.cpp, the ACE'ified version of this
+// program. This program may not be uptodate.
+//
+// = COMPILATION
+// CC -g -o test_aiosig -lrt test_aiosig.cpp
+//
+// = RUN
+// ./test_aiosig
+//
+// = AUTHOR
+// Programming for the Real World. Bill O. GallMeister.
+// Modified by Alexander Babu Arulanthu <alex@cs.wustl.edu>
+//
+// =====================================================================
+
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <signal.h>
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+
+#include <limits.h>
+
+#include <aio.h>
+
+int file_handle = -1;
+char mb1 [BUFSIZ + 1];
+char mb2 [BUFSIZ + 1];
+aiocb aiocb1, aiocb2;
+sigset_t completion_signal;
+
+// Function prototypes.
+int setup_signal_delivery (void);
+int issue_aio_calls (void);
+int query_aio_completions (void);
+int test_aio_calls (void);
+int setup_signal_handler (void);
+int setup_signal_handler (int signal_number);
+
+int
+setup_signal_delivery (void)
+{
+ // Make the sigset_t consisting of the completion signal.
+ if (sigemptyset (&completion_signal) == -1)
+ {
+ perror ("Error:Couldnt init the RT completion signal set\n");
+ return -1;
+ }
+
+ if (sigaddset (&completion_signal, SIGRTMIN) == -1)
+ {
+ perror ("Error:Couldnt init the RT completion signal set\n");
+ return -1;
+ }
+
+ // Mask them.
+ if (pthread_sigmask (SIG_BLOCK, &completion_signal, 0) == -1)
+ {
+ perror ("Error:Couldnt maks the RT completion signals\n");
+ return -1;
+ }
+
+ return setup_signal_handler (SIGRTMIN);
+}
+
+int
+issue_aio_calls (void)
+{
+ // Setup AIOCB.
+ aiocb1.aio_fildes = file_handle;
+ aiocb1.aio_offset = 0;
+ aiocb1.aio_buf = mb1;
+ aiocb1.aio_nbytes = BUFSIZ;
+ aiocb1.aio_reqprio = 0;
+ aiocb1.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
+ aiocb1.aio_sigevent.sigev_signo = SIGRTMIN;
+ aiocb1.aio_sigevent.sigev_value.sival_ptr = (void *) &aiocb1;
+
+ // Fire off the aio write.
+ if (aio_read (&aiocb1) == -1)
+ {
+ // Queueing failed.
+ perror ("Error:Asynch_Read_Stream: aio_read queueing failed\n");
+ return -1;
+ }
+
+ // Setup AIOCB.
+ aiocb2.aio_fildes = file_handle;
+ aiocb2.aio_offset = BUFSIZ + 1;
+ aiocb2.aio_buf = mb2;
+ aiocb2.aio_nbytes = BUFSIZ;
+ aiocb2.aio_reqprio = 0;
+ aiocb2.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
+ aiocb2.aio_sigevent.sigev_signo = SIGRTMIN;
+ aiocb2.aio_sigevent.sigev_value.sival_ptr = (void *) &aiocb2;
+
+ // Fire off the aio write.
+ if (aio_read (&aiocb2) == -1)
+ {
+ // Queueing failed.
+ perror ("Error:Asynch_Read_Stream: aio_read queueing failed\n");
+ return -1;
+ }
+ return 0;
+}
+
+int
+query_aio_completions (void)
+{
+ int result = 0;
+ size_t number_of_compleions = 0;
+ for (number_of_compleions = 0;
+ number_of_compleions < 2;
+ number_of_compleions ++)
+ {
+ // Wait for <milli_seconds> amount of time.
+ // @@ Assigning <milli_seconds> to tv_sec.
+ timespec timeout;
+ timeout.tv_sec = INT_MAX;
+ timeout.tv_nsec = 0;
+
+ // To get back the signal info.
+ siginfo_t sig_info;
+
+ // Await the RT completion signal.
+ int sig_return = sigtimedwait (&completion_signal,
+ &sig_info,
+ &timeout);
+
+ // Error case.
+ // If failure is coz of timeout, then return *0* but set
+ // errno appropriately. This is what the WinNT proactor
+ // does.
+ if (sig_return == -1)
+ {
+ perror ("Error:Error waiting for RT completion signals\n");
+ return -1;
+ }
+
+ // RT completion signals returned.
+ if (sig_return != SIGRTMIN)
+ {
+ printf ("Unexpected signal (%d) has been received while waiting for RT Completion Signals\n",
+ sig_return);
+ return -1;
+ }
+
+ // @@ Debugging.
+ printf ("Sig number found in the sig_info block : %d\n",
+ sig_info.si_signo);
+
+ // Is the signo returned consistent?
+ if (sig_info.si_signo != sig_return)
+ {
+ printf ("Inconsistent signal number (%d) in the signal info block\n",
+ sig_info.si_signo);
+ return -1;
+ }
+
+ // @@ Debugging.
+ printf ("Signal code for this signal delivery : %d\n",
+ sig_info.si_code);
+
+ // Is the signal code an aio completion one?
+ if ((sig_info.si_code != SI_ASYNCIO) &&
+ (sig_info.si_code != SI_QUEUE))
+ {
+ printf ("Unexpected signal code (%d) returned on completion querying\n",
+ sig_info.si_code);
+ return -1;
+ }
+
+ // Retrive the aiocb.
+ aiocb* aiocb_ptr = (aiocb *) sig_info.si_value.sival_ptr;
+
+ // Analyze error and return values. Return values are
+ // actually <errno>'s associated with the <aio_> call
+ // corresponding to aiocb_ptr.
+ int error_code = aio_error (aiocb_ptr);
+ if (error_code == -1)
+ {
+ perror ("Error:Invalid control block was sent to <aio_error> for compleion querying\n");
+ return -1;
+ }
+
+ if (error_code != 0)
+ {
+ // Error occurred in the <aio_>call. Return the errno
+ // corresponding to that <aio_> call.
+ printf ("Error:An AIO call has failed:Error code = %d\n",
+ error_code);
+ return -1;
+ }
+
+ // No error occured in the AIO operation.
+ int nbytes = aio_return (aiocb_ptr);
+ if (nbytes == -1)
+ {
+ perror ("Error:Invalid control block was send to <aio_return>\n");
+ return -1;
+ }
+
+ if (number_of_compleions == 0)
+ // Print the buffer.
+ printf ("Number of bytes transferred : %d\n The buffer : %s \n",
+ nbytes,
+ mb1);
+ else
+ // Print the buffer.
+ printf ("Number of bytes transferred : %d\n The buffer : %s \n",
+ nbytes,
+ mb2);
+ }
+ return 0;
+}
+
+int
+test_aio_calls (void)
+{
+ // Set up the input file.
+ // Open file (in SEQUENTIAL_SCAN mode)
+ file_handle = open ("test_aiosig.cpp", O_RDONLY);
+
+ if (file_handle == -1)
+ {
+ perror ("Error:Opening the inputfile");
+ return -1;
+ }
+
+ if (setup_signal_delivery () < 0)
+ return -1;
+
+ if (issue_aio_calls () < 0)
+ return -1;
+
+ if (query_aio_completions () < 0)
+ return -1;
+
+ return 0;
+}
+
+int
+setup_signal_handler (int signal_number)
+{
+ // Setting up the handler(!) for these signals.
+ struct sigaction reaction;
+ sigemptyset (&reaction.sa_mask); // Nothing else to mask.
+ reaction.sa_flags = SA_SIGINFO; // Realtime flag.
+#if defined (SA_SIGACTION)
+ // Lynx says, it is better to set this bit to be portable.
+ reaction.sa_flags &= SA_SIGACTION;
+#endif /* SA_SIGACTION */
+ reaction.sa_sigaction = null_handler; // Null handler.
+ int sigaction_return = sigaction (SIGRTMIN,
+ &reaction,
+ 0);
+ if (sigaction_return == -1)
+ {
+ perror ("Error:Proactor couldnt do sigaction for the RT SIGNAL");
+ return -1;
+ }
+
+ return 0;
+}
+
+void
+null_handler (int /* signal_number */,
+ siginfo_t * /* info */,
+ void * /* context */)
+{
+}
+
+int
+main (int, char *[])
+{
+ if (test_aio_calls () == 0)
+ printf ("RT SIG test successful:\n"
+ "ACE_POSIX_SIG_PROACTOR should work in this platform\n");
+ else
+ printf ("RT SIG test failed:\n"
+ "ACE_POSIX_SIG_PROACTOR may not work in this platform\n");
+ return 0;
+}
diff --git a/ACE/examples/Reactor/Proactor/test_aiosig_ace.cpp b/ACE/examples/Reactor/Proactor/test_aiosig_ace.cpp
new file mode 100644
index 00000000000..34c1b9b5ab2
--- /dev/null
+++ b/ACE/examples/Reactor/Proactor/test_aiosig_ace.cpp
@@ -0,0 +1,358 @@
+// $Id$
+
+// ============================================================================
+//
+// = FILENAME
+// test_aiosig_sig.cpp
+//
+// = DESCRITPTION
+// This program helps you to test the <aio_*> calls on a
+// platform.
+// Before running this test, make sure the platform can
+// support POSIX <aio_> calls, using ACE_ROOT/tests/Aio_Plaform_Test.cpp
+//
+// This program tests the Signal based completion approach which
+// uses <sigtimedwait> for completion querying.
+// If this test is successful, ACE_POSIX_SIG_PROACTOR
+// can be used on this platform.
+//
+// This program is a ACE version of the
+// $ACE_ROOT/examples/Reactor/Proactor/test_aiosig.cpp, with
+// ACE_DEBUGs and Message_Blocks.
+//
+// This test does the following:
+// Issue two <aio_read>s.
+// Assign SIGRTMIN as the notification signal.
+// Mask these signals from delivery.
+// Receive this signal by doing <sigtimedwait>.
+// Wait for two completions (two signals)
+//
+// = COMPILATION
+// make
+//
+// = RUN
+// ./test_aiosig_ace
+//
+// = AUTHOR
+// Programming for the Real World. Bill O. GallMeister.
+// Modified by Alexander Babu Arulanthu <alex@cs.wustl.edu>
+//
+// =====================================================================
+
+#include "ace/Message_Block.h"
+#include "ace/Log_Msg.h"
+#include "ace/os_include/os_aio.h"
+#include "ace/OS_NS_signal.h"
+#include "ace/OS_NS_unistd.h"
+#include "ace/OS_NS_fcntl.h"
+#include "ace/Asynch_IO.h" // for ACE_INFINITE
+
+static ACE_HANDLE file_handle = ACE_INVALID_HANDLE;
+static ACE_Message_Block mb1 (BUFSIZ + 1);
+static ACE_Message_Block mb2 (BUFSIZ + 1);
+static aiocb aiocb1;
+static aiocb aiocb2;
+static aiocb aiocb3;
+static sigset_t completion_signal;
+
+// Function prototypes.
+static int setup_signal_delivery (void);
+static int issue_aio_calls (void);
+static int query_aio_completions (void);
+static int test_aio_calls (void);
+static void null_handler (int signal_number, siginfo_t *info, void *context);
+static int setup_signal_handler (int signal_number);
+
+static int
+setup_signal_delivery (void)
+{
+ // = Mask all the signals.
+
+ sigset_t full_set;
+
+ // Get full set.
+ if (sigfillset (&full_set) != 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "Error:(%P | %t):%p\n",
+ "sigfillset failed"),
+ -1);
+
+ // Mask them.
+ if (ACE_OS::pthread_sigmask (SIG_SETMASK, &full_set, 0) != 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "Error:(%P | %t):%p\n",
+ "pthread_sigmask failed"),
+ -1);
+
+ // = Make a mask with SIGRTMIN only. We use only that signal to
+ // issue <aio_>'s.
+
+ if (sigemptyset (&completion_signal) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "Error: %p\n",
+ "Couldnt init the RT completion signal set"),
+ -1);
+
+ if (sigaddset (&completion_signal,
+ SIGRTMIN) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "Error: %p\n",
+ "Couldnt init the RT completion signal set"),
+ -1);
+
+ // Set up signal handler for this signal.
+ return setup_signal_handler (SIGRTMIN);
+}
+
+static int
+setup_signal_handler (int signal_number)
+{
+ ACE_UNUSED_ARG (signal_number);
+
+ // Setting up the handler(!) for these signals.
+ struct sigaction reaction;
+ sigemptyset (&reaction.sa_mask); // Nothing else to mask.
+ reaction.sa_flags = SA_SIGINFO; // Realtime flag.
+#if defined (SA_SIGACTION)
+ // Lynx says, it is better to set this bit to be portable.
+ reaction.sa_flags &= SA_SIGACTION;
+#endif /* SA_SIGACTION */
+ reaction.sa_sigaction = null_handler; // Null handler.
+ int sigaction_return = sigaction (SIGRTMIN,
+ &reaction,
+ 0);
+ if (sigaction_return == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "Error: %p\n",
+ "Proactor couldnt do sigaction for the RT SIGNAL"),
+ -1);
+ return 0;
+}
+
+
+static int
+issue_aio_calls (void)
+{
+ // Setup AIOCB.
+ aiocb1.aio_fildes = file_handle;
+ aiocb1.aio_offset = 0;
+ aiocb1.aio_buf = mb1.wr_ptr ();
+ aiocb1.aio_nbytes = BUFSIZ;
+ aiocb1.aio_reqprio = 0;
+ aiocb1.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
+ aiocb1.aio_sigevent.sigev_signo = SIGRTMIN;
+ aiocb1.aio_sigevent.sigev_value.sival_ptr = (void *) &aiocb1;
+
+ // Fire off the aio read.
+ if (aio_read (&aiocb1) == -1)
+ // Queueing failed.
+ ACE_ERROR_RETURN ((LM_ERROR, "Error: %p\n",
+ "Asynch_Read_Stream: aio_read queueing failed"),
+ -1);
+
+ // Setup AIOCB.
+ aiocb2.aio_fildes = file_handle;
+ aiocb2.aio_offset = BUFSIZ + 1;
+ aiocb2.aio_buf = mb2.wr_ptr ();
+ aiocb2.aio_nbytes = BUFSIZ;
+ aiocb2.aio_reqprio = 0;
+ aiocb2.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
+ aiocb2.aio_sigevent.sigev_signo = SIGRTMIN;
+ aiocb2.aio_sigevent.sigev_value.sival_ptr = (void *) &aiocb2;
+
+ // Fire off the aio read.
+ if (aio_read (&aiocb2) == -1)
+ // Queueing failed.
+ ACE_ERROR_RETURN ((LM_ERROR, "Error: %p\n",
+ "Asynch_Read_Stream: aio_read queueing failed"),
+ -1);
+
+ // Setup sigval.
+ aiocb3.aio_fildes = ACE_INVALID_HANDLE;
+ aiocb3.aio_offset = 0;
+ aiocb3.aio_buf = 0;
+ aiocb3.aio_nbytes = 0;
+ aiocb3.aio_reqprio = 0;
+ aiocb3.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
+ aiocb3.aio_sigevent.sigev_signo = SIGRTMIN;
+ aiocb3.aio_sigevent.sigev_value.sival_ptr = (void *) &aiocb3;
+ sigval value;
+ value.sival_ptr = reinterpret_cast<void *> (&aiocb3);
+ // Queue this one for completion right now.
+ if (sigqueue (ACE_OS::getpid (), SIGRTMIN, value) == -1)
+ // Queueing failed.
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "Error: %p\n", "sigqueue"),
+ -1);
+
+ return 0;
+}
+
+static int
+query_aio_completions (void)
+{
+ for (size_t number_of_compleions = 0;
+ number_of_compleions < 3;
+ number_of_compleions ++)
+ {
+ // Wait for <milli_seconds> amount of time. @@ Assigning
+ // <milli_seconds> to tv_sec.
+ timespec timeout;
+ timeout.tv_sec = ACE_INFINITE;
+ timeout.tv_nsec = 0;
+
+ // To get back the signal info.
+ siginfo_t sig_info;
+
+ // Await the RT completion signal.
+ int sig_return = sigtimedwait (&completion_signal,
+ &sig_info,
+ &timeout);
+
+ // Error case.
+ // If failure is coz of timeout, then return *0* but set
+ // errno appropriately. This is what the WinNT proactor
+ // does.
+ if (sig_return == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "Error: %p\n",
+ "Error waiting for RT completion signals"),
+ -1);
+
+ // RT completion signals returned.
+ if (sig_return != SIGRTMIN)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "Unexpected signal (%d) has been received while waiting for RT Completion Signals\n",
+ sig_return),
+ -1);
+
+ // @@ Debugging.
+ ACE_DEBUG ((LM_DEBUG,
+ "Sig number found in the sig_info block : %d\n",
+ sig_info.si_signo));
+
+ // Is the signo returned consistent?
+ if (sig_info.si_signo != sig_return)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "Inconsistent signal number (%d) in the signal info block\n",
+ sig_info.si_signo),
+ -1);
+
+ // @@ Debugging.
+ ACE_DEBUG ((LM_DEBUG,
+ "Signal code for this signal delivery : %d\n",
+ sig_info.si_code));
+
+ // Is the signal code an aio completion one?
+ if ((sig_info.si_code != SI_ASYNCIO) &&
+ (sig_info.si_code != SI_QUEUE))
+ ACE_ERROR_RETURN ((LM_DEBUG,
+ "Unexpected signal code (%d) returned on completion querying\n",
+ sig_info.si_code),
+ -1);
+
+ // Retrive the aiocb.
+ aiocb* aiocb_ptr = (aiocb *) sig_info.si_value.sival_ptr;
+ if (aiocb_ptr == &aiocb3)
+ {
+ ACE_ASSERT (sig_info.si_code == SI_QUEUE);
+ ACE_DEBUG ((LM_DEBUG, "sigqueue caught... good\n"));
+ }
+ else
+ {
+ // Analyze error and return values. Return values are
+ // actually <errno>'s associated with the <aio_> call
+ // corresponding to aiocb_ptr.
+ int error_code = aio_error (aiocb_ptr);
+ if (error_code == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "%p\n",
+ "Invalid control block was sent to <aio_error> for completion querying"),
+ -1);
+
+ if (error_code != 0)
+ // Error occurred in the <aio_>call. Return the errno
+ // corresponding to that <aio_> call.
+ ACE_ERROR_RETURN ((LM_ERROR, "%p\n",
+ "An AIO call has failed"),
+ error_code);
+
+ // No error occured in the AIO operation.
+ int nbytes = aio_return (aiocb_ptr);
+ if (nbytes == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "%p\n",
+ "Invalid control block was send to <aio_return>"),
+ -1);
+ if (number_of_compleions == 0)
+ {
+ // Print the buffer.
+ ACE_DEBUG ((LM_DEBUG,
+ "\n Number of bytes transferred : %d\n",
+ nbytes));
+ // Note... the dumps of the buffers are disabled because they
+ // may easily overrun the ACE_Log_Msg output buffer. If you need
+ // to turn the on for some reason, be careful of this.
+#if 0
+ ACE_DEBUG ((LM_DEBUG, "The buffer : %s \n", mb1.rd_ptr ()));
+#endif /* 0 */
+ }
+ else
+ {
+ // Print the buffer.
+ ACE_DEBUG ((LM_DEBUG,
+ "\n Number of bytes transferred : %d\n",
+ nbytes));
+#if 0
+ ACE_DEBUG ((LM_DEBUG, "The buffer : %s \n", mb2.rd_ptr ()));
+#endif /* 0 */
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int
+test_aio_calls (void)
+{
+ // Set up the input file.
+ // Open file (in SEQUENTIAL_SCAN mode)
+ file_handle = ACE_OS::open ("test_aiosig_ace.cpp",
+ O_RDONLY);
+
+ if (file_handle == ACE_INVALID_HANDLE)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "%p\n",
+ "ACE_OS::open"),
+ -1);
+
+ if (setup_signal_delivery () == -1)
+ return -1;
+
+ if (issue_aio_calls () == -1)
+ return -1;
+
+ if (query_aio_completions () == -1)
+ return -1;
+
+ return 0;
+}
+
+static void
+null_handler (int signal_number,
+ siginfo_t */* info */,
+ void * /* context */)
+{
+ ACE_ERROR ((LM_ERROR,
+ "Error:%s:Signal number %d\n"
+ "Mask all the RT signals for this thread",
+ "ACE_POSIX_SIG_Proactor::null_handler called",
+ signal_number));
+}
+
+int
+main (int, char *[])
+{
+ if (test_aio_calls () == 0)
+ printf ("RT SIG test successful:\n"
+ "ACE_POSIX_SIG_PROACTOR should work in this platform\n");
+ else
+ printf ("RT SIG test failed:\n"
+ "ACE_POSIX_SIG_PROACTOR may not work in this platform\n");
+ return 0;
+}
diff --git a/ACE/examples/Reactor/Proactor/test_cancel.cpp b/ACE/examples/Reactor/Proactor/test_cancel.cpp
new file mode 100644
index 00000000000..c10f8e9be2c
--- /dev/null
+++ b/ACE/examples/Reactor/Proactor/test_cancel.cpp
@@ -0,0 +1,246 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// examples
+//
+// = FILENAME
+// test_cancel.cpp
+//
+// = DESCRIPTION
+// This program tests cancelling an Asynchronous Operation in the
+// Proactor framework.
+//
+// This tests accepts a connection and issues an Asynchronous Read
+// Stream. It reads <read_size> (option -s) number of bytes and
+// when this operation completes, it issues another Asynchronous
+// Read Stream to <read_size> and immediately calls <cancel> to
+// cancel the operation and so the program exits closing the
+// connection.
+//
+// Works fine on NT. On Solaris platforms, the asynch read is
+// pending, but the cancel returns with the value <AIO_ALLDONE>
+// indicating all the operations in that handle are done.
+// But, LynxOS has a good <aio_cancel> implementation. It works
+// fine.
+//
+// = RUN
+// ./test_cancel -p <port_number>
+// Then telnet to this port and send <read_size> bytes and your
+// connection should get closed down.
+//
+// = AUTHOR
+// Irfan Pyarali (irfan@cs.wustl.edu)
+//
+// ============================================================================
+
+#include "ace/OS_main.h"
+#include "ace/Service_Config.h"
+#include "ace/Proactor.h"
+#include "ace/Asynch_IO.h"
+#include "ace/Asynch_IO_Impl.h"
+#include "ace/Asynch_Acceptor.h"
+#include "ace/INET_Addr.h"
+#include "ace/SOCK_Connector.h"
+#include "ace/SOCK_Acceptor.h"
+#include "ace/SOCK_Stream.h"
+#include "ace/Message_Block.h"
+#include "ace/Get_Opt.h"
+#include "ace/Log_Msg.h"
+#include "ace/OS_NS_sys_socket.h"
+
+ACE_RCSID (Proactor, test_proactor, "$Id$")
+
+#if ((defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)) || (defined (ACE_HAS_AIO_CALLS)))
+ // This only works on Win32 platforms and on Unix platforms supporting
+ // POSIX aio calls.
+
+#include "test_cancel.h"
+
+static u_short port = ACE_DEFAULT_SERVER_PORT;
+static int done = 0;
+static int read_size = 2;
+
+
+Receiver::Receiver (void)
+ : mb_ (read_size + 1),
+ handle_ (ACE_INVALID_HANDLE)
+{
+}
+
+Receiver::~Receiver (void)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ "Receiver: Closing down Remote connection:%d\n",
+ this->handle_));
+
+ ACE_OS::closesocket (this->handle_);
+}
+
+void
+Receiver::open (ACE_HANDLE handle,
+ ACE_Message_Block &)
+{
+ // New connection, initiate stuff
+
+ ACE_DEBUG ((LM_DEBUG, "%N:%l:Receiver::open called\n"));
+
+ // Cache the new connection
+ this->handle_ = handle;
+
+ // Initiate ACE_Asynch_Read_Stream
+ if (this->rs_.open (*this, this->handle_) == -1)
+ {
+ ACE_ERROR ((LM_ERROR, "%p\n", "ACE_Asynch_Read_Stream::open"));
+ return;
+ }
+
+ // Try to read <n> bytes from the stream.
+
+ ACE_DEBUG ((LM_DEBUG,
+ "Receiver::open: Issuing Asynch Read of (%d) bytes from the stream\n",
+ read_size));
+
+ if (this->rs_.read (this->mb_,
+ read_size) == -1)
+ ACE_ERROR ((LM_ERROR,
+ "%p\n",
+ "Receiver::open: Failed to issue the read"));
+}
+
+void
+Receiver::handle_read_stream (const ACE_Asynch_Read_Stream::Result &result)
+{
+ ACE_DEBUG ((LM_DEBUG, "handle_read_stream called\n"));
+
+ // Reset pointers
+ result.message_block ().rd_ptr ()[result.bytes_transferred ()] = '\0';
+
+ ACE_DEBUG ((LM_DEBUG, "********************\n"));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "bytes_to_read", result.bytes_to_read ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "handle", result.handle ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "bytes_transfered", result.bytes_transferred ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "act", (u_long) result.act ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "success", result.success ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "completion_key", (u_long) result.completion_key ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "error", result.error ()));
+ ACE_DEBUG ((LM_DEBUG, "********************\n"));
+ ACE_DEBUG ((LM_DEBUG, "%s = %s\n", "message_block", result.message_block ().rd_ptr ()));
+
+ if (result.success () && !result.error ())
+ {
+ // Successful read: No error.
+
+ // Set the pointers back in the message block.
+ result.message_block ().wr_ptr (result.message_block ().rd_ptr ());
+
+ // Issue another read, but immediately cancel it.
+
+ // Issue the read.
+
+ ACE_DEBUG ((LM_DEBUG,
+ "Issuing Asynch Read of (%d) bytes from the stream\n",
+ read_size));
+
+ if (this->rs_.read (this->mb_,
+ read_size) == -1)
+ ACE_ERROR ((LM_ERROR,
+ "%p\n",
+ "Receiver::handle_read_stream: Failed to issue the read"));
+
+ // Cancel the read.
+
+ ACE_DEBUG ((LM_DEBUG,
+ "Cacelling Asynch Read "));
+
+ int ret_val = this->rs_.cancel ();
+ if (ret_val == -1)
+ ACE_ERROR ((LM_ERROR,
+ "%p\n",
+ "Receiver::handle_read_stream: Failed to cancel the read"));
+
+ ACE_DEBUG ((LM_DEBUG, "Asynch IO : Cancel : Result = %d\n",
+ ret_val));
+ }
+ else
+ {
+ done = 1;
+
+ ACE_DEBUG ((LM_DEBUG, "Receiver completed\n"));
+
+ // Print the error message if any.
+ if (result.error () != 0)
+ {
+ errno = result.error ();
+
+ ACE_ERROR ((LM_ERROR,
+ "%p\n",
+ "Asynch Read Stream Error: "));
+ }
+ }
+}
+
+static int
+parse_args (int argc, ACE_TCHAR *argv[])
+{
+ ACE_Get_Opt get_opt (argc, argv, ACE_TEXT("p:s:"));
+ int c;
+
+ while ((c = get_opt ()) != EOF)
+ switch (c)
+ {
+ case 'p':
+ port = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 's':
+ read_size = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ default:
+ ACE_ERROR ((LM_ERROR, "%p.\n",
+ "usage :\n"
+ "-p <port>\n"
+ "-s <read_size>\n"));
+ return -1;
+ }
+
+ return 0;
+}
+
+int
+ACE_TMAIN (int argc, ACE_TCHAR *argv[])
+{
+ if (parse_args (argc, argv) == -1)
+ return -1;
+
+ // Note: acceptor parameterized by the Receiver
+ ACE_Asynch_Acceptor<Receiver> acceptor;
+
+ // Listening passively.
+ if (acceptor.open (ACE_INET_Addr (port),
+ read_size,
+ 1) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "ACE:acceptor::open failed\n"),
+ 1);
+
+ int success = 1;
+
+ while (success > 0 && !done)
+ // dispatch events
+ success = ACE_Proactor::instance ()->handle_events ();
+
+ return 0;
+}
+
+#else /* ACE_WIN32 && !ACE_HAS_WINCE || ACE_HAS_AIO_CALLS*/
+
+int
+ACE_TMAIN (int, ACE_TCHAR *[])
+{
+ ACE_DEBUG ((LM_DEBUG,
+ "This example does not work on this platform.\n"));
+ return 1;
+}
+
+#endif /* ACE_WIN32 && !ACE_HAS_WINCE || ACE_HAS_AIO_CALLS*/
diff --git a/ACE/examples/Reactor/Proactor/test_cancel.h b/ACE/examples/Reactor/Proactor/test_cancel.h
new file mode 100644
index 00000000000..45c4bfbc85b
--- /dev/null
+++ b/ACE/examples/Reactor/Proactor/test_cancel.h
@@ -0,0 +1,47 @@
+/*
+** $Id$
+*/
+
+#ifndef _TEST_CANCEL_H
+#define _TEST_CANCEL_H
+
+#include "ace/Asynch_IO.h"
+
+class Receiver : public ACE_Service_Handler
+{
+ // = TITLE
+ //
+ // Receiver
+ //
+ // = DESCRIPTION
+ //
+ // The class will be created by ACE_Asynch_Acceptor when new
+ // connections arrive. This class will then receive data from
+ // the network connection and dump it to a file.
+
+public:
+ Receiver (void);
+ ~Receiver (void);
+
+ virtual void open (ACE_HANDLE handle,
+ ACE_Message_Block &message_block);
+ // This is called after the new connection has been accepted.
+
+protected:
+ // These methods are called by the framework
+
+ virtual void handle_read_stream (const ACE_Asynch_Read_Stream::Result &result);
+ // This is called when asynchronous read from the socket complete
+
+private:
+ ACE_Asynch_Read_Stream rs_;
+ // rs (read stream): for reading from a socket
+
+ ACE_Message_Block mb_;
+ // Message block to read from the stream.
+
+ ACE_HANDLE handle_;
+ // Handle for IO to remote peer
+};
+
+#endif /* _TEST_CANCEL_H */
diff --git a/ACE/examples/Reactor/Proactor/test_end_event_loop.cpp b/ACE/examples/Reactor/Proactor/test_end_event_loop.cpp
new file mode 100644
index 00000000000..096f77b089d
--- /dev/null
+++ b/ACE/examples/Reactor/Proactor/test_end_event_loop.cpp
@@ -0,0 +1,168 @@
+// $Id$
+// ============================================================================
+//
+// = FILENAME
+// test_end_event_loop.cpp
+//
+// = DESCRITPTION
+// This program tests the event loop mechanism of the
+// Proactor. To end the event loop, threads that are blocked in
+// waiting for completions are woken up and the event loop comes
+// to the end. This is tested in this program.
+//
+// Threads are doing <run_event_loop> with/without time_out
+// values and the main thread calls <end_event_loop>.
+//
+// = COMPILATION
+// make
+//
+// = RUN
+// ./test_end_event_loop
+//
+// = AUTHOR
+// Alexander Babu Arulanthu <alex@cs.wustl.edu>
+//
+// =====================================================================
+
+#include "ace/OS_NS_unistd.h"
+#include "ace/Proactor.h"
+#include "ace/Task.h"
+#include "ace/WIN32_Proactor.h"
+#include "ace/POSIX_Proactor.h"
+#include "ace/OS_main.h"
+
+#if ((defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)) || \
+ (defined (ACE_HAS_AIO_CALLS)) && !defined (ACE_POSIX_AIOCB_PROACTOR))
+// This only works on Win32 platforms and on Unix platforms supporting
+// POSIX aio calls.
+
+class My_Task: public ACE_Task <ACE_NULL_SYNCH>
+{
+ // = TITLE
+ //
+ // Contains thread functions which execute event loops. Each
+ // thread waits for a different signal.
+ //
+public:
+ // Constructor.
+ My_Task (void)
+ : time_flag_ (0)
+ {}
+
+
+ virtual ~My_Task (void) {}
+ // Destructor.
+
+ // If time_flag is zero do the eventloop indefinitely, otherwise do
+ // it for finite amount of time (13secs!!!).
+ int open (void *timed_event_loop)
+ {
+ // Set the local variable.
+ if (timed_event_loop == 0)
+ this->time_flag_ = 0;
+ else
+ this->time_flag_ = 1;
+
+ // Spawn the threads.
+ if (this->activate (THR_NEW_LWP, 5) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "%N:%l:%p\n",
+ "My_Task:open: <activate> failed"),
+ -1);
+
+ return 0;
+ }
+
+ // Thread function.
+ int svc (void)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ "(%P|%t):Starting svc routine\n"));
+
+ if (this->time_flag_)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ "(%P|%t):Going to do *timed* <run_event_loop> \n"));
+
+ ACE_Time_Value run_time (13);
+
+ if (ACE_Proactor::instance ()->run_event_loop (run_time) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t):%p.\n",
+ "<Proactor::run_event_loop> failed"),
+ -1);
+ }
+ else
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ "(%P|%t):Going to do *indefinite* <run_event_loop> \n"));
+
+ if (ACE_Proactor::instance ()->run_event_loop () == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t):%p.\n",
+ "<Proactor::run_event_loop> failed"),
+ -1);
+ }
+ return 0;
+ };
+
+private:
+ int time_flag_;
+ // If zero, indefinite event loop, otherwise timed event loop.
+};
+
+int
+ACE_TMAIN (int argc, ACE_TCHAR *argv [])
+{
+ ACE_UNUSED_ARG (argc);
+ ACE_UNUSED_ARG (argv);
+
+ ACE_DEBUG ((LM_DEBUG,
+ "(%P | %t):Test starts \n"));
+
+ // Let us get the singleton proactor created here. This is very
+ // important. This will mask the signal used in the Proactor masked
+ // for the main thread (and all the threads).
+ ACE_Proactor *proactor = ACE_Proactor::instance ();
+ ACE_UNUSED_ARG (proactor);
+
+ My_Task task1, task2;
+
+ // Test the indefinite run event loop.
+ if (task1.open (0) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "%N:%l:(%P | %t):Failed to <open> the task\n"),
+ 1);
+
+ // Test the indefinite run event loop. Just pass a non-zero.
+ if (task2.open ((void *)&task2) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "%N:%l:(%P | %t):Failed to <open> the task\n"),
+ 1);
+
+ // Give a gap.
+ ACE_OS::sleep (3);
+
+ // End the event loop.
+ if (ACE_Proactor::instance ()->end_event_loop () == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "%N:%l:(%P | %t):Failed to <end_event_loop>\n"),
+ 1);
+
+ ACE_Thread_Manager::instance ()->wait ();
+
+ ACE_DEBUG ((LM_DEBUG,
+ "(%P | %t):Test ends\n"));
+ return 0;
+}
+
+#else /* ACE_WIN32 && !ACE_HAS_WINCE || ACE_HAS_AIO_CALLS && !ACE_POSIX_AIOCB_PROACTOR*/
+
+int
+main (int, char *[])
+{
+ ACE_DEBUG ((LM_DEBUG,
+ "This example cannot work with AIOCB_Proactor.\n"));
+ return 1;
+}
+
+#endif /* ACE_WIN32 && !ACE_HAS_WINCE || ACE_HAS_AIO_CALLS && !ACE_POSIX_AIOCB_PROACTOR*/
+
diff --git a/ACE/examples/Reactor/Proactor/test_multiple_loops.cpp b/ACE/examples/Reactor/Proactor/test_multiple_loops.cpp
new file mode 100644
index 00000000000..ac4228ab641
--- /dev/null
+++ b/ACE/examples/Reactor/Proactor/test_multiple_loops.cpp
@@ -0,0 +1,140 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// examples
+//
+// = FILENAME
+// test_multiple_loops.cpp
+//
+// = DESCRIPTION
+//
+// This example application shows how to write programs that
+// combine the Proactor and Reactor event loops. This is possible
+// only on WIN32 platform.
+//
+// = AUTHOR
+// Irfan Pyarali
+//
+// ============================================================================
+
+#include "ace/Task.h"
+#include "ace/Proactor.h"
+#include "ace/WIN32_Proactor.h"
+#include "ace/Atomic_Op.h"
+#include "ace/OS_NS_unistd.h"
+
+ACE_RCSID(Proactor, test_multiple_loops, "$Id$")
+
+#if (defined (ACE_WIN32) && !defined (ACE_HAS_WINCE))
+
+class Timeout_Handler : public ACE_Handler, public ACE_Event_Handler
+{
+ // = TITLE
+ // Generic timeout handler.
+
+public:
+ Timeout_Handler (void)
+ {
+ }
+
+ // This is called by the Proactor. This is declared in ACE_Handler.
+ virtual void handle_time_out (const ACE_Time_Value &tv,
+ const void *arg)
+ {
+ // Print out when timeouts occur.
+ ACE_DEBUG ((LM_DEBUG, "(%t) %d timeout occurred for %s @ %d.\n",
+ ++count_,
+ (char *) arg,
+ tv.sec ()));
+
+ // Since there is only one thread that can do the timeouts in
+ // Reactor, lets keep the handle_timeout short for that
+ // thread.
+ if (ACE_OS::strcmp ((char *) arg, "Proactor") == 0)
+ // Sleep for a while
+ ACE_OS::sleep (1);
+ }
+
+ // This method is declared in ACE_Event_Handler.
+ virtual int handle_timeout (const ACE_Time_Value &tv,
+ const void *arg)
+ {
+ this->handle_time_out (tv, arg);
+ return 0;
+ }
+
+private:
+ ACE_Atomic_Op <ACE_Thread_Mutex, int> count_;
+};
+
+class Worker : public ACE_Task <ACE_NULL_SYNCH>
+{
+public:
+
+ // Thread fuction.
+ int svc (void)
+ {
+ ACE_DEBUG ((LM_DEBUG, "(%t) Worker started\n"));
+
+ // Handle events for 13 seconds.
+ ACE_Time_Value run_time (13);
+
+ // Try to become the owner
+ ACE_Reactor::instance ()->owner (ACE_Thread::self ());
+
+ if (ACE_Reactor::run_event_loop (run_time) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "%p.\n", "Worker::svc"), -1);
+ else
+ ACE_DEBUG ((LM_DEBUG, "(%t) work complete\n"));
+
+ return 0;
+ }
+};
+
+int
+ACE_TMAIN (int, ACE_TCHAR *[])
+{
+ Timeout_Handler handler;
+ ACE_WIN32_Proactor win32_proactor (0, 1);
+ ACE_Proactor proactor (&win32_proactor, 0, 0);
+
+ ACE_Reactor::instance ()->register_handler (proactor.implementation ());
+
+ // Register a 2 second timer.
+ ACE_Time_Value foo_tv (2);
+ if (proactor.schedule_timer (handler,
+ (void *) "Proactor",
+ ACE_Time_Value::zero,
+ foo_tv) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "schedule_timer"), -1);
+
+ // Register a 3 second timer.
+ ACE_Time_Value bar_tv (3);
+ if (ACE_Reactor::instance ()->schedule_timer (&handler,
+ (void *) "Reactor",
+ ACE_Time_Value::zero,
+ bar_tv) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "schedule_timer"), -1);
+
+ Worker worker;
+
+ if (worker.activate (THR_NEW_LWP, 10) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "%p.\n", "main"), -1);
+
+ ACE_Thread_Manager::instance ()->wait ();
+
+ // Remove from reactor
+ ACE_Reactor::instance ()->remove_handler (&proactor,
+ ACE_Event_Handler::DONT_CALL);
+
+ return 0;
+}
+#else
+int
+main (int, char *[])
+{
+ return 0;
+}
+#endif /* ACE_WIN32 && !ACE_HAS_WINCE */
diff --git a/ACE/examples/Reactor/Proactor/test_proactor.cpp b/ACE/examples/Reactor/Proactor/test_proactor.cpp
new file mode 100644
index 00000000000..035a2facf6a
--- /dev/null
+++ b/ACE/examples/Reactor/Proactor/test_proactor.cpp
@@ -0,0 +1,679 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// examples
+//
+// = FILENAME
+// test_proactor.cpp
+//
+// = DESCRIPTION
+// This program illustrates how the <ACE_Proactor> can be used to
+// implement an application that does various asynchronous
+// operations.
+//
+// = AUTHOR
+// Irfan Pyarali <irfan@cs.wustl.edu>
+//
+// ============================================================================
+
+#include "ace/OS_NS_string.h"
+#include "ace/OS_main.h"
+#include "ace/Service_Config.h"
+#include "ace/Proactor.h"
+#include "ace/Asynch_IO.h"
+#include "ace/Asynch_IO_Impl.h"
+#include "ace/Asynch_Acceptor.h"
+#include "ace/INET_Addr.h"
+#include "ace/SOCK_Connector.h"
+#include "ace/SOCK_Acceptor.h"
+#include "ace/SOCK_Stream.h"
+#include "ace/Message_Block.h"
+#include "ace/Get_Opt.h"
+#include "ace/Log_Msg.h"
+#include "ace/OS_NS_sys_stat.h"
+#include "ace/OS_NS_sys_socket.h"
+#include "ace/OS_NS_unistd.h"
+#include "ace/OS_NS_fcntl.h"
+
+ACE_RCSID(Proactor, test_proactor, "$Id$")
+
+#if ((defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)) || (defined (ACE_HAS_AIO_CALLS)))
+ // This only works on Win32 platforms and on Unix platforms supporting
+ // POSIX aio calls.
+
+#include "test_proactor.h"
+
+
+// Host that we're connecting to.
+static ACE_TCHAR *host = 0;
+
+// Port that we're receiving connections on.
+static u_short port = ACE_DEFAULT_SERVER_PORT;
+
+// File that we're sending.
+static const ACE_TCHAR *file = ACE_TEXT("test_proactor.cpp");
+
+// Name of the output file.
+static const ACE_TCHAR *dump_file = ACE_TEXT("output");
+
+// Keep track of when we're done.
+static int done = 0;
+
+// Size of each initial asynchronous <read> operation.
+static int initial_read_size = BUFSIZ;
+
+
+Receiver::Receiver (void)
+ : dump_file_ (ACE_INVALID_HANDLE),
+ handle_ (ACE_INVALID_HANDLE)
+{
+}
+
+Receiver::~Receiver (void)
+{
+ ACE_OS::close (this->dump_file_);
+ ACE_OS::closesocket (this->handle_);
+}
+
+void
+Receiver::open (ACE_HANDLE handle,
+ ACE_Message_Block &message_block)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ "%N:%l:Receiver::open called\n"));
+
+ // New connection, so initiate stuff.
+
+ // Cache the new connection
+ this->handle_ = handle;
+
+ // File offset starts at zero
+ this->file_offset_ = 0;
+
+ // Open dump file (in OVERLAPPED mode)
+ this->dump_file_ = ACE_OS::open (dump_file,
+ O_CREAT | O_RDWR | O_TRUNC | \
+ FILE_FLAG_OVERLAPPED);
+ if (this->dump_file_ == ACE_INVALID_HANDLE)
+ {
+ ACE_ERROR ((LM_ERROR,
+ "%p\n",
+ "ACE_OS::open"));
+ return;
+ }
+
+ // Initiate <ACE_Asynch_Write_File>.
+ if (this->wf_.open (*this,
+ this->dump_file_) == -1)
+ {
+ ACE_ERROR ((LM_ERROR,
+ "%p\n",
+ "ACE_Asynch_Write_File::open"));
+ return;
+ }
+
+ // Initiate <ACE_Asynch_Read_Stream>.
+ if (this->rs_.open (*this, this->handle_) == -1)
+ {
+ ACE_ERROR ((LM_ERROR,
+ "%p\n",
+ "ACE_Asynch_Read_Stream::open"));
+ return;
+ }
+
+ // Fake the result and make the <handle_read_stream> get
+ // called. But, not, if there is '0' is transferred.
+ if (message_block.length () != 0)
+ {
+ // Duplicate the message block so that we can keep it around.
+ ACE_Message_Block &duplicate =
+ *message_block.duplicate ();
+
+ // Fake the result so that we will get called back.
+ ACE_Asynch_Read_Stream_Result_Impl *fake_result =
+ ACE_Proactor::instance ()->create_asynch_read_stream_result (this->proxy (),
+ this->handle_,
+ duplicate,
+ initial_read_size,
+ 0,
+ ACE_INVALID_HANDLE,
+ 0,
+ 0);
+
+ size_t bytes_transferred = message_block.length ();
+
+ // <complete> for Accept would have already moved the <wr_ptr>
+ // forward. Update it to the beginning position.
+ duplicate.wr_ptr (duplicate.wr_ptr () - bytes_transferred);
+
+ // This will call the callback.
+ fake_result->complete (message_block.length (),
+ 1,
+ 0);
+
+ // Zap the fake result.
+ delete fake_result;
+ }
+ else
+ // Otherwise, make sure we proceed. Initiate reading the socket
+ // stream.
+ if (this->initiate_read_stream () == -1)
+ return;
+}
+
+int
+Receiver::initiate_read_stream (void)
+{
+ // Create a new <Message_Block>. Note that this message block will
+ // be used both to <read> data asynchronously from the socket and to
+ // <write> data asynchronously to the file.
+ ACE_Message_Block *mb = 0;
+ ACE_NEW_RETURN (mb,
+ ACE_Message_Block (BUFSIZ + 1),
+ -1);
+
+ // Inititiate read
+ if (this->rs_.read (*mb,
+ mb->size () - 1) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "%p\n",
+ "ACE_Asynch_Read_Stream::read"),
+ -1);
+ return 0;
+}
+
+void
+Receiver::handle_read_stream (const ACE_Asynch_Read_Stream::Result &result)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ "handle_read_stream called\n"));
+
+ // Reset pointers.
+ result.message_block ().rd_ptr ()[result.bytes_transferred ()] = '\0';
+
+ ACE_DEBUG ((LM_DEBUG, "********************\n"));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "bytes_to_read", result.bytes_to_read ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "handle", result.handle ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "bytes_transfered", result.bytes_transferred ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "act", (u_long) result.act ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "success", result.success ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "completion_key", (u_long) result.completion_key ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "error", result.error ()));
+ ACE_DEBUG ((LM_DEBUG, "********************\n"));
+#if 0
+ // This can overrun the ACE_Log_Msg buffer and do bad things.
+ // Re-enable it at your risk.
+ ACE_DEBUG ((LM_DEBUG, "%s = %s\n", "message_block", result.message_block ().rd_ptr ()));
+#endif /* 0 */
+
+ if (result.success () && result.bytes_transferred () != 0)
+ {
+ // Successful read: write the data to the file asynchronously.
+ // Note how we reuse the <ACE_Message_Block> for the writing.
+ // Therefore, we do not delete this buffer because it is handled
+ // in <handle_write_stream>.
+ if (this->wf_.write (result.message_block (),
+ result.bytes_transferred (),
+ this->file_offset_) == -1)
+ {
+ ACE_ERROR ((LM_ERROR,
+ "%p\n",
+ "ACE_Asynch_Write_File::write"));
+ return;
+ }
+
+ // Initiate new read from the stream.
+ if (this->initiate_read_stream () == -1)
+ return;
+ }
+ else
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ "Receiver completed\n"));
+
+ // No need for this message block anymore.
+ result.message_block ().release ();
+
+ // Note that we are done with the test.
+ done = 1;
+
+ // We are done: commit suicide.
+ delete this;
+ }
+}
+
+void
+Receiver::handle_write_file (const ACE_Asynch_Write_File::Result &result)
+{
+ ACE_DEBUG ((LM_DEBUG, "handle_write_file called\n"));
+
+ ACE_DEBUG ((LM_DEBUG, "********************\n"));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "bytes_to_write", result.bytes_to_write ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "handle", result.handle ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "bytes_transfered", result.bytes_transferred ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "act", (u_long) result.act ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "success", result.success ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "completion_key", (u_long) result.completion_key ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "error", result.error ()));
+ ACE_DEBUG ((LM_DEBUG, "********************\n"));
+
+ result.message_block ().release ();
+
+ if (result.success ())
+ // Write successful: Increment file offset
+ this->file_offset_ += result.bytes_transferred ();
+
+ // This code is not robust enough to deal with short file writes
+ // (which hardly ever happen) ;-)
+ ACE_ASSERT (result.bytes_to_write () == result.bytes_transferred ());
+}
+
+class Sender : public ACE_Handler
+{
+ // = TITLE
+ // The class will be created by <main>. After connecting to the
+ // host, this class will then read data from a file and send it
+ // to the network connection.
+public:
+ Sender (void);
+ ~Sender (void);
+ int open (const ACE_TCHAR *host,
+ u_short port);
+ ACE_HANDLE handle (void) const;
+ void handle (ACE_HANDLE);
+
+protected:
+ // These methods are called by the freamwork
+
+ virtual void handle_transmit_file (const ACE_Asynch_Transmit_File::Result &result);
+ // This is called when asynchronous transmit files complete
+ virtual void handle_write_stream (const ACE_Asynch_Write_Stream::Result &result);
+ // This is called when asynchronous writes from the socket complete
+ virtual void handle_read_file (const ACE_Asynch_Read_File::Result &result);
+ // This is called when asynchronous reads from the socket complete
+
+private:
+ int transmit_file (void);
+ // Transmit the entire file in one fell swoop.
+
+ int initiate_read_file (void);
+ // Initiate an asynchronous file read.
+
+ ACE_SOCK_Stream stream_;
+ // Network I/O handle
+
+ ACE_Asynch_Write_Stream ws_;
+ // ws (write stream): for writing to the socket
+
+ ACE_Asynch_Read_File rf_;
+ // rf (read file): for writing from the file
+
+ ACE_Asynch_Transmit_File tf_;
+ // Transmit file.
+
+ ACE_HANDLE input_file_;
+ // File to read from
+
+ u_long file_offset_;
+ // Current file offset
+
+ u_long file_size_;
+ // File size
+
+ ACE_Message_Block welcome_message_;
+ // Welcome message
+
+ ACE_Asynch_Transmit_File::Header_And_Trailer header_and_trailer_;
+ // Header and trailer which goes with transmit_file
+
+ int stream_write_done_;
+ int transmit_file_done_;
+ // These flags help to determine when to close down the event loop
+};
+
+Sender::Sender (void)
+ : input_file_ (ACE_INVALID_HANDLE),
+ file_offset_ (0),
+ file_size_ (0),
+ stream_write_done_ (0),
+ transmit_file_done_ (0)
+{
+ // Moment of inspiration... :-)
+ static const char *data = "Welcome to Irfan World! Irfan RULES here !!\n";
+ this->welcome_message_.init (data,
+ ACE_OS::strlen (data));
+ this->welcome_message_.wr_ptr (ACE_OS::strlen (data));
+}
+
+Sender::~Sender (void)
+{
+ this->stream_.close ();
+}
+
+ACE_HANDLE
+Sender::handle (void) const
+{
+ return this->stream_.get_handle ();
+}
+
+void
+Sender::handle (ACE_HANDLE handle)
+{
+ this->stream_.set_handle (handle);
+}
+
+int
+Sender::open (const ACE_TCHAR *host,
+ u_short port)
+{
+ // Initialize stuff
+
+ // Open input file (in OVERLAPPED mode)
+ this->input_file_ =
+ ACE_OS::open (file, GENERIC_READ | FILE_FLAG_OVERLAPPED);
+ if (this->input_file_ == ACE_INVALID_HANDLE)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "%p\n",
+ "ACE_OS::open"), -1);
+
+ // Find file size
+ this->file_size_ =
+ ACE_OS::filesize (this->input_file_);
+
+ // Connect to remote host
+ ACE_INET_Addr address (port, host);
+ ACE_SOCK_Connector connector;
+ if (connector.connect (this->stream_,
+ address) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "%p\n",
+ "ACE_SOCK_Connector::connect"),
+ -1);
+
+ // Open ACE_Asynch_Write_Stream
+ if (this->ws_.open (*this) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "%p\n",
+ "ACE_Asynch_Write_Stream::open"),
+ -1);
+
+ // Open ACE_Asynch_Read_File
+ if (this->rf_.open (*this, this->input_file_) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "%p\n",
+ "ACE_Asynch_Read_File::open"),
+ -1);
+
+ // Start an asynchronous transmit file
+ if (this->transmit_file () == -1)
+ return -1;
+
+ // Start an asynchronous read file
+ if (this->initiate_read_file () == -1)
+ return -1;
+
+ return 0;
+}
+
+int
+Sender::transmit_file (void)
+{
+ // Open file (in SEQUENTIAL_SCAN mode)
+ ACE_HANDLE file_handle =
+ ACE_OS::open (file, GENERIC_READ | FILE_FLAG_SEQUENTIAL_SCAN);
+ if (file_handle == ACE_INVALID_HANDLE)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "%p\n",
+ "ACE_OS::open"),
+ -1);
+
+ // Open ACE_Asynch_Transmit_File
+ if (this->tf_.open (*this) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "%p\n",
+ "ACE_Asynch_Transmit_File::open"),
+ -1);
+
+ // Header and trailer data for the file.
+ // @@ What happens if header and trailer are the same?
+ this->header_and_trailer_.header_and_trailer (&this->welcome_message_,
+ this->welcome_message_.length (),
+ &this->welcome_message_,
+ this->welcome_message_.length ());
+
+ // Send the entire file in one fell swoop!
+ if (this->tf_.transmit_file (file_handle,
+ &this->header_and_trailer_) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "%p\n",
+ "ACE_Asynch_Transmit_File::transmit_file"),
+ -1);
+
+ return 0;
+}
+
+void
+Sender::handle_transmit_file (const ACE_Asynch_Transmit_File::Result &result)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ "handle_transmit_file called\n"));
+
+ ACE_DEBUG ((LM_DEBUG, "********************\n"));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "socket", result.socket ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "file", result.file ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "bytes_to_write", result.bytes_to_write ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "bytes_per_send", result.bytes_per_send ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "flags", result.flags ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "bytes_transfered", result.bytes_transferred ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "act", (u_long) result.act ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "success", result.success ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "completion_key", (u_long) result.completion_key ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "error", result.error ()));
+ ACE_DEBUG ((LM_DEBUG, "********************\n"));
+
+ // Done with file
+ ACE_OS::close (result.file ());
+
+ this->transmit_file_done_ = 1;
+ if (this->stream_write_done_)
+ done = 1;
+}
+
+int
+Sender::initiate_read_file (void)
+{
+ // Create a new <Message_Block>. Note that this message block will
+ // be used both to <read> data asynchronously from the file and to
+ // <write> data asynchronously to the socket.
+ ACE_Message_Block *mb = 0;
+ ACE_NEW_RETURN (mb,
+ ACE_Message_Block (BUFSIZ + 1),
+ -1);
+
+ // Inititiate an asynchronous read from the file
+ if (this->rf_.read (*mb,
+ mb->size () - 1,
+ this->file_offset_) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "%p\n",
+ "ACE_Asynch_Read_File::read"),
+ -1);
+ return 0;
+}
+
+void
+Sender::handle_read_file (const ACE_Asynch_Read_File::Result &result)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ "handle_read_file called\n"));
+
+ result.message_block ().rd_ptr ()[result.bytes_transferred ()] = '\0';
+
+ ACE_DEBUG ((LM_DEBUG, "********************\n"));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "bytes_to_read", result.bytes_to_read ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "handle", result.handle ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "bytes_transfered", result.bytes_transferred ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "act", (u_long) result.act ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "success", result.success ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "completion_key", (u_long) result.completion_key ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "error", result.error ()));
+ ACE_DEBUG ((LM_DEBUG, "********************\n"));
+ //ACE_DEBUG ((LM_DEBUG, "%s = %s\n", "message_block", result.message_block ().rd_ptr ()));
+
+ if (result.success ())
+ {
+ // Read successful: increment offset and write data to network.
+ // Note how we reuse the <ACE_Message_Block> for the writing.
+ // Therefore, we do not delete this buffer because it is handled
+ // in <handle_write_stream>.
+
+ this->file_offset_ += result.bytes_transferred ();
+ if (this->ws_.write (result.message_block (),
+ result.bytes_transferred ()) == -1)
+ {
+ ACE_ERROR ((LM_ERROR,
+ "%p\n",
+ "ACE_Asynch_Write_Stream::write"));
+ return;
+ }
+
+ if (this->file_size_ > this->file_offset_)
+ {
+ // Start an asynchronous read file.
+ if (initiate_read_file () == -1)
+ return;
+ }
+ }
+}
+
+void
+Sender::handle_write_stream (const ACE_Asynch_Write_Stream::Result &result)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ "handle_write_stream called\n"));
+
+ // Reset pointers.
+ result.message_block ().rd_ptr (result.message_block ().rd_ptr () - result.bytes_transferred ());
+
+ ACE_DEBUG ((LM_DEBUG, "********************\n"));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "bytes_to_write", result.bytes_to_write ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "handle", result.handle ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "bytes_transfered", result.bytes_transferred ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "act", (u_long) result.act ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "success", result.success ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "completion_key", (u_long) result.completion_key ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "error", result.error ()));
+ ACE_DEBUG ((LM_DEBUG, "********************\n"));
+#if 0
+ ACE_DEBUG ((LM_DEBUG, "%s = %s\n", "message_block", result.message_block ().rd_ptr ()));
+#endif
+
+ if (result.success ())
+ {
+ // Partial write to socket
+ int unsent_data = result.bytes_to_write () - result.bytes_transferred ();
+ if (unsent_data != 0)
+ {
+ // Reset pointers
+ result.message_block ().rd_ptr (result.bytes_transferred ());
+
+ // Duplicate the message block and retry remaining data
+ if (this->ws_.write (*result.message_block ().duplicate (),
+ unsent_data) == -1)
+ {
+ ACE_ERROR ((LM_ERROR,
+ "%p\n",
+ "ACE_Asynch_Write_Stream::write"));
+ return;
+ }
+ }
+ else if (!(this->file_size_ > this->file_offset_))
+ {
+ this->stream_write_done_ = 1;
+ if (this->transmit_file_done_)
+ done = 1;
+ }
+ }
+
+ // Release message block.
+ result.message_block ().release ();
+}
+
+static int
+parse_args (int argc, ACE_TCHAR *argv[])
+{
+ ACE_Get_Opt get_opt (argc, argv, ACE_TEXT("h:p:f:d:"));
+ int c;
+
+ while ((c = get_opt ()) != EOF)
+ switch (c)
+ {
+ case 'h':
+ host = get_opt.opt_arg ();
+ break;
+ case 'p':
+ port = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'f':
+ file = get_opt.opt_arg ();
+ break;
+ case 'd':
+ dump_file = get_opt.opt_arg ();
+ break;
+ default:
+ ACE_ERROR ((LM_ERROR, "%p.\n",
+ "usage :\n"
+ "-h <host>\n"
+ "-p <port>\n"
+ "-f <file>\n"));
+ return -1;
+ }
+
+ return 0;
+}
+
+int
+ACE_TMAIN (int argc, ACE_TCHAR *argv[])
+{
+ if (parse_args (argc, argv) == -1)
+ return -1;
+
+ Sender sender;
+
+ // Note: acceptor parameterized by the Receiver.
+ ACE_Asynch_Acceptor<Receiver> acceptor;
+
+ // If passive side
+ if (host == 0)
+ {
+ if (acceptor.open (ACE_INET_Addr (port),
+ initial_read_size,
+ 1) == -1)
+ return -1;
+ }
+ // If active side
+ else if (sender.open (host, port) == -1)
+ return -1;
+
+ int success = 1;
+
+ while (success > 0 && !done)
+ // Dispatch events via Proactor singleton.
+ success = ACE_Proactor::instance ()->handle_events ();
+
+ return 0;
+}
+
+#else /* ACE_WIN32 && !ACE_HAS_WINCE || ACE_HAS_AIO_CALLS*/
+
+int
+ACE_TMAIN (int, ACE_TCHAR *[])
+{
+ ACE_DEBUG ((LM_DEBUG,
+ "This example does not work on this platform.\n"));
+ return 1;
+}
+
+#endif /* ACE_WIN32 && !ACE_HAS_WINCE || ACE_HAS_AIO_CALLS*/
diff --git a/ACE/examples/Reactor/Proactor/test_proactor.h b/ACE/examples/Reactor/Proactor/test_proactor.h
new file mode 100644
index 00000000000..482e176041e
--- /dev/null
+++ b/ACE/examples/Reactor/Proactor/test_proactor.h
@@ -0,0 +1,56 @@
+/*
+** $Id$
+*/
+
+#ifndef _TEST_PROACTOR_H
+#define _TEST_PROACTOR_H
+
+#include "ace/Asynch_IO.h"
+
+class Receiver : public ACE_Service_Handler
+{
+ // = TITLE
+ // The class will be created by <ACE_Asynch_Acceptor> when new
+ // connections arrive. This class will then receive data from
+ // the network connection and dump it to a file.
+public:
+ // = Initialization and termination.
+ Receiver (void);
+ ~Receiver (void);
+
+ virtual void open (ACE_HANDLE handle,
+ ACE_Message_Block &message_block);
+ // This is called after the new connection has been accepted.
+
+protected:
+ // These methods are called by the framework
+
+ virtual void handle_read_stream (const ACE_Asynch_Read_Stream::Result &result);
+ // This is called when asynchronous <read> operation from the socket
+ // complete.
+
+ virtual void handle_write_file (const ACE_Asynch_Write_File::Result &result);
+ // This is called when an asynchronous <write> to the file
+ // completes.
+
+private:
+ int initiate_read_stream (void);
+ // Initiate an asynchronous <read> operation on the socket.
+
+ ACE_Asynch_Read_Stream rs_;
+ // rs (read stream): for reading from a socket.
+
+ ACE_HANDLE dump_file_;
+ // File for dumping data.
+
+ ACE_Asynch_Write_File wf_;
+ // wf (write file): for writing to a file.
+
+ u_long file_offset_;
+ // Offset for the file.
+
+ ACE_HANDLE handle_;
+ // Handle for IO to remote peer.
+};
+
+#endif /* _TEST_PROACTOR_H */
diff --git a/ACE/examples/Reactor/Proactor/test_proactor2.cpp b/ACE/examples/Reactor/Proactor/test_proactor2.cpp
new file mode 100644
index 00000000000..cd5cbf7092e
--- /dev/null
+++ b/ACE/examples/Reactor/Proactor/test_proactor2.cpp
@@ -0,0 +1,808 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// examples
+//
+// = FILENAME
+// test_proactor2.cpp
+//
+// = DESCRIPTION
+// Alexander Libman <Alibman@baltimore.com> modified
+// <test_proactor> and made this test. Instead of writing received
+// data to the file, the receiver sends them back to the
+// sender,i.e. ACE_Asynch_Write_File wf_ has been changed to
+// ACE_Asynch_Write_Stream wf_.
+//
+// = AUTHOR
+// Irfan Pyarali <irfan@cs.wustl.edu> and Alexander Libman
+// <Alibman@baltimore.com>.
+// ============================================================================
+
+#include "ace/Signal.h"
+
+#include "ace/Service_Config.h"
+#include "ace/Proactor.h"
+#include "ace/Asynch_IO.h"
+#include "ace/Asynch_IO_Impl.h"
+#include "ace/Asynch_Acceptor.h"
+#include "ace/INET_Addr.h"
+#include "ace/SOCK_Connector.h"
+#include "ace/SOCK_Acceptor.h"
+#include "ace/SOCK_Stream.h"
+#include "ace/Message_Block.h"
+#include "ace/Get_Opt.h"
+
+// FUZZ: disable check_for_streams_include
+#include "ace/streams.h"
+
+#include "ace/Task.h"
+#include "ace/OS_main.h"
+
+ACE_RCSID(Proactor, test_proactor2, "test_proactor2.cpp,v 1.27 2000/03/07 17:15:56 schmidt Exp")
+
+#if ((defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)) || (defined (ACE_HAS_AIO_CALLS)))
+ // This only works on Win32 platforms and on Unix platforms supporting
+ // POSIX aio calls.
+
+#if defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)
+
+#include "ace/WIN32_Proactor.h"
+
+#elif defined (ACE_HAS_AIO_CALLS)
+
+#include "ace/POSIX_Proactor.h"
+
+#endif
+
+ // Some debug helper functions
+ int DisableSignal ( int SigNum );
+int PrintSigMask ();
+
+#define COUT(X) cout << X ; cout.flush ();
+
+// Host that we're connecting to.
+static ACE_TCHAR *host = 0;
+
+// duplex mode: ==0 half-duplex
+// !=0 full duplex
+static int duplex = 0 ;
+
+// number threads in the Proactor thread pool
+static int nThreads = 1;
+
+// Port that we're receiving connections on.
+static u_short port = ACE_DEFAULT_SERVER_PORT;
+
+// Size of each initial asynchronous <read> operation.
+static int initial_read_size = BUFSIZ;
+
+
+#define MyMutex ACE_Recursive_Thread_Mutex
+//#define MyMutex ACE_Thread_Mutex
+//#define MyMutex ACE_Null_Mutex
+
+//--------------------------------------------------------------------------
+// MyTask plays role for Proactor threads pool
+//--------------------------------------------------------------------------
+class MyTask: public ACE_Task<ACE_MT_SYNCH>
+{
+
+public:
+
+ int svc (void) ;
+};
+
+
+int MyTask::svc (void )
+{
+ ACE_DEBUG ((LM_DEBUG, "(%t) MyTask started\n"));
+
+ while ( ACE_Proactor::event_loop_done () == 0 )
+ {
+ ACE_Proactor::run_event_loop ();
+ }
+
+ ACE_DEBUG ((LM_DEBUG, "(%t) MyTask finished\n"));
+ return 0 ;
+}
+
+//-----------------------------------------------------------
+// Receiver
+//-----------------------------------------------------------
+class Receiver : public ACE_Service_Handler
+{
+public:
+
+ Receiver (void);
+ ~Receiver (void);
+
+ virtual void open (ACE_HANDLE handle,
+ ACE_Message_Block &message_block);
+ // This is called after the new connection has been accepted.
+
+protected:
+ // These methods are called by the framework
+
+ virtual void handle_read_stream (const ACE_Asynch_Read_Stream::Result
+ &result);
+ // This is called when asynchronous <read> operation from the socket
+ // complete.
+
+ virtual void handle_write_stream (const ACE_Asynch_Write_Stream::Result
+ &result);
+ // This is called when an asynchronous <write> to the file
+ // completes.
+
+private:
+ int initiate_read_stream (void);
+ int initiate_write_stream (ACE_Message_Block & mb, int nBytes );
+ bool check_destroy () ;
+
+ ACE_Asynch_Read_Stream rs_;
+ ACE_Asynch_Write_Stream ws_;
+ ACE_HANDLE handle_;
+ MyMutex m_Mtx ;
+ long nIOCount ;
+ static long nSessions ;
+};
+
+
+long Receiver::nSessions = 0 ;
+
+Receiver::Receiver (void)
+ : handle_ (ACE_INVALID_HANDLE),
+ nIOCount ( 0 )
+{
+ ACE_Guard<MyMutex> locker (m_Mtx) ;
+ nSessions ++ ;
+ ACE_DEBUG ((LM_DEBUG, "Receiver Ctor nSessions=%d\n", nSessions ));
+}
+
+Receiver::~Receiver (void)
+{
+ ACE_Guard<MyMutex> locker (m_Mtx) ;
+ nSessions -- ;
+ ACE_OS::closesocket (this->handle_);
+ ACE_DEBUG ((LM_DEBUG, "~Receiver Dtor nSessions=%d\n", nSessions ));
+}
+
+//---------------------------------------------------------------------
+// return true if we alive, false we commited suicide
+//
+//---------------------------------------------------------------------
+bool Receiver::check_destroy ()
+{
+ {
+ ACE_Guard<MyMutex> locker (m_Mtx) ;
+
+ if ( nIOCount > 0 )
+ {
+ return true ;
+ }
+ }
+
+ delete this ;
+ return false ;
+}
+
+
+void Receiver::open (ACE_HANDLE handle,
+ ACE_Message_Block &message_block)
+{
+ ACE_UNUSED_ARG (message_block);
+
+ ACE_DEBUG ((LM_DEBUG,
+ "%N:%l:Receiver::open called\n"));
+
+
+ this->handle_ = handle;
+
+ if (this->ws_.open (*this, this->handle_ ) == -1)
+ {
+ ACE_ERROR ((LM_ERROR,
+ "%p\n",
+ "ACE_Asynch_Write_Stream::open"));
+
+ }
+ else if (this->rs_.open (*this, this->handle_) == -1)
+ {
+ ACE_ERROR ((LM_ERROR,
+ "%p\n",
+ "ACE_Asynch_Read_Stream::open"));
+ }
+ else
+ {
+ initiate_read_stream ();
+ }
+
+
+ check_destroy ();
+}
+
+int Receiver::initiate_read_stream (void)
+{
+ ACE_Guard<MyMutex> locker (m_Mtx) ;
+
+ // Create a new <Message_Block>. Note that this message block will
+ // be used both to <read> data asynchronously from the socket and to
+ // <write> data asynchronously to the file.
+ ACE_DEBUG ((LM_DEBUG,
+ "initiate_read_stream called\n"));
+
+
+ ACE_Message_Block *mb = 0;
+ ACE_NEW_RETURN (mb,
+ ACE_Message_Block (BUFSIZ + 1),
+ -1);
+
+ // Inititiate read
+ if (this->rs_.read (*mb, mb->size ()- 1) == -1)
+ {
+ mb->release () ;
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "%p\n",
+ "ACE_Asynch_Read_Stream::read"),
+ -1);
+ }
+
+ nIOCount++ ;
+ return 0;
+}
+
+int Receiver::initiate_write_stream (ACE_Message_Block & mb, int nBytes )
+{
+ ACE_Guard<MyMutex> locker (m_Mtx) ;
+ if (this->ws_.write (mb , nBytes ) == -1)
+ {
+ mb.release ();
+ ACE_ERROR_RETURN((LM_ERROR,
+ "%p\n",
+ "ACE_Asynch_Write_File::write"),
+ -1);
+ }
+
+ nIOCount++ ;
+ return 0;
+}
+
+void
+Receiver::handle_read_stream (const ACE_Asynch_Read_Stream::Result &result)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ "handle_read_stream called\n"));
+
+ // Reset pointers.
+ result.message_block ().rd_ptr ()[result.bytes_transferred ()] =
+ '\0';
+
+ ACE_DEBUG ((LM_DEBUG, "********************\n"));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "bytes_to_read", result.bytes_to_read
+ ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "handle", result.handle ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "bytes_transfered",
+ result.bytes_transferred ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "act", (u_long) result.act ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "success", result.success ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "completion_key", (u_long)
+ result.completion_key ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "error", result.error ()));
+ ACE_DEBUG ((LM_DEBUG, "********************\n"));
+ ACE_DEBUG ((LM_DEBUG, "%s = %s\n", "message_block",
+ result.message_block ().rd_ptr ()));
+
+ if ( result.success () && result.bytes_transferred () != 0)
+ {
+ // Successful read: write the data to the file asynchronously.
+ // Note how we reuse the <ACE_Message_Block> for the writing.
+ // Therefore, we do not delete this buffer because it is handled
+ // in <handle_write_stream>.
+
+ if(this->initiate_write_stream (result.message_block (),
+
+ result.bytes_transferred () ) == 0 )
+ {
+ if ( duplex != 0 )
+ {
+ // Initiate new read from the stream.
+ this->initiate_read_stream () ;
+ }
+ }
+ }
+ else
+ {
+ result.message_block ().release ();
+ ACE_DEBUG ((LM_DEBUG, "Receiver completed\n"));
+ }
+
+ {
+ ACE_Guard<MyMutex> locker (m_Mtx) ;
+ nIOCount-- ;
+ }
+ check_destroy () ;
+}
+
+void
+Receiver::handle_write_stream (const ACE_Asynch_Write_Stream::Result
+ &result)
+{
+ ACE_DEBUG ((LM_DEBUG, "handle_write_stream called\n"));
+
+ ACE_DEBUG ((LM_DEBUG, "********************\n"));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "bytes_to_write",
+ result.bytes_to_write ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "handle", result.handle ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "bytes_transfered",
+ result.bytes_transferred ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "act", (u_long) result.act ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "success", result.success ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "completion_key", (u_long)
+ result.completion_key ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "error", result.error ()));
+ ACE_DEBUG ((LM_DEBUG, "********************\n"));
+
+ result.message_block ().release ();
+
+ if (result.success ())
+ {
+ // This code is not robust enough to deal with short file writes
+ // (which hardly ever happen) ;-)
+ //ACE_ASSERT (result.bytes_to_write () == result.bytes_transferred ());
+
+ if ( duplex == 0 )
+ {
+ initiate_read_stream () ;
+ }
+ }
+
+ {
+ ACE_Guard<MyMutex> locker (m_Mtx) ;
+ nIOCount-- ;
+ }
+ check_destroy () ;
+}
+
+//-------------------------------------------------------------------------
+// Sender: sends indefinetely welcome message
+// and recieves it back
+//------------------------------------------------------------------------
+class Sender : public ACE_Handler
+{
+public:
+ Sender (void);
+ ~Sender (void);
+ int open (const ACE_TCHAR *host, u_short port);
+ void close ();
+ ACE_HANDLE handle (void) const;
+ void handle (ACE_HANDLE);
+
+protected:
+// These methods are called by the freamwork
+
+virtual void handle_read_stream (const ACE_Asynch_Read_Stream::Result
+&result);
+// This is called when asynchronous reads from the socket complete
+
+virtual void handle_write_stream (const ACE_Asynch_Write_Stream::Result
+&result);
+// This is called when asynchronous writes from the socket complete
+
+private:
+
+int initiate_read_stream (void);
+int initiate_write_stream (void);
+
+ACE_SOCK_Stream stream_;
+// Network I/O handle
+
+ACE_Asynch_Write_Stream ws_;
+// ws (write stream): for writing to the socket
+
+ACE_Asynch_Read_Stream rs_;
+// rs (read file): for reading from the socket
+
+ACE_Message_Block welcome_message_;
+// Welcome message
+
+MyMutex m_Mtx ;
+long nIOCount ;
+};
+
+static char *data = "Welcome to Irfan World! Irfan RULES here !!\n";
+
+Sender::Sender (void)
+ :nIOCount ( 0 )
+{
+ // Moment of inspiration... :-)
+ this->welcome_message_.init (data, ACE_OS::strlen (data));
+}
+
+Sender::~Sender (void)
+{
+ close ();
+}
+
+void Sender::close ()
+{
+ this->stream_.close ();
+}
+
+ACE_HANDLE Sender::handle (void) const
+{
+ return this->stream_.get_handle ();
+}
+
+void Sender::handle (ACE_HANDLE handle)
+{
+ this->stream_.set_handle (handle);
+}
+
+int Sender::open (const ACE_TCHAR *host, u_short port)
+{
+ // Initialize stuff
+ // Connect to remote host
+ ACE_INET_Addr address (port, host);
+ ACE_SOCK_Connector connector;
+
+ if (connector.connect (this->stream_,
+ address) == -1)
+ {
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "%p\n",
+ "ACE_SOCK_Connector::connect"),
+ -1);
+ }
+
+ // Open ACE_Asynch_Write_Stream
+ if (this->ws_.open (*this) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "%p\n",
+ "ACE_Asynch_Write_Stream::open"),
+ -1);
+
+ // Open ACE_Asynch_Read_Stream
+ if (this->rs_.open (*this) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "%p\n",
+ "ACE_Asynch_Read_File::open"),
+ -1);
+
+ // Start an asynchronous transmit file
+ if ( this->initiate_write_stream () == -1)
+ return -1;
+
+ if ( duplex != 0 )
+ {
+ // Start an asynchronous read file
+ if (this->initiate_read_stream () == -1)
+ return -1;
+ }
+
+ return 0;
+}
+
+int Sender::initiate_write_stream (void)
+{
+ ACE_Guard<MyMutex> locker (m_Mtx) ;
+
+
+ welcome_message_.rd_ptr( welcome_message_.base ());
+ welcome_message_.wr_ptr( welcome_message_.base ());
+ welcome_message_.wr_ptr (ACE_OS::strlen (data));
+
+ if (this->ws_.write (welcome_message_,
+ welcome_message_.length ()
+ ) == -1)
+ {
+ ACE_ERROR_RETURN((LM_ERROR,
+ "%p\n",
+ "ACE_Asynch_Write_File::write"),
+ -1);
+ }
+
+ nIOCount++ ;
+ return 0;
+}
+
+int Sender::initiate_read_stream (void)
+{
+ ACE_Guard<MyMutex> locker (m_Mtx) ;
+
+ // Create a new <Message_Block>. Note that this message block will
+ // be used both to <read> data asynchronously from the socket and to
+ // <write> data asynchronously to the file.
+ ACE_DEBUG ((LM_DEBUG,
+ "initiate_read_stream called\n"));
+
+
+ ACE_Message_Block *mb = 0;
+ ACE_NEW_RETURN (mb,
+ ACE_Message_Block (BUFSIZ + 1),
+ -1);
+
+ // Inititiate read
+ if (this->rs_.read (*mb, mb->size ()- 1) == -1)
+ {
+ mb->release () ;
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "%p\n",
+ "ACE_Asynch_Read_Stream::read"),
+ -1);
+ }
+
+ nIOCount++ ;
+ return 0;
+}
+
+
+void Sender::handle_write_stream (const ACE_Asynch_Write_Stream::Result
+ &result)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ "handle_write_stream called\n"));
+
+ // Reset pointers.
+ result.message_block ().rd_ptr (result.message_block ().rd_ptr () -
+ result.bytes_transferred ());
+
+
+ ACE_DEBUG ((LM_DEBUG, "********************\n"));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "bytes_to_write",
+ result.bytes_to_write ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "handle", result.handle ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "bytes_transfered",
+ result.bytes_transferred ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "act", (u_long) result.act ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "success", result.success ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "completion_key", (u_long)
+ result.completion_key ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "error", result.error ()));
+ ACE_DEBUG ((LM_DEBUG, "********************\n"));
+ ACE_DEBUG ((LM_DEBUG, "%s = %s\n", "message_block",
+ result.message_block ().rd_ptr ()));
+
+ // Simplify just for Test
+ if (result.success () && result.bytes_transferred () != 0)
+ {
+ if ( duplex != 0 ) // full duplex, continue write
+ {
+ initiate_write_stream () ;
+ }
+ else // half-duplex read reply, after read we will start
+ // write
+ {
+ initiate_read_stream () ;
+ }
+ }
+
+ {
+ ACE_Guard<MyMutex> locker (m_Mtx) ;
+ nIOCount-- ;
+ }
+}
+
+void
+Sender::handle_read_stream (const ACE_Asynch_Read_Stream::Result &result)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ "handle_read_stream called\n"));
+
+ // Reset pointers.
+ result.message_block ().rd_ptr ()[result.bytes_transferred ()] =
+ '\0';
+
+ ACE_DEBUG ((LM_DEBUG, "********************\n"));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "bytes_to_read", result.bytes_to_read
+ ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "handle", result.handle ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "bytes_transfered",
+ result.bytes_transferred ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "act", (u_long) result.act ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "success", result.success ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "completion_key", (u_long)
+ result.completion_key ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "error", result.error ()));
+ ACE_DEBUG ((LM_DEBUG, "********************\n"));
+ ACE_DEBUG ((LM_DEBUG, "%s = %s\n", "message_block",
+ result.message_block ().rd_ptr ()));
+
+ result.message_block().release ();
+
+ if ( result.success () && result.bytes_transferred () != 0)
+ {
+ // Successful read: write the data to the file asynchronously.
+ // Note how we reuse the <ACE_Message_Block> for the writing.
+ // Therefore, we do not delete this buffer because it is handled
+ // in <handle_write_stream>.
+
+ if ( duplex != 0 ) // full duplex, continue read
+ {
+ initiate_read_stream () ;
+ }
+ else // half-duplex writey, after write we will start read
+ {
+ initiate_write_stream () ;
+ }
+ }
+
+ {
+ ACE_Guard<MyMutex> locker (m_Mtx) ;
+ nIOCount-- ;
+ }
+}
+
+//--------------------------------------------------------------------------
+
+static int
+parse_args (int argc, ACE_TCHAR *argv[])
+{
+ ACE_Get_Opt get_opt (argc, argv, ACE_TEXT("n:p:d:h:"));
+ int c;
+
+ while ((c = get_opt ()) != EOF)
+ switch (c)
+ {
+ case 'h':
+ host = get_opt.opt_arg ();
+ break;
+ case 'n':
+ nThreads = ACE_OS::atoi (get_opt.opt_arg ()) ;
+ break;
+ case 'p':
+ port = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'd':
+ duplex = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ default:
+ ACE_ERROR ((LM_ERROR, "%p.\n",
+ "usage :\n"
+ "-h <host> for Sender mode\n"
+ "-d <duplex mode 1-on/0-off>\n"
+ "-p <port to listen/connect>\n"
+ "-n <number threads for Proactor pool>\n"));
+ return -1;
+ }
+
+ return 0;
+}
+
+int
+ACE_TMAIN (int argc, ACE_TCHAR *argv[])
+{
+ ACE_UNUSED_ARG (initial_read_size);
+
+ if (parse_args (argc, argv) == -1)
+ return -1;
+
+#if defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)
+
+ ACE_WIN32_Proactor * pImpl = new ACE_WIN32_Proactor;
+
+#elif defined (ACE_HAS_AIO_CALLS)
+
+ // ACE_POSIX_AIOCB_Proactor * pImpl = new ACE_POSIX_AIOCB_Proactor;
+ ACE_POSIX_SIG_Proactor * pImpl = new ACE_POSIX_SIG_Proactor;
+#endif
+
+ ACE_Proactor Proactor ( pImpl ,1 );
+
+ ACE_Proactor::instance( & Proactor );
+
+
+ MyTask Task1 ;
+
+ if (Task1.activate (THR_NEW_LWP, nThreads ) == -1)
+ {
+ ACE_ERROR_RETURN ((LM_ERROR, "%p.\n", "main"), -1);
+ }
+
+ Sender sender;
+ ACE_Asynch_Acceptor<Receiver> acceptor;
+
+ int Rc = -1 ;
+
+ if ( host == NULL ) // Acceptor
+ {
+ // Simplify , initial read with zero size
+ Rc = acceptor.open (ACE_INET_Addr (port),0,1);
+
+ }
+ else
+ {
+ Rc = sender.open (host, port);
+ }
+
+ if ( Rc == 0 )
+ {
+ char c ;
+ cout << "Press any key to stop and exit=>\n" << flush ;
+ cin.clear ();
+ cin >> c ;
+ }
+
+ ACE_Proactor::end_event_loop () ;
+
+ if ( host != NULL ) // we are sender
+ {
+ sender.close () ; // disconnect to get reciever error !!!
+ }
+
+
+ ACE_Thread_Manager * pTM = ACE_Thread_Manager::instance();
+
+ pTM->wait_task ( & Task1 ) ;
+
+ ACE_Proactor::instance( ( ACE_Proactor* )NULL );
+
+ return 0;
+}
+//--------------------------------------------------------------------
+//
+//--------------------------------------------------------------------
+int DisableSignal ( int SigNum )
+{
+
+#ifndef ACE_WIN32
+ sigset_t signal_set;
+ if ( sigemptyset (&signal_set) == - 1 )
+ {
+ ACE_ERROR ((LM_ERROR,
+ "Error:(%P | %t):%p\n",
+ "sigemptyset failed"));
+ }
+
+ sigaddset (&signal_set, SigNum);
+
+ // Put the <signal_set>.
+ if (ACE_OS::pthread_sigmask (SIG_BLOCK, &signal_set, 0) != 0)
+ {
+ ACE_ERROR ((LM_ERROR,
+ "Error:(%P | %t):%p\n",
+ "pthread_sigmask failed"));
+ }
+#else
+ ACE_UNUSED_ARG(SigNum);
+#endif
+
+ return 1;
+}
+//--------------------------------------------------------------------
+// Get the <signal_set> back from the OS.
+//--------------------------------------------------------------------
+
+int PrintSigMask ()
+{
+#ifndef ACE_WIN32
+
+ sigset_t mask ;
+ int member = 0;
+
+ COUT ( "\n=============Signal Mask==========" )
+
+ if (ACE_OS::pthread_sigmask (SIG_SETMASK, 0, & mask ) != 0)
+ {
+ ACE_ERROR ((LM_ERROR,
+ "Error:(%P | %t):%p\n",
+ "ACE_OS::pthread_sigmask failed"));
+ }
+ else for (int i = 1 ; i < 1000; i++)
+ {
+ member = sigismember (&mask,i);
+
+ COUT ( "\nSig " )
+ COUT ( i )
+ COUT ( " is " )
+ COUT (member )
+
+ if (member == -1)
+ {
+ break ;
+ }
+ }
+#endif
+ return 0;
+}
+
+#endif /* ACE_WIN32 && !ACE_HAS_WINCE || ACE_HAS_AIO_CALLS*/
diff --git a/ACE/examples/Reactor/Proactor/test_proactor3.cpp b/ACE/examples/Reactor/Proactor/test_proactor3.cpp
new file mode 100644
index 00000000000..c47468276c8
--- /dev/null
+++ b/ACE/examples/Reactor/Proactor/test_proactor3.cpp
@@ -0,0 +1,864 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// examples
+//
+// = FILENAME
+// test_proactor3.cpp
+//
+// = DESCRIPTION
+// This program illustrates how the <ACE_Proactor> can be used to
+// implement an application that does various asynchronous
+// operations.
+//
+// = AUTHOR
+// Irfan Pyarali <irfan@cs.wustl.edu>
+// modified by Alexander Libman <alibman@baltimore.com>
+// from original test_proactor.cpp
+// ============================================================================
+
+#include "ace/Signal.h"
+
+#include "ace/Service_Config.h"
+#include "ace/Proactor.h"
+#include "ace/Asynch_IO.h"
+#include "ace/Asynch_IO_Impl.h"
+#include "ace/Asynch_Acceptor.h"
+#include "ace/INET_Addr.h"
+#include "ace/SOCK_Connector.h"
+#include "ace/SOCK_Acceptor.h"
+#include "ace/SOCK_Stream.h"
+#include "ace/Message_Block.h"
+#include "ace/Get_Opt.h"
+
+// FUZZ: disable check_for_streams_include
+#include "ace/streams.h"
+
+#include "ace/Task.h"
+
+ACE_RCSID(Proactor, test_proactor, "test_proactor.cpp,v 1.27 2000/03/07 17:15:56 schmidt Exp")
+
+#if ((defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)) || (defined (ACE_HAS_AIO_CALLS)))
+ // This only works on Win32 platforms and on Unix platforms
+ // supporting POSIX aio calls.
+
+#if defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)
+
+# include "ace/WIN32_Proactor.h"
+
+#elif defined (ACE_HAS_AIO_CALLS)
+
+# include "ace/POSIX_Proactor.h"
+# include "ace/SUN_Proactor.h"
+
+#endif /* defined (ACE_WIN32) && !defined (ACE_HAS_WINCE) */
+
+// Some debug helper functions
+static int disable_signal (int sigmin, int sigmax);
+#if 0
+static int print_sigmask (void);
+#endif
+
+#define COUT(X) cout << X; cout.flush ();
+
+// Proactor Type (UNIX only, Win32 ignored) 0-default, 1 -AIOCB,
+// 2-SIG, 3-SUN
+static int proactor_type = 0;
+
+// POSIX : > 0 max number aio operations proactor,
+static int max_aio_operations = 0;
+
+// Host that we're connecting to.
+static ACE_TCHAR *host = 0;
+
+// number of Senders instances
+static int senders = 1;
+static const int MaxSenders = 100;
+
+// duplex mode: ==0 half-duplex
+// !=0 full duplex
+static int duplex = 0;
+
+// number threads in the Proactor thread pool
+static int threads = 1;
+
+// Port that we're receiving connections on.
+static u_short port = ACE_DEFAULT_SERVER_PORT;
+
+class MyTask: public ACE_Task<ACE_MT_SYNCH>
+{
+ // = TITLE
+ // MyTask plays role for Proactor threads pool
+public:
+ MyTask (void) : threads_ (0), proactor_ (0) {}
+
+ int svc (void);
+ void waitready (void) { event_.wait (); }
+
+private:
+ ACE_Recursive_Thread_Mutex mutex_;
+ int threads_;
+ ACE_Proactor *proactor_;
+ ACE_Manual_Event event_;
+
+ void create_proactor (void);
+ void delete_proactor (void);
+};
+
+void
+MyTask::create_proactor (void)
+{
+ ACE_Guard<ACE_Recursive_Thread_Mutex> locker (mutex_);
+
+ if (threads_ == 0)
+ {
+#if defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)
+ ACE_WIN32_Proactor *proactor = new ACE_WIN32_Proactor;
+ ACE_DEBUG ((LM_DEBUG,"(%t) Create Proactor Type=WIN32"));
+
+#elif defined (ACE_HAS_AIO_CALLS)
+
+ ACE_POSIX_Proactor *proactor = 0;
+
+ switch (proactor_type)
+ {
+ case 1: proactor = new ACE_POSIX_AIOCB_Proactor (max_aio_operations);
+ ACE_DEBUG ((LM_DEBUG,"(%t) Create Proactor Type=AIOCB\n"));
+ break;
+ case 2: proactor = new ACE_POSIX_SIG_Proactor;
+ ACE_DEBUG ((LM_DEBUG,"(%t) Create Proactor Type=SIG\n"));
+ break;
+# if defined (sun)
+ case 3: proactor = new ACE_SUN_Proactor (max_aio_operations);
+ ACE_DEBUG ((LM_DEBUG,"(%t) Create Proactor Type=SUN\n"));
+ break;
+# endif /* sun */
+ default:proactor = new ACE_POSIX_SIG_Proactor;
+ ACE_DEBUG ((LM_DEBUG,"(%t) Create Proactor Type=SIG\n"));
+ break;
+ }
+#endif
+
+ proactor_ = new ACE_Proactor (proactor, 1);
+
+ ACE_Proactor::instance(proactor_);
+ event_.signal ();
+ }
+
+ threads_++;
+}
+
+void
+MyTask::delete_proactor (void)
+{
+ ACE_Guard<ACE_Recursive_Thread_Mutex> locker (mutex_);
+ if (--threads_ == 0)
+ {
+ ACE_DEBUG ((LM_DEBUG, "(%t) Delete Proactor\n"));
+ ACE_Proactor::instance ((ACE_Proactor *) 0);
+ delete proactor_;
+ proactor_ = 0;
+ }
+}
+
+int
+MyTask::svc (void)
+{
+ ACE_DEBUG ((LM_DEBUG, "(%t) MyTask started\n"));
+
+ create_proactor ();
+ disable_signal (ACE_SIGRTMIN, ACE_SIGRTMAX);
+
+ while (ACE_Proactor::event_loop_done () == 0)
+ ACE_Proactor::run_event_loop ();
+
+ delete_proactor ();
+
+ ACE_DEBUG ((LM_DEBUG, "(%t) MyTask finished\n"));
+ return 0;
+}
+
+class Receiver : public ACE_Service_Handler
+{
+public:
+
+ Receiver (void);
+ ~Receiver (void);
+
+ virtual void open (ACE_HANDLE handle,
+ ACE_Message_Block &message_block);
+ // This is called after the new connection has been accepted.
+
+ static long get_number_sessions (void) { return sessions_; }
+
+protected:
+ // These methods are called by the framework
+
+ virtual void handle_read_stream (const ACE_Asynch_Read_Stream::Result &result);
+ // This is called when asynchronous <read> operation from the socket
+ // complete.
+
+ virtual void handle_write_stream (const ACE_Asynch_Write_Stream::Result &result);
+ // This is called when an asynchronous <write> to the file
+ // completes.
+
+private:
+ int initiate_read_stream (void);
+ int initiate_write_stream (ACE_Message_Block & mb, int nBytes);
+ int check_destroy (void);
+
+ ACE_Asynch_Read_Stream rs_;
+ ACE_Asynch_Write_Stream ws_;
+ ACE_HANDLE handle_;
+ ACE_Recursive_Thread_Mutex mutex_;
+ long io_count_;
+ static long sessions_;
+};
+
+long Receiver::sessions_ = 0;
+
+Receiver::Receiver (void)
+ : handle_ (ACE_INVALID_HANDLE),
+ io_count_ (0)
+{
+ ACE_Guard<ACE_Recursive_Thread_Mutex> locker (mutex_);
+ sessions_++;
+ ACE_DEBUG ((LM_DEBUG, "Receiver Ctor sessions_=%d\n", sessions_));
+}
+
+Receiver::~Receiver (void)
+{
+ ACE_Guard<ACE_Recursive_Thread_Mutex> locker (mutex_);
+ sessions_--;
+ ACE_OS::closesocket (this->handle_);
+ ACE_DEBUG ((LM_DEBUG, "~Receiver Dtor sessions_=%d\n", sessions_));
+}
+
+// return true if we alive, false we commited suicide
+int
+Receiver::check_destroy (void)
+{
+ {
+ ACE_Guard<ACE_Recursive_Thread_Mutex> locker (mutex_);
+
+ if (io_count_ > 0)
+ return 1;
+ }
+
+ delete this;
+ return 0;
+}
+
+void
+Receiver::open (ACE_HANDLE handle,
+ ACE_Message_Block &)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ "%N:%l:Receiver::open called\n"));
+
+ this->handle_ = handle;
+
+ if (this->ws_.open (*this, this->handle_) == -1)
+ ACE_ERROR ((LM_ERROR,
+ "%p\n",
+ "ACE_Asynch_Write_Stream::open"));
+ else if (this->rs_.open (*this, this->handle_) == -1)
+ ACE_ERROR ((LM_ERROR,
+ "%p\n",
+ "ACE_Asynch_Read_Stream::open"));
+ else
+ initiate_read_stream ();
+
+ check_destroy ();
+}
+
+int
+Receiver::initiate_read_stream (void)
+{
+ ACE_Guard<ACE_Recursive_Thread_Mutex> locker (mutex_);
+
+ ACE_Message_Block *mb = 0;
+ ACE_NEW_RETURN (mb,
+ ACE_Message_Block (BUFSIZ + 1),
+ -1);
+
+ // Inititiate read
+ if (this->rs_.read (*mb, mb->size ()- 1) == -1)
+ {
+ mb->release ();
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "%p\n",
+ "ACE_Asynch_Read_Stream::read"),
+ -1);
+ }
+
+ io_count_++;
+ return 0;
+}
+
+int
+Receiver::initiate_write_stream (ACE_Message_Block &mb, int nbytes)
+{
+ ACE_Guard<ACE_Recursive_Thread_Mutex> locker (mutex_);
+ if (nbytes <= 0)
+ {
+ mb.release ();
+ ACE_ERROR_RETURN((LM_ERROR,
+ "ACE_Asynch_Write_Stream::write nbytes <0 "),
+ -1);
+ }
+
+ if (this->ws_.write (mb, nbytes) == -1)
+ {
+ mb.release ();
+ ACE_ERROR_RETURN((LM_ERROR,
+ "%p\n",
+ "ACE_Asynch_Write_Stream::write"),
+ -1);
+ }
+
+ io_count_++;
+ return 0;
+}
+
+void
+Receiver::handle_read_stream (const ACE_Asynch_Read_Stream::Result &result)
+{
+ // Reset pointers.
+ result.message_block ().rd_ptr ()[result.bytes_transferred ()] = '\0';
+
+ if (result.bytes_transferred () == 0 || result.error () != 0)
+ {
+ ACE_DEBUG ((LM_DEBUG, "handle_read_stream called\n"));
+ ACE_DEBUG ((LM_DEBUG, "********************\n"));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "bytes_to_read", result.bytes_to_read ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "handle", result.handle ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "bytes_transfered", result.bytes_transferred ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "act", (u_long) result.act ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "success", result.success ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "completion_key", (u_long) result.completion_key ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "error", result.error ()));
+ ACE_DEBUG ((LM_DEBUG, "********************\n"));
+ ACE_DEBUG ((LM_DEBUG, "%s = %s\n", "message_block", result.message_block ().rd_ptr ()));
+ }
+
+ if (result.success () && result.bytes_transferred () != 0)
+ {
+ // Successful read: write the data to the file asynchronously.
+ // Note how we reuse the <ACE_Message_Block> for the writing.
+ // Therefore, we do not delete this buffer because it is handled
+ // in <handle_write_stream>.
+
+ if(this->initiate_write_stream (result.message_block (),
+ result.bytes_transferred ()) == 0)
+ {
+ if (duplex != 0)
+ {
+ // Initiate new read from the stream.
+ this->initiate_read_stream ();
+ }
+ }
+ }
+ else
+ {
+ result.message_block ().release ();
+ ACE_DEBUG ((LM_DEBUG, "Receiver completed\n"));
+ }
+
+ {
+ ACE_Guard<ACE_Recursive_Thread_Mutex> locker (mutex_);
+ io_count_--;
+ }
+ check_destroy ();
+}
+
+void
+Receiver::handle_write_stream (const ACE_Asynch_Write_Stream::Result &result)
+{
+ if (result.bytes_transferred () == 0 || result.error () != 0)
+ {
+ ACE_DEBUG ((LM_DEBUG, "handle_write_stream called\n"));
+
+ ACE_DEBUG ((LM_DEBUG, "********************\n"));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "bytes_to_write", result.bytes_to_write ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "handle", result.handle ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "bytes_transfered", result.bytes_transferred ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "act", (u_long) result.act ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "success", result.success ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "completion_key", (u_long) result.completion_key ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "error", result.error ()));
+ ACE_DEBUG ((LM_DEBUG, "********************\n"));
+ }
+
+ result.message_block ().release ();
+
+ if (result.success () && result.bytes_transferred () != 0)
+ {
+ // This code is not robust enough to deal with short file writes
+ // (which hardly ever happen);-)
+ // ACE_ASSERT (result.bytes_to_write () == result.bytes_transferred ());
+
+ if (duplex == 0)
+ initiate_read_stream ();
+ }
+
+ {
+ ACE_Guard<ACE_Recursive_Thread_Mutex> locker (mutex_);
+ io_count_--;
+ }
+ check_destroy ();
+}
+
+class Sender : public ACE_Handler
+{
+ // = TITLE
+ // Sends welcome messages receives them back.
+public:
+ Sender (void);
+ ~Sender (void);
+ int open (const ACE_TCHAR *host, u_short port);
+ void close (void);
+ ACE_HANDLE handle (void) const;
+
+protected:
+ // These methods are called by the freamwork
+
+ virtual void handle_read_stream (const ACE_Asynch_Read_Stream::Result &result);
+ // This is called when asynchronous reads from the socket complete
+
+ virtual void handle_write_stream (const ACE_Asynch_Write_Stream::Result &result);
+ // This is called when asynchronous writes from the socket complete
+
+private:
+
+ int initiate_read_stream (void);
+ int initiate_write_stream (void);
+
+ ACE_SOCK_Stream stream_;
+ // Network I/O handle
+
+ ACE_Asynch_Write_Stream ws_;
+ // ws (write stream): for writing to the socket
+
+ ACE_Asynch_Read_Stream rs_;
+ // rs (read file): for reading from the socket
+
+ ACE_Message_Block welcome_message_;
+ // Welcome message
+
+ ACE_Recursive_Thread_Mutex mutex_;
+ long io_count_;
+};
+
+static char *data = "Welcome to Irfan World! Irfan RULES here !!\n";
+
+Sender::Sender (void)
+ : io_count_ (0)
+{
+ // Moment of inspiration... :-)
+ this->welcome_message_.init (data, ACE_OS::strlen (data));
+}
+
+Sender::~Sender (void)
+{
+ close ();
+}
+
+void Sender::close (void)
+{
+ this->stream_.close ();
+}
+
+ACE_HANDLE Sender::handle (void) const
+{
+ return this->stream_.get_handle ();
+}
+
+int Sender::open (const ACE_TCHAR *host, u_short port)
+{
+ // Initialize stuff
+ // Connect to remote host
+ ACE_INET_Addr address (port, host);
+ ACE_SOCK_Connector connector;
+
+ if (connector.connect (this->stream_,
+ address) == -1)
+ {
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "%p\n",
+ "ACE_SOCK_Connector::connect"),
+ -1);
+ }
+
+ // Open ACE_Asynch_Write_Stream
+ if (this->ws_.open (*this) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "%p\n",
+ "ACE_Asynch_Write_Stream::open"),
+ -1);
+
+ // Open ACE_Asynch_Read_Stream
+ if (this->rs_.open (*this) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "%p\n",
+ "ACE_Asynch_Read_Stream::open"),
+ -1);
+
+ // Start an asynchronous transmit file
+ if (this->initiate_write_stream () == -1)
+ return -1;
+
+ if (duplex != 0)
+ // Start an asynchronous read file
+ if (this->initiate_read_stream () == -1)
+ return -1;
+
+ return 0;
+}
+
+int
+Sender::initiate_write_stream (void)
+{
+ ACE_Guard<ACE_Recursive_Thread_Mutex> locker (mutex_);
+
+ welcome_message_.rd_ptr(welcome_message_.base ());
+ welcome_message_.wr_ptr(welcome_message_.base ());
+ welcome_message_.wr_ptr (ACE_OS::strlen (data));
+
+ if (this->ws_.write (welcome_message_,
+ welcome_message_.length ()) == -1)
+ ACE_ERROR_RETURN((LM_ERROR,
+ "%p\n",
+ "ACE_Asynch_Write_Stream::write"),
+ -1);
+ io_count_++;
+ return 0;
+}
+
+int
+Sender::initiate_read_stream (void)
+{
+ ACE_Guard<ACE_Recursive_Thread_Mutex> locker (mutex_);
+
+ // Create a new <Message_Block>. Note that this message block will
+ // be used both to <read> data asynchronously from the socket and to
+ // <write> data asynchronously to the file.
+ ACE_DEBUG ((LM_DEBUG,
+ "initiate_read_stream called\n"));
+
+ ACE_Message_Block *mb = 0;
+ ACE_NEW_RETURN (mb,
+ ACE_Message_Block (BUFSIZ + 1),
+ -1);
+
+ // Inititiate read
+ if (this->rs_.read (*mb, mb->size ()- 1) == -1)
+ {
+ mb->release ();
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "%p\n",
+ "ACE_Asynch_Read_Stream::read"),
+ -1);
+ }
+
+ io_count_++;
+ return 0;
+}
+
+void
+Sender::handle_write_stream (const ACE_Asynch_Write_Stream::Result &result)
+{
+ if (result.bytes_transferred () == 0 || result.error () != 0)
+ {
+ ACE_DEBUG ((LM_DEBUG, "handle_write_stream called\n"));
+
+ // Reset pointers.
+ result.message_block ().rd_ptr (result.message_block ().rd_ptr () - result.bytes_transferred ());
+
+ ACE_DEBUG ((LM_DEBUG, "********************\n"));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "bytes_to_write", result.bytes_to_write ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "handle", result.handle ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "bytes_transfered", result.bytes_transferred ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "act", (u_long) result.act ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "success", result.success ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "completion_key", (u_long) result.completion_key ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "error", result.error ()));
+ ACE_DEBUG ((LM_DEBUG, "********************\n"));
+ ACE_DEBUG ((LM_DEBUG, "%s = %s\n", "message_block", result.message_block ().rd_ptr ()));
+ }
+
+ // Simplify just for Test
+ if (result.success () && result.bytes_transferred () != 0)
+ {
+ if (duplex != 0) // full duplex, continue write
+ initiate_write_stream ();
+ else // half-duplex read reply, after read we will start write
+ initiate_read_stream ();
+ }
+
+ {
+ ACE_Guard<ACE_Recursive_Thread_Mutex> locker (mutex_);
+ io_count_--;
+ }
+}
+
+void
+Sender::handle_read_stream (const ACE_Asynch_Read_Stream::Result &result)
+{
+ if (result.bytes_transferred () == 0 || result.error () != 0)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ "handle_read_stream called\n"));
+
+ // Reset pointers.
+ result.message_block ().rd_ptr ()[result.bytes_transferred ()] = '\0';
+
+ ACE_DEBUG ((LM_DEBUG, "********************\n"));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "bytes_to_read", result.bytes_to_read ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "handle", result.handle ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "bytes_transfered", result.bytes_transferred ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "act", (u_long) result.act ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "success", result.success ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "completion_key", (u_long) result.completion_key ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "error", result.error ()));
+ ACE_DEBUG ((LM_DEBUG, "********************\n"));
+ ACE_DEBUG ((LM_DEBUG, "%s = %s\n", "message_block", result.message_block ().rd_ptr ()));
+ }
+
+ result.message_block().release ();
+
+ if (result.success () && result.bytes_transferred () != 0)
+ {
+ // Successful read: write the data to the file asynchronously.
+ // Note how we reuse the <ACE_Message_Block> for the writing.
+ // Therefore, we do not delete this buffer because it is handled
+ // in <handle_write_stream>.
+
+ if (duplex != 0) // full duplex, continue read
+ initiate_read_stream ();
+ else // half-duplex writey, after write we will start read
+ initiate_write_stream ();
+ }
+
+ {
+ ACE_Guard<ACE_Recursive_Thread_Mutex> locker (mutex_);
+ io_count_--;
+ }
+}
+
+static int
+set_proactor_type (const char *ptype)
+{
+ if (!ptype)
+ return false;
+
+ switch (toupper (*ptype))
+ {
+ case 'D' : proactor_type = 0; return true;
+ case 'A' : proactor_type = 1; return true;
+ case 'I' : proactor_type = 2; return true;
+#if defined (sun)
+ case 'S' : proactor_type = 3; return true;
+#endif /* sun */
+ }
+ return false;
+}
+
+static int
+parse_args (int argc, ACE_TCHAR *argv[])
+{
+ ACE_Get_Opt get_opt (argc, argv, ACE_TEXT("t:o:n:p:d:h:s:u"));
+ int c;
+
+ while ((c = get_opt ()) != EOF)
+ switch (c)
+ {
+ case 'd': // duplex
+ duplex = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'h': // host for sender
+ host = get_opt.opt_arg ();
+ break;
+ case 'p': // port number
+ port = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'n': // thread pool size
+ threads = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 's': // number of senders
+ senders = ACE_OS::atoi (get_opt.opt_arg ());
+ if (senders > MaxSenders)
+ senders = MaxSenders;
+ break;
+ case 'o': // max number of aio for proactor
+ max_aio_operations = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 't': // Proactor Type
+ if (set_proactor_type (get_opt.opt_arg ()))
+ break;
+ case 'u':
+ default:
+ ACE_ERROR ((LM_ERROR, "%p.",
+ "\nusage:"
+ "\n-o <max number of started aio operations for Proactor>"
+ "\n-t <Proactor type> UNIX-only, Win32-default always:"
+ "\n a AIOCB"
+ "\n i SIG"
+ "\n s SUN"
+ "\n d default"
+ "\n-d <duplex mode 1-on/0-off>"
+ "\n-h <host> for Sender mode"
+ "\n-n <number threads for Proactor pool>"
+ "\n-p <port to listen/connect>"
+ "\n-s <number of sender's instances>"
+ "\n-u show this message"
+ "\n"));
+
+ return -1;
+ }
+
+ return 0;
+}
+
+int
+ACE_TMAIN (int argc, ACE_TCHAR *argv[])
+{
+#if defined (sun)
+ ACE_DEBUG ((LM_DEBUG, "\nSUN defined!\n"));
+#endif
+ if (parse_args (argc, argv) == -1)
+ return -1;
+
+ disable_signal (ACE_SIGRTMIN, ACE_SIGRTMAX);
+
+ MyTask task1;
+
+ if (task1.activate (THR_NEW_LWP, threads) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "%p.\n",
+ "main"),
+ -1);
+
+ // wait for creation of Proactor
+ task1.waitready ();
+
+ Sender * send_list[MaxSenders];
+
+ ACE_Asynch_Acceptor<Receiver> acceptor;
+
+ int rc = -1;
+ int i;
+ char c;
+
+ if (host == 0) // Acceptor
+ {
+ // Simplify, initial read with zero size
+ if (acceptor.open (ACE_INET_Addr (port),0,1) == 0)
+ rc = 1;
+ }
+ else
+ {
+ for (i = 0; i < senders; ++i)
+ send_list[i] = new Sender;
+
+ for (i = 0; i < senders; ++i)
+ if (send_list[i]->open (host, port) == 0)
+ rc++;
+ }
+
+ if (rc > 0)
+ {
+ cout << "Press any key to stop=>" << flush;
+ cin.clear ();
+ cin >> c;
+ }
+
+ ACE_Proactor::end_event_loop ();
+
+ if (host != 0) // we are sender
+ {
+ for (i = 0; i < senders; ++i)
+ send_list[i]->close ();
+ }
+
+
+ ACE_Thread_Manager *tm =
+ ACE_Thread_Manager::instance();
+
+ tm->wait_task (&task1);
+
+ cout << "\nNumber of Receivers objects="
+ << Receiver::get_number_sessions ()
+ << flush;
+
+ for (i = 0; i < senders; ++i)
+ {
+ delete (send_list[i]);
+ send_list[i] = 0;
+ }
+
+ return 0;
+}
+
+static int
+disable_signal (int sigmin, int sigmax)
+{
+#ifndef ACE_WIN32
+
+ sigset_t signal_set;
+ if (sigemptyset (&signal_set) == - 1)
+ ACE_ERROR ((LM_ERROR,
+ "Error:(%P | %t):%p\n",
+ "sigemptyset failed"));
+
+ for (int i = sigmin; i <= sigmax; i++)
+ sigaddset (&signal_set, i);
+
+ // Put the <signal_set>.
+ if (ACE_OS::pthread_sigmask (SIG_BLOCK, &signal_set, 0) != 0)
+ ACE_ERROR ((LM_ERROR,
+ "Error:(%P | %t):%p\n",
+ "pthread_sigmask failed"));
+#endif /* ACE_WIN32 */
+
+ return 1;
+}
+
+// Get the <signal_set> back from the OS.
+
+#if 0
+static int
+print_sigmask (void)
+{
+#ifndef ACE_WIN32
+ sigset_t mask;
+ int member = 0;
+
+ COUT ("\n=============Signal Mask==========")
+
+ if (ACE_OS::pthread_sigmask (SIG_SETMASK, 0, & mask) != 0)
+ ACE_ERROR ((LM_ERROR,
+ "Error:(%P | %t):%p\n",
+ "ACE_OS::pthread_sigmask failed"));
+ else
+ for (int i = 1; i < 1000; i++)
+ {
+ member = sigismember (&mask,i);
+
+ COUT ("\nSig ")
+ COUT (i)
+ COUT (" is ")
+ COUT (member)
+
+ if (member == -1)
+ break;
+ }
+
+#endif /* ACE_WIN32 */
+ return 0;
+}
+#endif /* 0 */
+
+#endif /* ACE_WIN32 && !ACE_HAS_WINCE || ACE_HAS_AIO_CALLS*/
diff --git a/ACE/examples/Reactor/Proactor/test_timeout.cpp b/ACE/examples/Reactor/Proactor/test_timeout.cpp
new file mode 100644
index 00000000000..39351717db9
--- /dev/null
+++ b/ACE/examples/Reactor/Proactor/test_timeout.cpp
@@ -0,0 +1,130 @@
+// $Id: test_timeout.cpp
+
+// ============================================================================
+//
+// = LIBRARY
+// examples
+//
+// = FILENAME
+// test_timeout.cpp
+//
+// = DESCRIPTION
+//
+// This example application shows how to write event loops that
+// handle events for some fixed amount of time. Note that any
+// thread in the Proactor thread pool can call back the handler. On
+// POSIX4 systems, this test works only with POSIX_SIG_Proactor,
+// which can work with multiple threads.
+//
+// = AUTHOR
+// Irfan Pyarali and Alexander Babu Arulanthu
+//
+// ============================================================================
+
+#include "ace/Proactor.h"
+#include "ace/Task.h"
+#include "ace/Atomic_Op.h"
+#include "ace/OS_NS_sys_time.h"
+#include "ace/OS_NS_unistd.h"
+#include "ace/OS_main.h"
+
+ACE_RCSID(Proactor, test_timeout, "$Id$")
+
+#if ((defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)) || \
+ (defined (ACE_HAS_AIO_CALLS)) && !defined (ACE_POSIX_AIOCB_PROACTOR))
+ // This only works on Win32 platforms and on Unix platforms supporting
+ // POSIX aio calls.
+
+class Timeout_Handler : public ACE_Handler
+{
+ // = TITLE
+ // Generic timeout handler.
+public:
+ Timeout_Handler (void)
+ : start_time_ (ACE_OS::gettimeofday ())
+ {
+ }
+
+ virtual void handle_time_out (const ACE_Time_Value &tv,
+ const void *arg)
+ {
+ // Print out when timeouts occur.
+ ACE_DEBUG ((LM_DEBUG, "(%t) %d timeout occurred for %s @ %d.\n",
+ ++count_,
+ (char *) arg,
+ (tv - this->start_time_).sec ()));
+
+ // Sleep for a while
+ ACE_OS::sleep (4);
+ }
+
+private:
+ ACE_Atomic_Op <ACE_SYNCH_MUTEX, int> count_;
+ // Number of the timer event.
+
+ ACE_Time_Value start_time_;
+ // Starting time of the test.
+};
+
+class Worker : public ACE_Task <ACE_NULL_SYNCH>
+{
+public:
+ int svc (void)
+ {
+ // Handle events for 13 seconds.
+ ACE_Time_Value run_time (13);
+
+ ACE_DEBUG ((LM_DEBUG, "(%t):Starting svc routine\n"));
+
+ if (ACE_Proactor::run_event_loop(run_time) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "(%t):%p.\n", "Worker::svc"), -1);
+
+ ACE_DEBUG ((LM_DEBUG, "(%t) work complete\n"));
+
+ return 0;
+ }
+};
+
+int
+ACE_TMAIN (int, ACE_TCHAR *[])
+{
+ Timeout_Handler handler;
+
+ // Register a 2 second timer.
+ ACE_Time_Value foo_tv (2);
+ if (ACE_Proactor::instance ()->schedule_timer (handler,
+ (void *) "Foo",
+ ACE_Time_Value::zero,
+ foo_tv) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "schedule_timer"), -1);
+
+ // Register a 3 second timer.
+ ACE_Time_Value bar_tv (3);
+ if (ACE_Proactor::instance ()->schedule_timer (handler,
+ (void *) "Bar",
+ ACE_Time_Value::zero,
+ bar_tv) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "schedule_timer"), -1);
+
+ Worker worker;
+
+ if (worker.activate (THR_NEW_LWP, 10) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "%p.\n", "main"), -1);
+
+ ACE_Thread_Manager::instance ()->wait ();
+
+ return 0;
+}
+
+#else /* ACE_WIN32 && !ACE_HAS_WINCE || ACE_HAS_AIO_CALLS && !ACE_POSIX_AIOCB_PROACTOR*/
+
+int
+main (int, char *[])
+{
+ ACE_DEBUG ((LM_DEBUG,
+ "This example is multithreaded version of test_timeout_st.cpp\n"
+ "This doesnt work on this platform !!!\n"));
+ return 1;
+}
+
+#endif /* ACE_WIN32 && !ACE_HAS_WINCE || ACE_HAS_AIO_CALLS && !ACE_POSIX_AIOCB_PROACTOR*/
diff --git a/ACE/examples/Reactor/Proactor/test_timeout_st.cpp b/ACE/examples/Reactor/Proactor/test_timeout_st.cpp
new file mode 100644
index 00000000000..ae44c2ba1f4
--- /dev/null
+++ b/ACE/examples/Reactor/Proactor/test_timeout_st.cpp
@@ -0,0 +1,99 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// examples
+//
+// = FILENAME
+// test_timeout_st.cpp
+//
+// = DESCRIPTION
+//
+// This example application shows how to write event loops that
+// handle events for some fixed amount of time. This is the single
+// threaded version of the test_timeout.cpp application.
+//
+// = AUTHOR
+// Irfan Pyarali and Alexander Babu Arulanthu
+//
+// ============================================================================
+
+#include "ace/Proactor.h"
+#include "ace/OS_main.h"
+
+ACE_RCSID(Proactor, test_timeout, "$Id$")
+
+#if ((defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)) || (defined (ACE_HAS_AIO_CALLS)))
+// This only works on Win32 platforms and on Unix platforms supporting
+// POSIX aio calls.
+
+class Timeout_Handler : public ACE_Handler
+{
+ // = TITLE
+ // Generic timeout handler.
+
+public:
+ Timeout_Handler (void)
+ : count_ (0),
+ start_time_ (ACE_OS::gettimeofday ())
+ {
+ }
+
+ virtual void handle_time_out (const ACE_Time_Value &tv,
+ const void *arg)
+ {
+ // Print out when timeouts occur.
+ ACE_DEBUG ((LM_DEBUG, "(%t) %d timeout occurred for %s @ %d.\n",
+ ++count_,
+ (char *) arg,
+ (tv - this->start_time_).sec ()));
+ }
+
+private:
+ int count_;
+ // Sequence number for the timeouts.
+
+ ACE_Time_Value start_time_;
+ // Starting time of the test.
+};
+
+
+int
+ACE_TMAIN (int, ACE_TCHAR *[])
+{
+ Timeout_Handler handler;
+
+ // Register a 2 second timer.
+ ACE_Time_Value foo_tv (2);
+ if (ACE_Proactor::instance ()->schedule_timer (handler,
+ (void *) "Foo",
+ ACE_Time_Value::zero,
+ foo_tv) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "schedule_timer"), -1);
+
+ // Register a 3 second timer.
+ ACE_Time_Value bar_tv (3);
+ if (ACE_Proactor::instance ()->schedule_timer (handler,
+ (void *) "Bar",
+ ACE_Time_Value::zero,
+ bar_tv) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "schedule_timer"), -1);
+
+ // Handle events for 13 seconds.
+ ACE_Time_Value run_time (13);
+
+ ACE_DEBUG ((LM_DEBUG, "Starting event loop\n"));
+
+ // Run the event loop.
+ if (ACE_Proactor::run_event_loop(run_time) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "(%t):%p.\n", "Worker::svc"),
+ 1);
+
+ ACE_DEBUG ((LM_DEBUG, "Ending event loop\n"));
+
+ return 0;
+}
+
+#endif /* ACE_WIN32 && !ACE_HAS_WINCE || ACE_HAS_AIO_CALLS*/
diff --git a/ACE/examples/Reactor/Proactor/test_udp_proactor.cpp b/ACE/examples/Reactor/Proactor/test_udp_proactor.cpp
new file mode 100644
index 00000000000..49d834a2884
--- /dev/null
+++ b/ACE/examples/Reactor/Proactor/test_udp_proactor.cpp
@@ -0,0 +1,432 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// examples
+//
+// = FILENAME
+// test_udp_proactor.cpp
+//
+// = DESCRIPTION
+// This program illustrates how the <ACE_Proactor> can be used to
+// implement an application that does asynchronous operations using
+// datagrams.
+//
+// = AUTHOR
+// Irfan Pyarali <irfan@cs.wustl.edu> and
+// Roger Tragin <r.tragin@computer.org>
+//
+// ============================================================================
+
+#include "ace/OS_NS_string.h"
+#include "ace/OS_main.h"
+#include "ace/Proactor.h"
+#include "ace/Asynch_IO.h"
+#include "ace/INET_Addr.h"
+#include "ace/SOCK_Dgram.h"
+#include "ace/Message_Block.h"
+#include "ace/Get_Opt.h"
+#include "ace/Log_Msg.h"
+
+ACE_RCSID(Proactor, test_udp_proactor, "test_proactor.cpp,v 1.29 2001/02/02 23:41:16 shuston Exp")
+
+#if defined (ACE_WIN32) && !defined (ACE_HAS_WINCE) || defined (ACE_HAS_AIO_CALLS)
+ // This only works on Win32 platforms.
+
+// Host that we're connecting to.
+static ACE_TCHAR *host = 0;
+
+// Port that we're receiving connections on.
+static u_short port = ACE_DEFAULT_SERVER_PORT;
+
+// Keep track of when we're done.
+static int done = 0;
+
+class Receiver : public ACE_Service_Handler
+{
+ // = TITLE
+ // This class will receive data from
+ // the network connection and dump it to a file.
+public:
+ // = Initialization and termination.
+ Receiver (void);
+ ~Receiver (void);
+
+ int open_addr (const ACE_INET_Addr &localAddr);
+
+protected:
+ // These methods are called by the framework
+
+ /// This method will be called when an asynchronous read completes on
+ /// a UDP socket.
+ virtual void handle_read_dgram (const ACE_Asynch_Read_Dgram::Result &result);
+
+private:
+ ACE_SOCK_Dgram sock_dgram_;
+
+ ACE_Asynch_Read_Dgram rd_;
+ // rd (read dgram): for reading from a UDP socket.
+ const char* completion_key_;
+ const char* act_;
+};
+
+Receiver::Receiver (void)
+ : completion_key_ ("Receiver Completion Key"),
+ act_ ("Receiver ACT")
+{
+}
+
+Receiver::~Receiver (void)
+{
+ sock_dgram_.close ();
+}
+
+int
+Receiver::open_addr (const ACE_INET_Addr &localAddr)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ "%N:%l:Receiver::open_addr called\n"));
+
+ // Create a local UDP socket to receive datagrams.
+ if (this->sock_dgram_.open (localAddr) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "%p\n",
+ "ACE_SOCK_Dgram::open"), -1);
+
+ // Initialize the asynchronous read.
+ if (this->rd_.open (*this,
+ this->sock_dgram_.get_handle (),
+ this->completion_key_,
+ ACE_Proactor::instance ()) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "%p\n",
+ "ACE_Asynch_Read_Dgram::open"), -1);
+
+ // Create a buffer to read into. We are using scatter/gather to
+ // read the message header and message body into 2 buffers
+
+ // create a message block to read the message header
+ ACE_Message_Block* msg = 0;
+ ACE_NEW_RETURN (msg, ACE_Message_Block (1024), -1);
+
+ // the next line sets the size of the header, even though we
+ // allocated a the message block of 1k, by setting the size to 20
+ // bytes then the first 20 bytes of the reveived datagram will be
+ // put into this message block.
+ msg->size (20); // size of header to read is 20 bytes
+
+ // create a message block to read the message body
+ ACE_Message_Block* body = 0;
+ ACE_NEW_RETURN (body, ACE_Message_Block (1024), -1);
+ // The message body will not exceed 1024 bytes, at least not in this test.
+
+ // set body as the cont of msg. This associates the 2 message
+ // blocks so that a read will fill the first block (which is the
+ // header) up to size (), and use the cont () block for the rest of
+ // the data. You can chain up to IOV_MAX message block using this
+ // method.
+ msg->cont (body);
+
+ // ok lets do the asynch read
+ size_t number_of_bytes_recvd = 0;
+
+ int res = rd_.recv (msg,
+ number_of_bytes_recvd,
+ 0,
+ PF_INET,
+ this->act_);
+ switch (res)
+ {
+ case 0:
+ // this is a good error. The proactor will call our handler when the
+ // read has completed.
+ break;
+ case 1:
+ // actually read something, we will handle it in the handler callback
+ ACE_DEBUG ((LM_DEBUG, "********************\n"));
+ ACE_DEBUG ((LM_DEBUG,
+ "%s = %d\n",
+ "bytes recieved immediately",
+ number_of_bytes_recvd));
+ ACE_DEBUG ((LM_DEBUG, "********************\n"));
+ res = 0;
+ break;
+ case -1:
+ // Something else went wrong.
+ ACE_ERROR ((LM_ERROR,
+ "%p\n",
+ "ACE_Asynch_Read_Dgram::recv"));
+ // the handler will not get called in this case so lets clean up our msg
+ msg->release ();
+ break;
+ default:
+ // Something undocumented really went wrong.
+ ACE_ERROR ((LM_ERROR,
+ "%p\n",
+ "ACE_Asynch_Read_Dgram::recv"));
+ msg->release ();
+ break;
+ }
+
+ return res;
+}
+
+void
+Receiver::handle_read_dgram (const ACE_Asynch_Read_Dgram::Result &result)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ "handle_read_dgram called\n"));
+
+ ACE_DEBUG ((LM_DEBUG, "********************\n"));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "bytes_to_read", result.bytes_to_read ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "handle", result.handle ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "bytes_transfered", result.bytes_transferred ()));
+ ACE_INET_Addr peerAddr;
+ result.remote_address (peerAddr);
+ ACE_DEBUG ((LM_DEBUG, "%s = %s:%d\n", "peer_address", peerAddr.get_host_addr (), peerAddr.get_port_number ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "flags", result.flags ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %s\n", "act", result.act ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "success", result.success ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %s\n", "completion_key", result.completion_key ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "error", result.error ()));
+ ACE_DEBUG ((LM_DEBUG, "********************\n"));
+
+ if (result.success () && result.bytes_transferred () != 0)
+ {
+ // loop through our message block and print out the contents
+ for (const ACE_Message_Block* msg = result.message_block (); msg != 0; msg = msg->cont ())
+ { // use msg->length () to get the number of bytes written to the message
+ // block.
+ ACE_DEBUG ((LM_DEBUG, "Buf=[size=<%d>", msg->length ()));
+ for (u_long i = 0; i < msg->length (); ++i)
+ ACE_DEBUG ((LM_DEBUG,
+ "%c", (msg->rd_ptr ())[i]));
+ ACE_DEBUG ((LM_DEBUG, "]\n"));
+ }
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ "Receiver completed\n"));
+
+ // No need for this message block anymore.
+ result.message_block ()->release ();
+
+ // Note that we are done with the test.
+ done++;
+}
+
+class Sender : public ACE_Handler
+{
+ // = TITLE
+ // The class will be created by <main>.
+public:
+ Sender (void);
+ ~Sender (void);
+ int open (const ACE_TCHAR *host, u_short port);
+
+protected:
+ // These methods are called by the freamwork
+
+ virtual void handle_write_dgram (const ACE_Asynch_Write_Dgram::Result &result);
+ // This is called when asynchronous writes from the dgram socket
+ // complete
+
+private:
+
+ ACE_SOCK_Dgram sock_dgram_;
+ // Network I/O handle
+
+ ACE_Asynch_Write_Dgram wd_;
+ // wd (write dgram): for writing to the socket
+
+ const char* completion_key_;
+ const char* act_;
+};
+
+Sender::Sender (void)
+ : completion_key_ ("Sender completion key"),
+ act_ ("Sender ACT")
+{
+}
+
+Sender::~Sender (void)
+{
+ this->sock_dgram_.close ();
+}
+
+int
+Sender::open (const ACE_TCHAR *host,
+ u_short port)
+{
+ // Initialize stuff
+
+ if (this->sock_dgram_.open (ACE_INET_Addr::sap_any) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "%p\n",
+ "ACE_SOCK_Dgram::open"), -1);
+
+ // Initialize the asynchronous read.
+ if (this->wd_.open (*this,
+ this->sock_dgram_.get_handle (),
+ this->completion_key_,
+ ACE_Proactor::instance ()) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "%p\n",
+ "ACE_Asynch_Write_Dgram::open"), -1);
+
+ // We are using scatter/gather to send the message header and
+ // message body using 2 buffers
+
+ // create a message block for the message header
+ ACE_Message_Block* msg = 0;
+ ACE_NEW_RETURN (msg, ACE_Message_Block (100), -1);
+ const char raw_msg [] = "To be or not to be.";
+ // Copy buf into the Message_Block and update the wr_ptr ().
+ msg->copy (raw_msg, ACE_OS::strlen (raw_msg) + 1);
+
+ // create a message block for the message body
+ ACE_Message_Block* body = 0;
+ ACE_NEW_RETURN (body, ACE_Message_Block (100), -1);
+ ACE_OS::memset (body->wr_ptr (), 'X', 100);
+ body->wr_ptr (100); // always remember to update the wr_ptr ()
+
+ // set body as the cont of msg. This associates the 2 message blocks so
+ // that a send will send the first block (which is the header) up to
+ // length (), and use the cont () to get the next block to send. You can
+ // chain up to IOV_MAX message block using this method.
+ msg->cont (body);
+
+ // do the asynch send
+ size_t number_of_bytes_sent = 0;
+ ACE_INET_Addr serverAddr (port, host);
+ int res = this->wd_.send (msg, number_of_bytes_sent, 0, serverAddr, this->act_);
+
+ switch (res)
+ {
+ case 0:
+ // this is a good error. The proactor will call our handler when the
+ // send has completed.
+ break;
+ case 1:
+ // actually sent something, we will handle it in the handler callback
+ ACE_DEBUG ((LM_DEBUG, "********************\n"));
+ ACE_DEBUG ((LM_DEBUG,
+ "%s = %d\n",
+ "bytes sent immediately",
+ number_of_bytes_sent));
+ ACE_DEBUG ((LM_DEBUG, "********************\n"));
+ res = 0;
+ break;
+ case -1:
+ // Something else went wrong.
+ ACE_ERROR ((LM_ERROR,
+ "%p\n",
+ "ACE_Asynch_Write_Dgram::recv"));
+ // the handler will not get called in this case so lets clean up our msg
+ msg->release ();
+ break;
+ default:
+ // Something undocumented really went wrong.
+ ACE_ERROR ((LM_ERROR,
+ "%p\n",
+ "ACE_Asynch_Write_Dgram::recv"));
+ msg->release ();
+ break;
+ }
+ return res;
+}
+
+void
+Sender::handle_write_dgram (const ACE_Asynch_Write_Dgram::Result &result)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ "handle_write_dgram called\n"));
+
+ ACE_DEBUG ((LM_DEBUG, "********************\n"));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "bytes_to_write", result.bytes_to_write ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "handle", result.handle ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "bytes_transfered", result.bytes_transferred ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "flags", result.flags ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %s\n", "act", result.act ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "success", result.success ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %s\n", "completion_key", result.completion_key ()));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "error", result.error ()));
+ ACE_DEBUG ((LM_DEBUG, "********************\n"));
+
+
+ ACE_DEBUG ((LM_DEBUG,
+ "Sender completed\n"));
+
+ // No need for this message block anymore.
+ result.message_block ()->release ();
+
+ // Note that we are done with the test.
+ done++;
+}
+
+static int
+parse_args (int argc, ACE_TCHAR *argv[])
+{
+ ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("h:p:"));
+ int c;
+
+ while ((c = get_opt ()) != EOF)
+ switch (c)
+ {
+ case 'h':
+ host = get_opt.opt_arg ();
+ break;
+ case 'p':
+ port = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ default:
+ ACE_ERROR_RETURN ((LM_ERROR, "%p.\n",
+ "usage :\n"
+ "-h <host>\n"), -1);
+ }
+
+ return 0;
+}
+
+int
+ACE_TMAIN (int argc, ACE_TCHAR *argv[])
+{
+ if (parse_args (argc, argv) == -1)
+ return -1;
+
+ Sender sender;
+
+ Receiver receiver;
+
+ // If passive side
+ if (host == 0)
+ {
+ if (receiver.open_addr (ACE_INET_Addr (port)) == -1)
+ return -1;
+ }
+ // If active side
+ else if (sender.open (host, port) == -1)
+ return -1;
+
+ for (int success = 1;
+ success > 0 && !done;
+ )
+ // Dispatch events via Proactor singleton.
+ success = ACE_Proactor::instance ()->handle_events ();
+
+ return 0;
+}
+
+#else /* ACE_WIN32 && !ACE_HAS_WINCE || ACE_HAS_AIO_CALLS*/
+
+int
+ACE_TMAIN (int, ACE_TCHAR *[])
+{
+ ACE_DEBUG ((LM_DEBUG,
+ "This example does not work on this platform.\n"));
+ return 1;
+}
+
+#endif /* ACE_WIN32 && !ACE_HAS_WINCE || ACE_HAS_AIO_CALLS*/
+
diff --git a/ACE/examples/Reactor/README b/ACE/examples/Reactor/README
new file mode 100644
index 00000000000..fefaeeaf317
--- /dev/null
+++ b/ACE/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/ACE/examples/Reactor/TP_Reactor/AcceptHandler.cpp b/ACE/examples/Reactor/TP_Reactor/AcceptHandler.cpp
new file mode 100644
index 00000000000..7ae34d2b2b4
--- /dev/null
+++ b/ACE/examples/Reactor/TP_Reactor/AcceptHandler.cpp
@@ -0,0 +1,106 @@
+/*
+ * $Id$
+ *
+ * ACE reactor demonstration
+ *
+ * Date: 26-Jan-2006
+ */
+
+#include <ace/Auto_Ptr.h>
+#include <ace/INET_Addr.h>
+
+#include "common.h"
+#include "AcceptHandler.h"
+#include "ReadHandler.h"
+
+AcceptHandler:: AcceptHandler(ACE_Reactor *reactor) :
+ ACE_Event_Handler(),
+ mReactor(reactor == 0 ? ACE_Reactor::instance() : reactor),
+ mAcceptor() {
+ ACE_TRACE("AcceptHandler:: AcceptHandler(ACE_Reactor *)");
+}
+
+AcceptHandler::~AcceptHandler() {
+ ACE_TRACE("AcceptHandler::~AcceptHandler()");
+}
+
+int AcceptHandler::open(void) {
+ ACE_TRACE("AcceptHandler::open(void)");
+
+ // create the local address used for the service (PORT is from common.h)
+ ACE_INET_Addr addr(PORT);
+
+ // open a port using the acceptor; reuse the address later
+ if (mAcceptor.open(addr, 1) == -1)
+ ACE_ERROR_RETURN((LM_ERROR, ACE_TEXT("%N:%l: Failed to open ")
+ ACE_TEXT ("listening socket. (errno = %i: %m)\n"), errno), -1);
+
+ // register the handler with the reactor
+ if (mReactor->register_handler(this,
+ ACE_Event_Handler::ACCEPT_MASK) == -1) {
+ ACE_ERROR((LM_ERROR, ACE_TEXT("%N:%l: Failed to register accept ")
+ ACE_TEXT ("handler. (errno = %i: %m)\n"), errno));
+
+ // don't leave the acceptor open
+ if (mAcceptor.close() == -1)
+ ACE_ERROR((LM_ERROR, ACE_TEXT("%N:%l: Failed to close the socket ")
+ ACE_TEXT ("after previous error. (errno = %i: %m)\n"),
+ errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+ACE_HANDLE AcceptHandler::get_handle(void) const {
+ ACE_TRACE("AcceptHandler::get_handle(void)");
+ return mAcceptor.get_handle();
+}
+
+int AcceptHandler::handle_input(ACE_HANDLE) {
+ ACE_TRACE("AcceptHandler::handle_input(ACE_HANDLE)");
+
+ ACE_INET_Addr clientAddr;
+
+ // create a new ReadHandler
+ ReadHandler *reader = 0;
+ ACE_NEW_NORETURN (reader, ReadHandler());
+ if (reader == 0)
+ ACE_ERROR_RETURN((LM_ERROR, ACE_TEXT("%N:%l: Failed to allocate ")
+ ACE_TEXT ("reader. (errno = %i: %m)\n"), errno), -1);
+
+ // put reader in an auto pointer so we can use ACE_ERROR_RETURN safely
+ auto_ptr<ReadHandler> pReader(reader);
+
+ // accept the connection using the reader's stream
+ if (mAcceptor.accept(reader->getStream(), &clientAddr) == -1)
+ ACE_ERROR_RETURN((LM_ERROR, ACE_TEXT("%N:%l: Failed to accept ")
+ ACE_TEXT ("client connection. (errno = %i: %m)\n"), errno), -1);
+
+ // register the reader with the reactor
+ if (mReactor->register_handler(reader,
+ ACE_Event_Handler::READ_MASK) == -1)
+ ACE_ERROR_RETURN((LM_ERROR, ACE_TEXT("%N:%l: Failed to register ")
+ ACE_TEXT ("read handler. (errno = %i: %m)\n"), errno), -1);
+
+ // from now on the read handler takes care of itself
+ pReader.release();
+
+ return 0; // keep going
+}
+
+int AcceptHandler::handle_close(ACE_HANDLE, ACE_Reactor_Mask) {
+ ACE_TRACE("AcceptHandler::handle_close(ACE_HANDLE, ACE_Reactor_Mask)");
+
+ // close the listening socket
+ if (mAcceptor.close() == -1)
+ ACE_ERROR((LM_ERROR, ACE_TEXT("%N:%l: Failed to close the ")
+ ACE_TEXT ("socket. (errno = %i: %m)\n"), errno));
+
+ // no need to distinguish between error during close and normal close
+ // since ACE does not evaluate the return value of handle_close()
+
+ delete this;
+ return 0;
+}
+
diff --git a/ACE/examples/Reactor/TP_Reactor/AcceptHandler.h b/ACE/examples/Reactor/TP_Reactor/AcceptHandler.h
new file mode 100644
index 00000000000..036f7a36f5a
--- /dev/null
+++ b/ACE/examples/Reactor/TP_Reactor/AcceptHandler.h
@@ -0,0 +1,75 @@
+/*
+ * ACE reactor demonstration
+ *
+ * $Id$
+ * Date: 26-Jan-2006
+ */
+
+#ifndef __ACCEPTHANDLER_H__
+#define __ACCEPTHANDLER_H__
+
+#include <ace/Event_Handler.h>
+#include <ace/Reactor.h>
+#include <ace/SOCK_Acceptor.h>
+
+/**
+ * This accept handler is based on the provided solution from the ACE course.
+ */
+class AcceptHandler : public ACE_Event_Handler {
+
+ private:
+
+ /**
+ * The reactor to which the accept handler belongs.
+ */
+ ACE_Reactor *mReactor;
+
+ /**
+ * The socket used for incoming conections.
+ */
+ ACE_SOCK_Acceptor mAcceptor;
+
+ public:
+
+ /**
+ * @param reactor The reactor which will use this accept handler.
+ */
+ AcceptHandler(ACE_Reactor *reactor = 0);
+
+ /**
+ * The destructor exists for tracing purposes.
+ */
+ virtual ~AcceptHandler();
+
+ /**
+ * Open the listening socket and register the handler with the reactor.
+ *
+ * @return 0 on success, -1 on failure
+ */
+ int open(void);
+
+ /**
+ * @name Overridden methods from the ACE_Event_Handler
+ */
+ // @{
+
+ /**
+ * Provides the handle of mAcceptor.
+ */
+ virtual ACE_HANDLE get_handle(void) const;
+
+ /**
+ * Create a read handler for the new connection and register that
+ * handler with the reactor.
+ */
+ virtual int handle_input(ACE_HANDLE = ACE_INVALID_HANDLE);
+
+ /**
+ * Close the listening socket.
+ */
+ virtual int handle_close(ACE_HANDLE, ACE_Reactor_Mask);
+ // @}
+};
+
+#endif /* __ACCEPTHANDLER_H__ */
+
diff --git a/ACE/examples/Reactor/TP_Reactor/Makefile.am b/ACE/examples/Reactor/TP_Reactor/Makefile.am
new file mode 100644
index 00000000000..5407cbb10e1
--- /dev/null
+++ b/ACE/examples/Reactor/TP_Reactor/Makefile.am
@@ -0,0 +1,53 @@
+## Process this file with automake to create Makefile.in
+##
+## $Id$
+##
+## This file was generated by MPC. Any changes made directly to
+## this file will be lost the next time it is generated.
+##
+## MPC Command:
+## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu
+
+ACE_BUILDDIR = $(top_builddir)
+ACE_ROOT = $(top_srcdir)
+
+## Makefile.TP_Reactor_Client.am
+noinst_PROGRAMS = client
+
+client_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+client_SOURCES = \
+ client.cpp \
+ AcceptHandler.h \
+ ReadHandler.h \
+ common.h
+
+client_LDADD = \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.TP_Reactor_Server.am
+noinst_PROGRAMS += server
+
+server_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+server_SOURCES = \
+ AcceptHandler.cpp \
+ ReadHandler.cpp \
+ server.cpp \
+ AcceptHandler.h \
+ ReadHandler.h
+
+server_LDADD = \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Clean up template repositories, etc.
+clean-local:
+ -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.*
+ -rm -f gcctemp.c gcctemp so_locations *.ics
+ -rm -rf cxx_repository ptrepository ti_files
+ -rm -rf templateregistry ir.out
+ -rm -rf ptrepository SunWS_cache Templates.DB
diff --git a/ACE/examples/Reactor/TP_Reactor/README b/ACE/examples/Reactor/TP_Reactor/README
new file mode 100644
index 00000000000..32fbc15aca9
--- /dev/null
+++ b/ACE/examples/Reactor/TP_Reactor/README
@@ -0,0 +1,86 @@
+ACE reactor demonstration
+=========================
+
+Martin Kolleck
+Tino Riethmuller
+
+
+
+1. Introduction
+
+This program demonstrates what we think is a bug in the ACE library. The
+affected component is the ACE_TP_Reactor. According to the documentation, the
+reactor ensures that only one of the handle_*() methods of an event handler is
+called at a time. Tino found this to be not true and I wrote this example
+program showing the behavior. I do not exclude the possibility that we are
+using the ACE library in an unintended/wrong way. So comments on the code as
+well as any other remarks are welcome.
+
+
+
+2. The program
+
+The program consists of a client and a server. The general implementation is
+taken from the example solution to exercise 4c of the ACE course. The client
+will send a request to the server. This request is interpreted to be the size
+of the following data. The server allocates the memory required to hold the
+client's data and then sends a confirmation to the client, that it may
+proceed. The the client sends the large data chunk and the server again
+confirms it.
+
+The client runs in a loop which can be configured to run indefinitely or a
+previously set amount of times. The configuration i done from the command
+line. To invoke the client type:
+
+ $ ./client size [count]
+
+<size> sets the size (in MiB) of the buffer sent to the server. Depending on
+the systems, values between 60 and 100 have been used for testing. <count>
+determines how often the buffer is sent. If left out, the clients send the
+buffer until interrupted.
+
+The server is started without arguments. Both programs will print a dot for
+each successful connection. I found this an easy and unintrusive way of showing
+progress whithout flooding the console too fast. This also makes it easier to
+see when an error has occurred.
+
+
+
+3. Building the program
+
+This example was created on a Linux box. You will need the environment
+variable ACE_ROOT set up to the location where ACE is installed. It might be
+possible, that the path where the ACE libraries are found, needs to be adjusted
+in the Makefile.
+
+To compile simply type 'make' on the command prompt.
+
+ $ make
+
+This will create two executable files. One for the server and one for the
+client. (named respectively)
+
+
+
+4. Running the program
+
+The error seems to be of statistical nature. Occurring only under certain
+conditions (which I am not sure of, what they are). I successfully produced
+the error on the four machines given below (architecture, ACE and compiler
+version). I tested the program with localhost connections, as well as over
+a real network connection and could always reproduce the error.
+
+To detect the error I introduced a member variable to the read event handler.
+This counter is initialized to zero in the constructor. When handle_input() of
+the event handler is called, the counter is increased and decreased, when
+handle_input() returns. Before increasing the counter, It is compared to zero
+(which it should alway be, if only one invocation to handle_input() is made
+at a time) and an error message is printed if it is not zero.
+
+To test for the error, I ran one instance of the server program and TWO
+instances of the client program. The sizes of the buffers were between 60 and
+100 MiB and no count was given (running until stopped) The three Linux boxes
+showed the error within one minute of starting both clients. For the Windows
+box I decreased the buffer size to 15 and 20 MiB (Windows does not seem to have
+very performant localhost connectivity) and it took about half an
+hour until the error occurred the first time.
diff --git a/ACE/examples/Reactor/TP_Reactor/ReadHandler.cpp b/ACE/examples/Reactor/TP_Reactor/ReadHandler.cpp
new file mode 100644
index 00000000000..06c6c953046
--- /dev/null
+++ b/ACE/examples/Reactor/TP_Reactor/ReadHandler.cpp
@@ -0,0 +1,151 @@
+/*
+ * ACE reactor demonstration
+ *
+ * $Id$
+ * Date: 26-Jan-2006
+ */
+
+#include <ace/streams.h>
+#include <ace/Time_Value.h>
+
+#include "common.h"
+#include "ReadHandler.h"
+
+/**
+ * This macro is used to increase the invocation counter by one when entering
+ * handle_input(). It also checks wether the counter is greater than zero
+ * indicating, that handle_input() has been called before.
+ */
+#define INVOCATION_ENTER() do { if (mInvocationCounter > 0) \
+ ACE_ERROR((LM_ERROR, ACE_TEXT("Multiple invocations detected.\n"))); \
+ mInvocationCounter++; } while (0)
+
+/**
+ * THis macro is the counter part to INVOCATION_ENTER(). It decreases the
+ * invocation counter and then returns the given value. This macro is
+ * here for convenience to decrease the invocation counter also when returning
+ * due to errors.
+ */
+#define INVOCATION_RETURN(retval) do { mInvocationCounter--; \
+ return retval; } while(0)
+
+ReadHandler::ReadHandler() : ACE_Event_Handler(), mStream(), mDataSize(0),
+ mData(0), mCallCounter(0), mInvocationCounter(0) {
+ ACE_TRACE(ACE_TEXT("ReadHandler::ReadHandler()"));
+}
+
+ReadHandler::~ReadHandler() {
+ ACE_TRACE(ACE_TEXT("ReadHandler::~ReadHandler()"));
+
+ if (mStream.close() == -1)
+ ACE_ERROR((LM_ERROR, ACE_TEXT("%N:%l: Failed to close socket. ")
+ ACE_TEXT ("(errno = %i: %m)\n"), errno));
+
+ delete[] mData;
+}
+
+ACE_SOCK_Stream &ReadHandler::getStream(void) {
+ ACE_TRACE(ACE_TEXT("ReadHandler::getStream(void)"));
+ return mStream;
+}
+
+ACE_HANDLE ReadHandler::get_handle(void) const {
+ ACE_TRACE(ACE_TEXT("ReadHandler::get_handle(void)"));
+ return mStream.get_handle();
+}
+
+int ReadHandler::handle_input(ACE_HANDLE) {
+ ACE_TRACE(ACE_TEXT("ReadHandler::handle_input(ACE_HANDLE)"));
+
+ INVOCATION_ENTER();
+
+ // the response sent to the client
+ char response = 0;
+
+ if (mCallCounter == 0) {
+
+ /*
+ * This is the first request from the client.
+ */
+
+ // increase the call counter so the next client request goes to else-if
+ mCallCounter++;
+
+ // get the desired size from the client
+ // Note: only use the sizeof and pointer to int on compatible
+ // platforms (i.e. little-endian/big-endian, data type size)
+ if (mStream.recv_n(&mDataSize, sizeof(mDataSize),
+ &connTimeout) != sizeof(mDataSize)) {
+ ACE_ERROR((LM_ERROR, ACE_TEXT("%N:%l: Failed to receive ")
+ ACE_TEXT ("request. (errno = %i: %m)\n"), errno));
+ INVOCATION_RETURN(-1);
+ }
+
+ // The verbose debug output is replaced with some unintrusive dots.
+ // This increases visibility of the desired effect.
+ // ACE_DEBUG((LM_DEBUG, ACE_TEXT("%@: Data size: %i\n"), this, mDataSize));
+ ACE_DEBUG((LM_DEBUG, ACE_TEXT(".")));
+
+ // check mDataSize for plausability then allocate memory
+ if (mDataSize > 0) {
+ mData = new (std::nothrow) char[mDataSize];
+ if (mData == 0)
+ ACE_DEBUG((LM_DEBUG, ACE_TEXT("%N:%l: Failed to allocate ")
+ ACE_TEXT ("data buffer.\n")));
+ else
+ response = 'K';
+ }
+
+ // send the response to the client (which is still 0, if the
+ // allocation did not succeed)
+ if (mStream.send_n(&response, sizeof(response), &connTimeout) != 1) {
+ ACE_ERROR((LM_ERROR, ACE_TEXT("%N:%l: Failed to send ")
+ ACE_TEXT ("response. (errno = %i: %m)\n"), errno));
+ INVOCATION_RETURN(-1);
+ }
+
+ if (response == 'K')
+ INVOCATION_RETURN(0); // get another request from the same client
+ else
+ INVOCATION_RETURN(-1); // the client will not send data if response != 'K'
+
+ } else if (mCallCounter == 1) {
+
+ /*
+ * This is the second request from the client.
+ */
+
+ // increase the call counter, this read handler should not be called
+ // again
+ mCallCounter++;
+
+ // receive the data from the client
+ if (mStream.recv_n(mData, mDataSize, &connTimeout) != mDataSize) {
+ ACE_ERROR((LM_ERROR, ACE_TEXT("%N:%l: Failed to receive data.")
+ ACE_TEXT ("(errno = %i: %m)\n"), errno));
+ INVOCATION_RETURN(-1);
+ }
+
+ response = 'K';
+
+ if (mStream.send_n(&response, 1, &connTimeout) != 1) {
+ ACE_ERROR((LM_ERROR, ACE_TEXT("%N:%l: Failed to send ")
+ ACE_TEXT ("confirmation. (errno = %i: %m)\n"), errno));
+ INVOCATION_RETURN(-1);
+ }
+
+ INVOCATION_RETURN(-1); // ask for removal, since client does not send any more data
+ }
+
+ // this is to find strange actions with the call counter
+ ACE_ERROR((LM_ERROR, ACE_TEXT("%N:%l: We should not get here.")));
+ INVOCATION_RETURN(-1);
+}
+
+int ReadHandler::handle_close(ACE_HANDLE, ACE_Reactor_Mask) {
+ ACE_TRACE("ReadHandler::handle_close(ACE_HANDLE, ACE_Reactor_Mask)");
+
+ delete this;
+ return 0;
+}
+
diff --git a/ACE/examples/Reactor/TP_Reactor/ReadHandler.h b/ACE/examples/Reactor/TP_Reactor/ReadHandler.h
new file mode 100644
index 00000000000..41d58b6008a
--- /dev/null
+++ b/ACE/examples/Reactor/TP_Reactor/ReadHandler.h
@@ -0,0 +1,92 @@
+/*
+ * ACE reactor demonstration
+ *
+ * $Id$
+ * Date: 26-Jan-2006
+ */
+
+#ifndef __READHANDLER_H__
+#define __READHANDLER_H__
+
+#include <ace/Event_Handler.h>
+#include <ace/SOCK_Stream.h>
+
+/**
+ * This read handler is created by the accept handler and handles all the data
+ * exchange between client and server. The client makes two requests to the
+ * server. The first asks the server to create a buffer which will hold the
+ * data sent in the second call.
+ */
+class ReadHandler : public ACE_Event_Handler {
+
+ private:
+
+ /**
+ * The stream socket used for data exchange.
+ */
+ ACE_SOCK_Stream mStream;
+
+ /**
+ * The size of the data array.
+ */
+ int mDataSize;
+
+ /**
+ * The array containing the client's data.
+ */
+ char *mData;
+
+ /**
+ * The call counter to distinguish between first and second call.
+ */
+ int mCallCounter;
+
+ /**
+ * Count the numer of invocations of handle_*(). According to the
+ * docs, there should be only one invocation at any given time.
+ */
+ int mInvocationCounter;
+
+ public:
+
+ /**
+ * Initialization.
+ */
+ ReadHandler(void);
+
+ /**
+ * Clean up data.
+ */
+ virtual ~ReadHandler();
+
+ /**
+ * Provide access to the internal stream socket.
+ */
+ ACE_SOCK_Stream &getStream(void);
+
+ /**
+ * @name Overridden methods from the ACE_Event_Handler
+ */
+ // @{
+
+ /**
+ * Provides the handle of mStream;
+ */
+ virtual ACE_HANDLE get_handle(void) const;
+
+ /**
+ * Handles the data excahnge between client and server. On the first
+ * invocation, mData is allocated to the requested size and on the
+ * second invocation, that buffer is filled with the client's data.
+ */
+ virtual int handle_input(ACE_HANDLE = ACE_INVALID_HANDLE);
+
+ /**
+ * Deletes this instance of the read handler.
+ */
+ virtual int handle_close(ACE_HANDLE, ACE_Reactor_Mask);
+ // @}
+};
+
+#endif /* __READHANDLER_H__ */
+
diff --git a/ACE/examples/Reactor/TP_Reactor/TP_Reactor.mpc b/ACE/examples/Reactor/TP_Reactor/TP_Reactor.mpc
new file mode 100644
index 00000000000..03d8de2e7aa
--- /dev/null
+++ b/ACE/examples/Reactor/TP_Reactor/TP_Reactor.mpc
@@ -0,0 +1,18 @@
+// -*- MPC -*-
+// $Id$
+
+project (*client) : aceexe {
+ exename = client
+ Source_Files {
+ client.cpp
+ }
+}
+
+project (*server) : aceexe {
+ exename = server
+ Source_Files {
+ server.cpp
+ AcceptHandler.cpp
+ ReadHandler.cpp
+ }
+}
diff --git a/ACE/examples/Reactor/TP_Reactor/client.cpp b/ACE/examples/Reactor/TP_Reactor/client.cpp
new file mode 100644
index 00000000000..509f2e9c457
--- /dev/null
+++ b/ACE/examples/Reactor/TP_Reactor/client.cpp
@@ -0,0 +1,141 @@
+/*
+ * ACE reactor demonstration
+ *
+ * $Id$
+ * Date: 26-Jan-2006
+ */
+
+#include <ace/Auto_Ptr.h>
+#include <ace/INET_Addr.h>
+#include <ace/Log_Msg.h>
+#include <ace/OS.h>
+#include <ace/SOCK_Acceptor.h>
+#include <ace/SOCK_Connector.h>
+#include <ace/SOCK_Stream.h>
+#include <ace/streams.h>
+
+#include "common.h"
+
+/**
+ * Print usage information for the client.
+ *
+ * @param arg The progams name (argv[0]).
+ */
+int printUsage(ACE_TCHAR *arg) {
+ cerr << "Usage: " << arg << " size [count]" << endl;
+ cerr << "\tSends <size> MiB to the server and optionally repeats that "
+ << "<count> times." << endl;
+ cerr << "\tAll arguments must be positive numbers. If no <count> is "
+ << "given, the\n\tclient runs until interrupted." << endl;
+ return -1;
+}
+
+int ACE_TMAIN(int argc, ACE_TCHAR **argv) {
+
+ // size and count for transmissions
+ int size = 0, count = -1;
+
+ // the server's answer is a single byte
+ char answer;
+
+ // parse the <size> argument
+ if ((argc < 2) || (((size = ACE_OS::strtol(argv[1], 0, 10)) < 1) ||
+ (errno == EINVAL)))
+ return printUsage(argv[0]);
+
+ // take size as the number of MiB and create appropriate buffer
+ size *= BASE;
+ char *someData = new (std::nothrow) char[size];
+
+ if (someData == 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%N:%l: Failed to allocate ")
+ ACE_TEXT ("data buffer.\n")), -1);
+
+ // put someData in an auto_ptr so it gets deleted automatically
+ auto_ptr<char> pSomeData(someData);
+
+ // parse the <count> argument if available
+ if ((argc == 3) && (((count = ACE_OS::strtol(argv[2], 0, 10)) < 1) ||
+ (errno == EINVAL)))
+ return printUsage(argv[0]);
+
+ // the server listens on localhost on default port (from common.h)
+ ACE_INET_Addr serverAddr(PORT, "localhost");
+
+ ACE_SOCK_Stream stream;
+ ACE_SOCK_Connector connector;
+
+ // -1 is running indefinitely
+ while ((count == -1) || (count-- != 0)) {
+
+ // some output, that we know something is happening
+ //ACE_DEBUG((LM_DEBUG, ACE_TEXT("%N:%l: Passes left: %i\n"), count));
+ ACE_DEBUG((LM_DEBUG, ACE_TEXT(".")));
+
+ // connect to the server and get the stream
+ if (connector.connect(stream, serverAddr) == -1) {
+ ACE_ERROR((LM_ERROR,
+ ACE_TEXT("%N:%l: Failed to connect to ")
+ ACE_TEXT ("server. (errno = %i: %m)\n"), errno));
+ break;
+ }
+
+ try {
+
+ // send the request to the server (number of MiB in the next call)
+ // Note: only use the sizeof and pointer to int on compatible
+ // platforms (i.e. little-endian/big-endian, data type size)
+ if (stream.send_n(&size, sizeof(size), &connTimeout) != sizeof(size)) {
+ ACE_ERROR((LM_ERROR, ACE_TEXT("%N:%l: Failed to send ")
+ ACE_TEXT ("request. (errno = %i: %m)\n"), errno));
+ throw(1);
+ }
+
+ // receive the answer
+ if (stream.recv_n(&answer, sizeof(answer), &connTimeout) != 1) {
+ ACE_ERROR((LM_ERROR, ACE_TEXT("%N: %l: Failed to receive ")
+ ACE_TEXT ("1st response. (errno = %i: %m)\n"), errno));
+ throw(1);
+ }
+
+ // server answer, 'K" indicates a positive answer
+ if (answer == 'K') {
+
+ // send a huge message to the server
+ if (stream.send_n(someData, size, &connTimeout) != size) {
+ ACE_ERROR((LM_ERROR, ACE_TEXT("%N:%l: Failed to send ")
+ ACE_TEXT ("someData. (errno = %i: %m)\n"), errno));
+ throw(1);
+ }
+
+ // get an answer
+ if (stream.recv_n(&answer, sizeof(answer), &connTimeout) != 1) {
+ ACE_ERROR((LM_ERROR, ACE_TEXT("%N: %l: Failed to receive ")
+ ACE_TEXT ("2nd response. (errno = %i: %m)\n"), errno));
+ throw(1);
+ }
+
+ // check the answer
+ if (answer != 'K') {
+ cout << "The server was unable to process the data."
+ << endl;
+ }
+ }
+ } catch (...) {
+ // ok we know an error occurred, we need to close the socket.
+ // The we'll try again.
+ }
+
+ // close the current stream
+ if (stream.close() == -1) {
+ ACE_ERROR((LM_ERROR, ACE_TEXT("%N:%l: Failed to close ")
+ ACE_TEXT ("socket. (errno = %i: %m)\n"), errno));
+ break;
+ }
+ } // while
+
+ cout << "Bye. Bye" << endl;
+ return 0;
+}
+
diff --git a/ACE/examples/Reactor/TP_Reactor/common.h b/ACE/examples/Reactor/TP_Reactor/common.h
new file mode 100644
index 00000000000..c9661027923
--- /dev/null
+++ b/ACE/examples/Reactor/TP_Reactor/common.h
@@ -0,0 +1,29 @@
+/*
+ * ACE reactor demonstration
+ *
+ * $Id$
+ * Date: 26-Jan-2006
+ */
+
+#ifndef __COMMON_H__
+#define __COMMON_H__
+
+#include <ace/Time_Value.h>
+
+/**
+ * The port number used by client and server.
+ */
+static const int PORT = 4711;
+
+/**
+ * The base size. 0x100000 = 1 MiB
+ */
+static const int BASE = 0x100000;
+
+/**
+ * The timeout value for connections. (30 seconds)
+ */
+static const ACE_Time_Value connTimeout(30);
+
+#endif /* __COMMON_H__ */
+
diff --git a/ACE/examples/Reactor/TP_Reactor/run_test.pl b/ACE/examples/Reactor/TP_Reactor/run_test.pl
new file mode 100644
index 00000000000..ac07295a735
--- /dev/null
+++ b/ACE/examples/Reactor/TP_Reactor/run_test.pl
@@ -0,0 +1,41 @@
+eval '(exit $?0)' && eval 'exec perl -S $0 ${1+"$@"}'
+ & eval 'exec perl -S $0 $argv:q'
+ if 0;
+
+# $Id$
+# -*- perl -*-
+
+use lib '../../../bin';
+use PerlACE::Run_Test;
+
+$status = 0;
+
+$SV = new PerlACE::Process ("server", "");
+$CL1 = new PerlACE::Process ("client", "80 100");
+$CL2 = new PerlACE::Process ("client", "80 100");
+$SV->Spawn ();
+
+sleep (1);
+
+$client1 = $CL1->Spawn ();
+
+if ($client1 != 0) {
+ print STDERR "ERROR: client 1 returned $client1\n";
+ $status = 1;
+}
+
+$client2 = $CL2->Spawn ();
+
+if ($client2 != 0) {
+ print STDERR "ERROR: client 2 returned $client2\n";
+ $status = 1;
+}
+
+$server = $SV->WaitKill (1000);
+
+if ($server != 0) {
+ print STDERR "ERROR: server returned $server\n";
+ $status = 1;
+}
+
+exit $status;
diff --git a/ACE/examples/Reactor/TP_Reactor/server.cpp b/ACE/examples/Reactor/TP_Reactor/server.cpp
new file mode 100644
index 00000000000..0c147818424
--- /dev/null
+++ b/ACE/examples/Reactor/TP_Reactor/server.cpp
@@ -0,0 +1,66 @@
+/*
+ * ACE reactor demonstration
+ *
+ * $Id$
+ * Date: 26-Jan-2006
+ */
+
+#include <ace/Event_Handler.h>
+#include <ace/Log_Msg.h>
+#include <ace/OS.h>
+#include <ace/Reactor.h>
+#include <ace/Signal.h>
+#include <ace/streams.h>
+#include <ace/Thread_Manager.h>
+#include <ace/TP_Reactor.h>
+
+#include "AcceptHandler.h"
+
+/**
+ * This is the function run by all threads in the thread pool.
+ *
+ * @param arg is expected to be of type (ACE_Reactor *)
+ */
+ACE_THR_FUNC_RETURN threadFunc(void *arg) {
+ ACE_TRACE("threadFunc(void *)");
+
+ ACE_Reactor *reactor = (ACE_Reactor *) arg;
+ reactor->run_reactor_event_loop();
+
+ return 0;
+}
+
+/**
+ * The main function sets up the TP reactor. The code is basically taken from
+ * the solution to exercise 4c of the ACE course.
+ */
+int ACE_TMAIN(int, ACE_TCHAR **) {
+
+ // create a reactor from a TP reactor
+ ACE_TP_Reactor tpReactor;
+ ACE_Reactor reactor(&tpReactor);
+
+ // create a new accept handler using that reactor
+ AcceptHandler *acceptHandler = 0;
+ ACE_NEW_NORETURN (acceptHandler, AcceptHandler(&reactor));
+ if (acceptHandler == 0)
+ ACE_ERROR_RETURN((LM_ERROR, ACE_TEXT("%N:%l: Failed to allocate ")
+ ACE_TEXT ("accept handler. (errno = %i: %m)\n"), errno), -1);
+
+ // open the accept handler
+ if (acceptHandler->open() == -1) {
+ delete acceptHandler;
+ ACE_ERROR_RETURN((LM_ERROR, ACE_TEXT("%N:%l: Failed to open accept ")
+ ACE_TEXT ("handler. Exiting.\n")), -1);
+ }
+
+ // spawn some threads which run the reactor event loop(s)
+ ACE_Thread_Manager::instance()->spawn_n(9, threadFunc, &reactor);
+
+ // let the thread manager wait for all threads
+ ACE_Thread_Manager::instance()->wait();
+
+ ACE_DEBUG((LM_DEBUG, ACE_TEXT("Bye. Bye.\n")));
+ return 0;
+}
+
diff --git a/ACE/examples/Reactor/WFMO_Reactor/APC.cpp b/ACE/examples/Reactor/WFMO_Reactor/APC.cpp
new file mode 100644
index 00000000000..bf42fd1edfa
--- /dev/null
+++ b/ACE/examples/Reactor/WFMO_Reactor/APC.cpp
@@ -0,0 +1,124 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// examples
+//
+// = FILENAME
+// APC.cpp
+//
+// = DESCRIPTION
+//
+// Tests the WFMO_Reactor's ability to handle regular APC
+// notifications.
+//
+// = AUTHOR
+//
+// Irfan Pyarali <irfan@cs.wustl.edu>
+//
+// ============================================================================
+
+#include "ace/OS_main.h"
+
+#if defined (ACE_WIN32)
+
+#include "ace/Reactor.h"
+#include "ace/Auto_Event.h"
+
+ACE_RCSID(WFMO_Reactor, APC, "$Id$")
+
+class Event_Handler : public ACE_Event_Handler
+{
+public:
+ int handle_signal (int signum,
+ siginfo_t * = 0,
+ ucontext_t * = 0);
+
+ int handle_timeout (const ACE_Time_Value &tv,
+ const void *arg = 0);
+
+ ACE_Auto_Event handle_;
+ int iterations_;
+};
+
+static Event_Handler *global_event_handler;
+
+static void WINAPI
+apc_callback (DWORD)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ "(%t) apc occured @ %T\n"));
+
+ global_event_handler->handle_.signal ();
+}
+
+void
+queue_apc (void)
+{
+ DWORD result = ::QueueUserAPC (reinterpret_cast<PAPCFUNC> (&apc_callback),
+ // pointer to APC function
+ ::GetCurrentThread (), // handle to the thread
+ 0); // argument for the APC function
+ if (result == FALSE)
+ ACE_OS::exit (-1);
+}
+
+int
+Event_Handler::handle_signal (int,
+ siginfo_t *,
+ ucontext_t *)
+{
+ --this->iterations_;
+
+ if (this->iterations_ == 0)
+ {
+ ACE_Reactor::instance ()->remove_handler (this->handle_.handle (),
+ ACE_Event_Handler::DONT_CALL);
+ ACE_Reactor::end_event_loop ();
+ }
+
+ return 0;
+}
+
+int
+Event_Handler::handle_timeout (const ACE_Time_Value &,
+ const void *)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ "(%t) timeout occured @ %T\n"));
+ queue_apc ();
+ return 0;
+}
+
+int
+ACE_TMAIN (int, ACE_TCHAR *[])
+{
+ Event_Handler event_handler;
+ event_handler.iterations_ = 5;
+ global_event_handler = &event_handler;
+
+ int result = ACE_Reactor::instance ()->register_handler (&event_handler,
+ event_handler.handle_.handle ());
+ ACE_ASSERT (result == 0);
+
+ ACE_Time_Value timeout (2);
+ result = ACE_Reactor::instance ()->schedule_timer (&event_handler,
+ 0,
+ timeout,
+ timeout);
+ ACE_ASSERT (result != -1);
+
+ ACE_Reactor::run_alertable_event_loop ();
+
+ ACE_Reactor::instance ()->cancel_timer(&event_handler);
+
+ return 0;
+}
+#else /* !ACE_WIN32 */
+int
+ACE_TMAIN (int, ACE_TCHAR *[])
+{
+ return 0;
+}
+#endif /* ACE_WIN32 */
diff --git a/ACE/examples/Reactor/WFMO_Reactor/Abandoned.cpp b/ACE/examples/Reactor/WFMO_Reactor/Abandoned.cpp
new file mode 100644
index 00000000000..c860fc2810c
--- /dev/null
+++ b/ACE/examples/Reactor/WFMO_Reactor/Abandoned.cpp
@@ -0,0 +1,141 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// examples
+//
+// = FILENAME
+// Abandoned.cpp
+//
+// = DESCRIPTION
+//
+// Tests the WFMO_Reactor's ability to handle abandoned mutexes.
+//
+// = AUTHOR
+//
+// Irfan Pyarali <irfan@cs.wustl.edu>
+//
+// ============================================================================
+
+#include "ace/OS_main.h"
+
+#if defined (ACE_WIN32)
+
+#include "ace/Reactor.h"
+#include "ace/Thread_Manager.h"
+#include "ace/Process_Mutex.h"
+#include "ace/Auto_Event.h"
+
+ACE_RCSID(WFMO_Reactor, Abandoned, "$Id$")
+
+class Event_Handler : public ACE_Event_Handler
+{
+public:
+ int handle_signal (int signum,
+ siginfo_t * = 0,
+ ucontext_t * = 0);
+
+ int handle_timeout (const ACE_Time_Value &tv,
+ const void *arg = 0);
+
+ ACE_Auto_Event handle_;
+ ACE_Process_Mutex *mutex_;
+ int iterations_;
+};
+
+static int abandon = 1;
+
+static ACE_THR_FUNC_RETURN
+worker (void *data)
+{
+ Event_Handler *handler = (Event_Handler *) data;
+
+ handler->handle_.signal ();
+ handler->mutex_->acquire ();
+
+ if (!abandon)
+ handler->mutex_->release ();
+
+ return 0;
+}
+
+int
+Event_Handler::handle_signal (int,
+ siginfo_t *s,
+ ucontext_t *)
+{
+ ACE_HANDLE handle = s->si_handle_;
+ if (handle == this->handle_.handle ())
+ ACE_Reactor::instance ()->register_handler (this,
+ this->mutex_->lock ().proc_mutex_);
+ else
+ {
+ ACE_Reactor::instance ()->remove_handler (this->mutex_->lock ().proc_mutex_,
+ ACE_Event_Handler::DONT_CALL);
+ delete this->mutex_;
+ }
+
+ return 0;
+}
+
+int
+Event_Handler::handle_timeout (const ACE_Time_Value &,
+ const void *)
+{
+ --this->iterations_;
+ ACE_DEBUG ((LM_DEBUG,
+ "(%t) timeout occured @ %T, iterations left %d\n",
+ this->iterations_));
+
+ if (this->iterations_ == 0)
+ {
+ ACE_Reactor::instance ()->remove_handler (this->handle_.handle (),
+ ACE_Event_Handler::DONT_CALL);
+
+ ACE_Reactor::instance ()->cancel_timer (this);
+
+ ACE_Reactor::end_event_loop ();
+ }
+ else
+ {
+ ACE_NEW_RETURN (this->mutex_,
+ ACE_Process_Mutex,
+ -1);
+ int result = ACE_Thread_Manager::instance ()->spawn (&worker, this);
+ ACE_ASSERT (result != -1);
+ ACE_UNUSED_ARG (result);
+ }
+
+ return 0;
+}
+
+int
+ACE_TMAIN (int , ACE_TCHAR *[])
+{
+ Event_Handler event_handler;
+
+ event_handler.iterations_ = 5;
+ int result = ACE_Reactor::instance ()->register_handler
+ (&event_handler,
+ event_handler.handle_.handle ());
+ ACE_ASSERT (result == 0);
+
+ ACE_Time_Value timeout (2);
+ result = ACE_Reactor::instance ()->schedule_timer (&event_handler,
+ 0,
+ timeout,
+ timeout);
+ ACE_ASSERT (result != -1);
+
+ ACE_Reactor::run_event_loop ();
+
+ return 0;
+}
+#else /* !ACE_WIN32 */
+int
+ACE_TMAIN (int , ACE_TCHAR *[])
+{
+ return 0;
+}
+#endif /* ACE_WIN32 */
diff --git a/ACE/examples/Reactor/WFMO_Reactor/Console_Input.cpp b/ACE/examples/Reactor/WFMO_Reactor/Console_Input.cpp
new file mode 100644
index 00000000000..363a6a8ead8
--- /dev/null
+++ b/ACE/examples/Reactor/WFMO_Reactor/Console_Input.cpp
@@ -0,0 +1,87 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// examples
+//
+// = FILENAME
+// Console_Input.cpp
+//
+// = DESCRIPTION
+//
+// This application tests the working of WFMO_Reactor when users
+// are interested in console input.
+//
+// = AUTHOR
+// Irfan Pyarali <irfan@cs.wustl.edu>
+//
+// ============================================================================
+
+#include "ace/Reactor.h"
+#include "ace/OS_NS_unistd.h"
+#include "ace/OS_NS_string.h"
+#include "ace/OS_main.h"
+
+ACE_RCSID(WFMO_Reactor, Console_Input, "$Id$")
+
+class Event_Handler : public ACE_Event_Handler
+{
+public:
+ Event_Handler (ACE_Reactor &reactor);
+ int handle_signal (int signum, siginfo_t * = 0, ucontext_t * = 0);
+ int handle_close (ACE_HANDLE handle,
+ ACE_Reactor_Mask close_mask);
+};
+
+Event_Handler::Event_Handler (ACE_Reactor &reactor)
+{
+ this->reactor (&reactor);
+
+ if (this->reactor ()->register_handler (this,
+ ACE_STDIN) != 0)
+ ACE_ERROR ((LM_ERROR,
+ "Registration with Reactor could not be done\n"));
+}
+
+int
+Event_Handler::handle_signal (int, siginfo_t *, ucontext_t *)
+{
+ ACE_TCHAR buffer[BUFSIZ];
+ int result = ACE_OS::read (ACE_STDIN, buffer, sizeof buffer);
+ buffer[result] = '\0';
+
+ if (result <= 0)
+ {
+ this->reactor ()->close ();
+ ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "ACE_OS::read"), -1);
+ }
+
+ if (ACE_OS::strcmp (ACE_TEXT("quit\r\n"), buffer) == 0)
+ this->reactor ()->close ();
+
+ ACE_DEBUG ((LM_DEBUG, "User input: %s", buffer));
+
+ return 0;
+}
+
+int
+Event_Handler::handle_close (ACE_HANDLE,
+ ACE_Reactor_Mask)
+{
+ ACE_DEBUG ((LM_DEBUG, "Event_Handler removed from Reactor\n"));
+ return 0;
+}
+
+int
+ACE_TMAIN (int, ACE_TCHAR *[])
+{
+ ACE_Reactor reactor;
+ Event_Handler handler (reactor);
+
+ int result = 0;
+ while (result != -1)
+ result = reactor.handle_events ();
+
+ return 0;
+}
diff --git a/ACE/examples/Reactor/WFMO_Reactor/Directory_Changes.cpp b/ACE/examples/Reactor/WFMO_Reactor/Directory_Changes.cpp
new file mode 100644
index 00000000000..7f5126c6cba
--- /dev/null
+++ b/ACE/examples/Reactor/WFMO_Reactor/Directory_Changes.cpp
@@ -0,0 +1,128 @@
+// $Id$
+//
+// ============================================================================
+//
+// = LIBRARY
+// examples
+//
+// = FILENAME
+// Directory_Changes.cpp
+//
+// = DESCRIPTION
+//
+// This application tests the working of WFMO_Reactor when users
+// are interested in monitoring changes in the filesystem.
+//
+// = AUTHOR
+// Irfan Pyarali
+//
+// ============================================================================
+
+#include "ace/OS_main.h"
+
+#if defined (ACE_WIN32)
+
+#include "ace/Reactor.h"
+#include "ace/OS_NS_unistd.h"
+#include "ace/OS_NS_fcntl.h"
+
+ACE_RCSID(WFMO_Reactor, Directory_Changes, "$Id$")
+
+static int stop_test = 0;
+static const ACE_TCHAR *directory = ACE_TEXT (".");
+static const ACE_TCHAR *temp_file = ACE_TEXT ("foo");
+
+class Event_Handler : public ACE_Event_Handler
+{
+public:
+ Event_Handler (ACE_Reactor &reactor);
+ ~Event_Handler (void);
+ int handle_signal (int signum, siginfo_t * = 0, ucontext_t * = 0);
+ int handle_close (ACE_HANDLE handle,
+ ACE_Reactor_Mask close_mask);
+
+private:
+ ACE_HANDLE handle_;
+};
+
+Event_Handler::Event_Handler (ACE_Reactor &reactor)
+ : handle_ (ACE_INVALID_HANDLE)
+{
+ this->reactor (&reactor);
+
+ int change_notification_flags = FILE_NOTIFY_CHANGE_FILE_NAME;
+
+ this->handle_ = ACE_TEXT_FindFirstChangeNotification (directory, // pointer to name of directory to watch
+ FALSE, // flag for monitoring directory or directory tree
+ change_notification_flags // filter conditions to watch for
+ );
+ if (this->handle_ == ACE_INVALID_HANDLE)
+ ACE_ERROR ((LM_ERROR, "FindFirstChangeNotification could not be setup\n"));
+
+ if (this->reactor ()->register_handler (this,
+ this->handle_) != 0)
+ ACE_ERROR ((LM_ERROR, "Registration with Reactor could not be done\n"));
+}
+
+Event_Handler::~Event_Handler (void)
+{
+}
+
+int
+Event_Handler::handle_signal (int, siginfo_t *, ucontext_t *)
+{
+ ::FindNextChangeNotification (this->handle_);
+ if (stop_test)
+ this->reactor ()->close ();
+ return 0;
+}
+
+int
+Event_Handler::handle_close (ACE_HANDLE,
+ ACE_Reactor_Mask)
+{
+ ACE_DEBUG ((LM_DEBUG, "Event_Handler removed from Reactor\n"));
+ ::FindCloseChangeNotification (this->handle_);
+ return 0;
+}
+
+void
+worker (void)
+{
+ ACE_DEBUG ((LM_DEBUG, "(%t) Thread creation\n"));
+ ACE_DEBUG ((LM_DEBUG, "(%t) Thread creating temporary file\n"));
+ ACE_HANDLE file = ACE_OS::open (temp_file, _O_CREAT | _O_EXCL);
+ if (file == ACE_INVALID_HANDLE)
+ ACE_ERROR ((LM_ERROR, "Error in creating %s: %p\n", temp_file, "ACE_OS::open"));
+ else
+ {
+ ACE_OS::close (file);
+ ACE_DEBUG ((LM_DEBUG, "(%t) Thread sleeping\n"));
+ ACE_OS::sleep (3);
+ ACE_DEBUG ((LM_DEBUG, "(%t) Thread removing temporary file\n"));
+ stop_test = 1;
+ ACE_OS::unlink (temp_file);
+ }
+}
+
+int
+ACE_TMAIN (int, ACE_TCHAR *[])
+{
+ ACE_Reactor reactor;
+ Event_Handler handler (reactor);
+
+ int result = ACE_OS::thr_create ((ACE_THR_FUNC) worker, 0, 0, 0);
+ ACE_ASSERT (result == 0);
+
+ for (result = 0; result != -1; result = reactor.handle_events ())
+ continue;
+
+ return 0;
+}
+#else /* !ACE_WIN32 */
+int
+ACE_TMAIN (int, ACE_TCHAR *[])
+{
+ return 0;
+}
+#endif /* ACE_WIN32 */
diff --git a/ACE/examples/Reactor/WFMO_Reactor/Exceptions.cpp b/ACE/examples/Reactor/WFMO_Reactor/Exceptions.cpp
new file mode 100644
index 00000000000..5bbf0b4e4f3
--- /dev/null
+++ b/ACE/examples/Reactor/WFMO_Reactor/Exceptions.cpp
@@ -0,0 +1,109 @@
+// $Id$
+//
+// ============================================================================
+//
+// = LIBRARY
+// examples
+//
+// = FILENAME
+// Exceptions.cpp
+//
+// = DESCRIPTION
+//
+// This test application tests the state of WFMO_Reactor when
+// exceptions occurs when executing user callbacks.
+//
+// The thread count in WFMO_Reactor is used to ensure that state of
+// WFMO_Reactor is not fouled up when exceptions occur in user code.
+// This example also shows how to write event loops that survive
+// user exceptions
+//
+// = AUTHOR
+// Irfan Pyarali
+//
+// ============================================================================
+
+#include "ace/OS_main.h"
+
+#if defined (ACE_WIN32)
+
+#include "ace/WFMO_Reactor.h"
+
+ACE_RCSID(WFMO_Reactor, Exceptions, "$Id$")
+
+class Event_Handler : public ACE_Event_Handler
+{
+public:
+ Event_Handler (void)
+ : event_ (1)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ "Event_Handler created\n"));
+ }
+
+ ~Event_Handler (void)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ "Event_Handler destroyed\n"));
+ }
+
+ int handle_signal (int, siginfo_t * = 0, ucontext_t * = 0)
+ {
+ char *cause_exception = 0;
+ char a = *cause_exception;
+ ACE_UNUSED_ARG(a);
+ return 0;
+ }
+
+ ACE_HANDLE get_handle (void) const
+ {
+ return this->event_.handle ();
+ }
+private:
+ ACE_Manual_Event event_;
+};
+
+class ACE_WFMO_Reactor_Test
+{
+public:
+ static void doit (ACE_WFMO_Reactor &wfmo_reactor)
+ {
+ for (int i = 1; i <= 10; i++)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ "Active threads in WFMO_Reactor (before handle_events) = %d\n",
+ wfmo_reactor.active_threads_));
+ ACE_SEH_TRY
+ {
+ wfmo_reactor.handle_events ();
+ }
+ ACE_SEH_EXCEPT (EXCEPTION_EXECUTE_HANDLER)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ "Exception occurred\n"));
+ }
+ ACE_DEBUG ((LM_DEBUG,
+ "Active threads in WFMO_Reactor (after handle_events) = %d\n",
+ wfmo_reactor.active_threads_));
+ }
+ }
+};
+
+int
+ACE_TMAIN (int, ACE_TCHAR *[])
+{
+ Event_Handler handler;
+ ACE_WFMO_Reactor wfmo_reactor;
+ wfmo_reactor.register_handler (&handler);
+
+ ACE_WFMO_Reactor_Test::doit (wfmo_reactor);
+
+ return 0;
+}
+#else /* !ACE_WIN32 */
+int
+ACE_TMAIN (int, ACE_TCHAR *[])
+{
+ return 0;
+}
+#endif /* ACE_WIN32 */
diff --git a/ACE/examples/Reactor/WFMO_Reactor/Handle_Close.cpp b/ACE/examples/Reactor/WFMO_Reactor/Handle_Close.cpp
new file mode 100644
index 00000000000..9eb6d7c727a
--- /dev/null
+++ b/ACE/examples/Reactor/WFMO_Reactor/Handle_Close.cpp
@@ -0,0 +1,333 @@
+// $Id$
+//
+// ============================================================================
+//
+// = LIBRARY
+// examples
+//
+// = FILENAME
+// Handle_Close.cpp
+//
+// = DESCRIPTION
+//
+// This application tests whether handle_close gets called and if
+// the correct masks are passed along. The handler should get
+// handle_close called for all three masks (READ, WRITE, and
+// EXCEPT).
+//
+// = AUTHOR
+// Irfan Pyarali
+//
+// ============================================================================
+
+#include "ace/Get_Opt.h"
+#include "ace/Reactor.h"
+#include "ace/WFMO_Reactor.h"
+#include "ace/Select_Reactor.h"
+#include "ace/Auto_Ptr.h"
+#include "ace/Pipe.h"
+#include "ace/OS_main.h"
+
+ACE_RCSID(WFMO_Reactor, Handle_Close, "$Id: ")
+
+// Use the WFMO_Reactor
+static int opt_wfmo_reactor = 0;
+
+// Use the Select_Reactor
+static int opt_select_reactor = 0;
+
+// Make pipe readable in main()
+static int write_to_pipe_in_main = 0;
+
+// Cancel reads
+static int cancel_reads = 0;
+
+// Write some data to the pipe. This will cause handle_input to get
+// called.
+void
+write_to_pipe (ACE_Pipe &pipe)
+{
+ char *data = "hello";
+ size_t len = ACE_OS::strlen (data);
+
+ ssize_t result = ACE::send (pipe.write_handle (),
+ data,
+ len);
+ ACE_ASSERT ((size_t)result == len);
+ ACE_UNUSED_ARG (result);
+}
+
+// Simple handler class
+class Handler : public ACE_Event_Handler
+{
+public:
+ Handler (ACE_Pipe &pipe)
+ : pipe_ (pipe)
+ {
+ }
+
+ ~Handler (void)
+ {
+ this->reactor (0);
+ }
+
+ ACE_HANDLE get_handle (void) const
+ {
+ return this->pipe_.read_handle ();
+ }
+
+ int handle_close (ACE_HANDLE handle,
+ ACE_Reactor_Mask close_mask)
+ {
+ ACE_UNUSED_ARG (handle);
+ ACE_DEBUG ((LM_DEBUG,
+ "Handler::handle_close called with mask = %d\n",
+ close_mask));
+ return 0;
+ }
+
+ int handle_input (ACE_HANDLE handle)
+ {
+ ACE_UNUSED_ARG (handle);
+ ACE_DEBUG ((LM_DEBUG, "Handler::handle_input\n"));
+
+ // Remove for reading
+ return -1;
+ }
+
+ int handle_output (ACE_HANDLE handle)
+ {
+ ACE_UNUSED_ARG (handle);
+ ACE_DEBUG ((LM_DEBUG, "Handler::handle_output\n"));
+
+ // Optionally cancel reads
+ if (cancel_reads)
+ {
+ int result = this->reactor ()->cancel_wakeup (this,
+ ACE_Event_Handler::READ_MASK);
+ ACE_ASSERT (result != -1);
+ ACE_UNUSED_ARG (result);
+ }
+
+ // Write to the pipe; this causes handle_input to get called.
+ if (!write_to_pipe_in_main)
+ write_to_pipe (this->pipe_);
+
+ // Remove for writing
+ return -1;
+ }
+
+protected:
+ ACE_Pipe &pipe_;
+};
+
+class Different_Handler : public ACE_Event_Handler
+{
+public:
+
+ Different_Handler (ACE_Pipe &pipe)
+ : pipe_ (pipe)
+ {
+ }
+
+ ~Different_Handler (void)
+ {
+ this->reactor (0);
+ }
+
+ ACE_HANDLE get_handle (void) const
+ {
+ return this->pipe_.read_handle ();
+ }
+
+ int handle_close (ACE_HANDLE handle,
+ ACE_Reactor_Mask close_mask)
+ {
+ ACE_UNUSED_ARG (handle);
+ ACE_DEBUG ((LM_DEBUG,
+ "Different_Handler::handle_close called with mask = %d\n",
+ close_mask));
+ return 0;
+ }
+
+ int handle_input (ACE_HANDLE handle)
+ {
+ ACE_UNUSED_ARG (handle);
+ ACE_DEBUG ((LM_DEBUG, "Different_Handler::handle_input\n"));
+
+ // Remove for reading
+ int result = this->reactor ()->remove_handler (this,
+ ACE_Event_Handler::READ_MASK);
+ ACE_ASSERT (result == 0);
+ ACE_UNUSED_ARG (result);
+
+ return 0;
+ }
+
+ int handle_output (ACE_HANDLE handle)
+ {
+ ACE_UNUSED_ARG (handle);
+ ACE_DEBUG ((LM_DEBUG, "Different_Handler::handle_output\n"));
+
+ // Add for reading
+ int result = this->reactor ()->mask_ops (this,
+ ACE_Event_Handler::READ_MASK,
+ ACE_Reactor::ADD_MASK);
+ ACE_ASSERT (result != -1);
+
+ ACE_Reactor_Mask old_masks =
+ ACE_Event_Handler::WRITE_MASK |
+ ACE_Event_Handler::EXCEPT_MASK;
+
+ ACE_ASSERT (old_masks ==
+ static_cast<ACE_Reactor_Mask> (result));
+ ACE_UNUSED_ARG (old_masks);
+
+ // Get new masks
+ result = this->reactor ()->mask_ops (this,
+ ACE_Event_Handler::NULL_MASK,
+ ACE_Reactor::GET_MASK);
+ ACE_ASSERT (result != -1);
+
+ ACE_Reactor_Mask current_masks =
+ ACE_Event_Handler::READ_MASK |
+ ACE_Event_Handler::WRITE_MASK |
+ ACE_Event_Handler::EXCEPT_MASK;
+
+ ACE_ASSERT (current_masks ==
+ static_cast<ACE_Reactor_Mask> (result));
+ ACE_UNUSED_ARG (current_masks);
+
+ // Remove for writing
+ ACE_Reactor_Mask mask = ACE_Event_Handler::WRITE_MASK | ACE_Event_Handler::DONT_CALL;
+ result = this->reactor ()->remove_handler (this,
+ mask);
+ ACE_ASSERT (result == 0);
+
+ // Write to the pipe; this causes handle_input to get called.
+ if (!write_to_pipe_in_main)
+ write_to_pipe (this->pipe_);
+
+ return 0;
+ }
+
+protected:
+ ACE_Pipe &pipe_;
+};
+
+
+//
+// Selection of which reactor should get created
+//
+ACE_Reactor *
+create_reactor (void)
+{
+ ACE_Reactor_Impl *impl = 0;
+
+ if (opt_wfmo_reactor)
+ {
+#if defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)
+ ACE_NEW_RETURN (impl,
+ ACE_WFMO_Reactor,
+ 0);
+#endif /* ACE_WIN32 */
+ }
+ else if (opt_select_reactor)
+ {
+ ACE_NEW_RETURN (impl,
+ ACE_Select_Reactor,
+ 0);
+ }
+ else
+ {
+ ACE_Reactor *singleton_reactor =
+ ACE_Reactor::instance ();
+ ACE_Reactor::instance (0);
+ return singleton_reactor;
+ }
+
+ ACE_Reactor *reactor = 0;
+ ACE_NEW_RETURN (reactor,
+ ACE_Reactor (impl,
+ 1),
+ 0);
+
+ return reactor;
+}
+
+int
+ACE_TMAIN (int argc, ACE_TCHAR *argv[])
+{
+ int result = 0;
+
+ // Parse args
+ ACE_Get_Opt getopt (argc, argv, ACE_TEXT ("swmc"), 1);
+ for (int c; (c = getopt ()) != -1; )
+ switch (c)
+ {
+ case 's':
+ opt_select_reactor = 1;
+ break;
+ case 'w':
+ opt_wfmo_reactor = 1;
+ break;
+ case 'm':
+ write_to_pipe_in_main = 1;
+ break;
+ case 'c':
+ cancel_reads = 1;
+ break;
+ }
+
+ // Create pipes
+ ACE_Pipe pipe1, pipe2;
+
+ result = pipe1.open ();
+ ACE_ASSERT (result == 0);
+
+ result = pipe2.open ();
+ ACE_ASSERT (result == 0);
+
+ // Create handlers
+ Handler handler (pipe1);
+ Different_Handler different_handler (pipe2);
+
+ // Manage memory automagically.
+ auto_ptr<ACE_Reactor> reactor (create_reactor ());
+
+ // Register handlers
+ ACE_Reactor_Mask handler_mask =
+ ACE_Event_Handler::READ_MASK |
+ ACE_Event_Handler::WRITE_MASK |
+ ACE_Event_Handler::EXCEPT_MASK;
+
+ ACE_Reactor_Mask different_handler_mask =
+ ACE_Event_Handler::WRITE_MASK |
+ ACE_Event_Handler::EXCEPT_MASK;
+
+ result = reactor->register_handler (&handler,
+ handler_mask);
+ ACE_ASSERT (result == 0);
+
+ result = reactor->register_handler (&different_handler,
+ different_handler_mask);
+ ACE_ASSERT (result == 0);
+
+ // Write to the pipe; this causes handle_input to get called.
+ if (write_to_pipe_in_main)
+ {
+ write_to_pipe (pipe1);
+ write_to_pipe (pipe2);
+ }
+
+ // Note that handle_output will get called automatically since the
+ // pipe is writable!
+
+ // Run for three seconds
+ ACE_Time_Value time (3);
+ reactor->run_reactor_event_loop (time);
+
+ ACE_DEBUG ((LM_DEBUG, "\nClosing down the application\n\n"));
+
+ return 0;
+}
diff --git a/ACE/examples/Reactor/WFMO_Reactor/Makefile.am b/ACE/examples/Reactor/WFMO_Reactor/Makefile.am
new file mode 100644
index 00000000000..cfa1c687b6c
--- /dev/null
+++ b/ACE/examples/Reactor/WFMO_Reactor/Makefile.am
@@ -0,0 +1,308 @@
+## Process this file with automake to create Makefile.in
+##
+## $Id$
+##
+## This file was generated by MPC. Any changes made directly to
+## this file will be lost the next time it is generated.
+##
+## MPC Command:
+## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu
+
+ACE_BUILDDIR = $(top_builddir)
+ACE_ROOT = $(top_srcdir)
+
+noinst_PROGRAMS =
+
+## Makefile.WFMO_Reactor_APC.am
+
+if BUILD_WFMO
+if !BUILD_WINCE
+noinst_PROGRAMS += apc
+
+apc_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+apc_SOURCES = \
+ APC.cpp
+
+apc_LDADD = \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_WINCE
+endif BUILD_WFMO
+
+## Makefile.WFMO_Reactor_Abandoned.am
+
+if BUILD_WFMO
+noinst_PROGRAMS += abandoned
+
+abandoned_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+abandoned_SOURCES = \
+ Abandoned.cpp
+
+abandoned_LDADD = \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif BUILD_WFMO
+
+## Makefile.WFMO_Reactor_Console_Input.am
+
+if BUILD_WFMO
+noinst_PROGRAMS += console_input
+
+console_input_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+console_input_SOURCES = \
+ Console_Input.cpp
+
+console_input_LDADD = \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif BUILD_WFMO
+
+## Makefile.WFMO_Reactor_Directory_Changes.am
+
+if BUILD_WFMO
+noinst_PROGRAMS += directory_changes
+
+directory_changes_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+directory_changes_SOURCES = \
+ Directory_Changes.cpp
+
+directory_changes_LDADD = \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif BUILD_WFMO
+
+## Makefile.WFMO_Reactor_Exceptions.am
+
+if BUILD_WFMO
+noinst_PROGRAMS += exceptions
+
+exceptions_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+exceptions_SOURCES = \
+ Exceptions.cpp
+
+exceptions_LDADD = \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif BUILD_WFMO
+
+## Makefile.WFMO_Reactor_Handle_Close.am
+
+if BUILD_WFMO
+noinst_PROGRAMS += handle_close
+
+handle_close_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+handle_close_SOURCES = \
+ Handle_Close.cpp
+
+handle_close_LDADD = \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif BUILD_WFMO
+
+## Makefile.WFMO_Reactor_Multithreading.am
+
+if BUILD_WFMO
+noinst_PROGRAMS += multithreading
+
+multithreading_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+multithreading_SOURCES = \
+ Multithreading.cpp
+
+multithreading_LDADD = \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif BUILD_WFMO
+
+## Makefile.WFMO_Reactor_Network_Events.am
+
+if BUILD_WFMO
+noinst_PROGRAMS += network_events
+
+network_events_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+network_events_SOURCES = \
+ Network_Events.cpp
+
+network_events_LDADD = \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif BUILD_WFMO
+
+## Makefile.WFMO_Reactor_Prerun_State_Changes.am
+
+if BUILD_WFMO
+noinst_PROGRAMS += prerun_state_changes
+
+prerun_state_changes_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+prerun_state_changes_SOURCES = \
+ Prerun_State_Changes.cpp
+
+prerun_state_changes_LDADD = \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif BUILD_WFMO
+
+## Makefile.WFMO_Reactor_Registration.am
+
+if BUILD_WFMO
+noinst_PROGRAMS += registration
+
+registration_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+registration_SOURCES = \
+ Registration.cpp
+
+registration_LDADD = \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif BUILD_WFMO
+
+## Makefile.WFMO_Reactor_Registry_Changes.am
+
+if BUILD_WFMO
+if !BUILD_ACE_FOR_TAO
+if !BUILD_WINCE
+noinst_PROGRAMS += registry_changes
+
+registry_changes_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+registry_changes_SOURCES = \
+ Registry_Changes.cpp
+
+registry_changes_LDADD = \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_WINCE
+endif !BUILD_ACE_FOR_TAO
+endif BUILD_WFMO
+
+## Makefile.WFMO_Reactor_Removals.am
+
+if BUILD_WFMO
+noinst_PROGRAMS += removals
+
+removals_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+removals_SOURCES = \
+ Removals.cpp
+
+removals_LDADD = \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif BUILD_WFMO
+
+## Makefile.WFMO_Reactor_Suspended_Removals.am
+
+if BUILD_WFMO
+noinst_PROGRAMS += suspended_removals
+
+suspended_removals_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+suspended_removals_SOURCES = \
+ Suspended_Removals.cpp
+
+suspended_removals_LDADD = \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif BUILD_WFMO
+
+## Makefile.WFMO_Reactor_Talker.am
+
+if BUILD_WFMO
+if !BUILD_ACE_FOR_TAO
+if !BUILD_WINCE
+noinst_PROGRAMS += talker
+
+talker_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+talker_SOURCES = \
+ Talker.cpp
+
+talker_LDADD = \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_WINCE
+endif !BUILD_ACE_FOR_TAO
+endif BUILD_WFMO
+
+## Makefile.WFMO_Reactor_Timeouts.am
+
+if BUILD_WFMO
+noinst_PROGRAMS += timeouts
+
+timeouts_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+timeouts_SOURCES = \
+ Timeouts.cpp
+
+timeouts_LDADD = \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif BUILD_WFMO
+
+## Makefile.WFMO_Reactor_Window_Messages.am
+
+if BUILD_WFMO
+if !BUILD_ACE_FOR_TAO
+if !BUILD_WINCE
+noinst_PROGRAMS += window_messages
+
+window_messages_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+window_messages_SOURCES = \
+ Window_Messages.cpp
+
+window_messages_LDADD = \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_WINCE
+endif !BUILD_ACE_FOR_TAO
+endif BUILD_WFMO
+
+## Clean up template repositories, etc.
+clean-local:
+ -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.*
+ -rm -f gcctemp.c gcctemp so_locations *.ics
+ -rm -rf cxx_repository ptrepository ti_files
+ -rm -rf templateregistry ir.out
+ -rm -rf ptrepository SunWS_cache Templates.DB
diff --git a/ACE/examples/Reactor/WFMO_Reactor/Multithreading.cpp b/ACE/examples/Reactor/WFMO_Reactor/Multithreading.cpp
new file mode 100644
index 00000000000..0778f375251
--- /dev/null
+++ b/ACE/examples/Reactor/WFMO_Reactor/Multithreading.cpp
@@ -0,0 +1,262 @@
+// $Id$
+//
+// ============================================================================
+//
+// = LIBRARY
+// examples
+//
+// = FILENAME
+// Multithreading.cpp
+//
+// = DESCRIPTION
+//
+// This application tests multiple threads simultaneously calling
+// Reactor::handle_events(). It also shows how different threads
+// can update the state of Reactor by registering and removing
+// Event_Handlers.
+//
+// Note that this test will only work with WFMO_Reactor
+//
+// = AUTHOR
+// Irfan Pyarali
+//
+// ============================================================================
+
+#include "ace/OS_main.h"
+
+#if defined (ACE_WIN32)
+
+#include "ace/Task.h"
+#include "ace/Reactor.h"
+#include "ace/WFMO_Reactor.h"
+#include "ace/Get_Opt.h"
+#include "ace/OS_NS_time.h"
+
+ACE_RCSID(WFMO_Reactor, Multithreading, "$Id$")
+
+static int concurrent_threads = 1;
+static int number_of_handles = static_cast<int> (ACE_Reactor::instance ()->size ());
+static int number_of_handles_to_signal = 1;
+static int interval = 2;
+static int iterations = 10;
+
+// Explain usage and exit.
+static void
+print_usage_and_die (void)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ "usage: \n\t"
+ "[-t (# of threads - default 1)] \n\t"
+ "[-h (# of handlers) - default 62] \n\t"
+ "[-i (# time interval between signals) - default 2] \n\t"
+ "[-s (# of handles to signal) - default 1] \n\t"
+ "[-e (# of iterations) - default 10] \n\t"));
+ ACE_OS::exit (1);
+}
+
+// Parse the command-line arguments and set options.
+static void
+parse_args (int argc, ACE_TCHAR **argv)
+{
+ ACE_Get_Opt get_opt (argc, argv, ACE_TEXT("t:h:s:i:e:"));
+ int c;
+
+ while ((c = get_opt ()) != -1)
+ switch (c)
+ {
+ case 't':
+ concurrent_threads = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'e':
+ iterations = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'h':
+ number_of_handles = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'i':
+ interval = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 's':
+ number_of_handles_to_signal = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ default:
+ print_usage_and_die ();
+ break;
+ }
+}
+
+class Task_Handler : public ACE_Task<ACE_NULL_SYNCH>
+{
+public:
+ Task_Handler (size_t number_of_handles,
+ size_t concurrent_threads);
+ // Constructor.
+
+ ~Task_Handler (void);
+ // Destructor.
+
+ virtual int handle_close (ACE_HANDLE handle,
+ ACE_Reactor_Mask close_mask);
+ // Called when object is removed from the ACE_Reactor
+
+ int handle_signal (int signum, siginfo_t * = 0, ucontext_t * = 0);
+ // Handle events being signaled by the main thread.
+
+ virtual int handle_timeout (const ACE_Time_Value &tv,
+ const void *arg = 0);
+ // Called when timer expires.
+
+ int svc (void);
+ // Task event loop.
+
+ int signal (size_t index);
+ // Signal an event.
+
+private:
+ ACE_Auto_Event *events_;
+};
+
+// All threads do reactor->handle_events ()
+int
+Task_Handler::svc (void)
+{
+ // Try to become the owner
+ ACE_Reactor::instance ()->owner (ACE_Thread::self ());
+ // Run the event loop.
+ return ACE_Reactor::run_event_loop ();
+}
+
+Task_Handler::Task_Handler (size_t number_of_handles,
+ size_t concurrent_threads)
+{
+ ACE_NEW (this->events_, ACE_Auto_Event [number_of_handles]);
+
+ for (size_t i = 0; i < number_of_handles; ++i)
+ if (ACE_Reactor::instance ()->register_handler (this,
+ this->events_[i].handle ()) == -1)
+ ACE_ERROR ((LM_ERROR,
+ "%p\t cannot register handle %d with Reactor\n",
+ "Task_Handler::Task_Handler",
+ i));
+
+ // Make us an active object.
+ if (this->activate (THR_NEW_LWP,
+ static_cast<int> (concurrent_threads)) == -1)
+ ACE_ERROR ((LM_ERROR, "%p\t cannot activate task\n",
+ "activate"));
+}
+
+Task_Handler::~Task_Handler (void)
+{
+ this->reactor (0);
+ delete [] this->events_;
+}
+
+
+int
+Task_Handler::handle_signal (int, siginfo_t *siginfo, ucontext_t *)
+{
+ // When signaled, print message, remove self, and add self
+ // This will force Reactor to update its internal handle tables
+
+ ACE_DEBUG ((LM_DEBUG,
+ "(%t) calls handle_signal for handle %d\n",
+ siginfo->si_handle_));
+
+ if (ACE_Reactor::instance ()->remove_handler (siginfo->si_handle_,
+ ACE_Event_Handler::DONT_CALL) == -1)
+ return -1;
+ // ACE_ERROR_RETURN ((LM_ERROR,
+ // "(%t) %p\tTask cannot be unregistered from Reactor: handle value = %d\n",
+ // "Task_Handler::handle_signal",
+ // siginfo->si_handle_), -1);
+
+ if (ACE_Reactor::instance ()->register_handler (this,
+ siginfo->si_handle_) == -1)
+ return -1;
+ // ACE_ERROR_RETURN ((LM_ERROR,
+ // "(%t) %p\tTask cannot be registered with Reactor: handle value = %d\n",
+ // "Task_Handler::handle_signal",
+ // siginfo->si_handle_), -1);
+ return 0;
+}
+
+int
+Task_Handler::handle_close (ACE_HANDLE handle,
+ ACE_Reactor_Mask)
+{
+ ACE_DEBUG ((LM_DEBUG, "(%t) handle_close() called: handle value = %d\n",
+ handle));
+ return 0;
+}
+
+int
+Task_Handler::handle_timeout (const ACE_Time_Value &,
+ const void *arg)
+{
+ ACE_DEBUG ((LM_DEBUG, "(%t) handle_timeout() called: iteration value = %d\n",
+ size_t (arg)));
+ return 0;
+}
+
+int
+Task_Handler::signal (size_t index)
+{
+ return this->events_[index].signal ();
+}
+
+int
+ACE_TMAIN (int argc, ACE_TCHAR **argv)
+{
+ parse_args (argc, argv);
+ Task_Handler task (number_of_handles,
+ concurrent_threads);
+
+ ACE_OS::srand (ACE_OS::time (0L));
+
+ for (int i = 1; i <= iterations; i++)
+ {
+ // Sleep for a while
+ ACE_OS::sleep (interval);
+
+ // Randomly generate events
+ ACE_DEBUG ((LM_DEBUG, "********************************************************\n"));
+ ACE_DEBUG ((LM_DEBUG, "(%t -- main thread) signaling %d events : iteration = %d\n",
+ number_of_handles_to_signal,
+ i));
+ ACE_DEBUG ((LM_DEBUG, "********************************************************\n"));
+
+ // Setup a timer for the task
+ if (ACE_Reactor::instance ()->schedule_timer (&task,
+ (void *)((size_t)i),
+ ACE_Time_Value::zero) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "schedule_timer"), -1);
+
+ for (int i = 0; i < number_of_handles_to_signal; i++)
+ // Randomly select a handle to signal.
+ task.signal (ACE_OS::rand() % number_of_handles);
+ }
+
+ // Sleep for a while
+ ACE_OS::sleep (interval);
+
+ // End the Reactor event loop
+ ACE_Reactor::end_event_loop ();
+
+ // Wait for all threads to exit
+ ACE_Thread_Manager::instance ()->wait ();
+
+ // Close the Reactor singleton before exiting this function.
+ // If we wait for the Object Manager to do this, it will be too
+ // late since Task_Handler instance would have disappeared.
+ ACE_Reactor::close_singleton ();
+
+ return 0;
+}
+#else /* !ACE_WIN32 */
+int
+ACE_TMAIN (int, ACE_TCHAR **)
+{
+ return 0;
+}
+#endif /* ACE_WIN32 */
diff --git a/ACE/examples/Reactor/WFMO_Reactor/Network_Events.cpp b/ACE/examples/Reactor/WFMO_Reactor/Network_Events.cpp
new file mode 100644
index 00000000000..9935679a60f
--- /dev/null
+++ b/ACE/examples/Reactor/WFMO_Reactor/Network_Events.cpp
@@ -0,0 +1,211 @@
+// $Id$
+//
+// ============================================================================
+//
+// = LIBRARY
+// examples
+//
+// = FILENAME
+// Network_Events.cpp
+//
+// = DESCRIPTION
+//
+// This application tests Reactor to make sure that it responds
+// correctly to different kinds of network events.
+//
+// The test starts off by creating a Network_Listener, that listens
+// for connections at ACE_DEFAULT_SERVER_PORT. When a client
+// connects, a Network_Handler is created. Network_Handler reads
+// messages off the socket and prints them out. This is done until
+// the remote side shuts down. Multiple clients can connect at the
+// same time.
+//
+// Events tested in this example includes ACCEPT, READ, and CLOSE masks.
+//
+// To run this example, start an instance of this example and
+// connect to it using telnet (to port
+// ACE_DEFAULT_SERVER_PORT(20002)).
+//
+// = AUTHOR
+// Irfan Pyarali
+//
+// ============================================================================
+
+#include "ace/Reactor.h"
+#include "ace/WFMO_Reactor.h"
+#include "ace/INET_Addr.h"
+#include "ace/SOCK_Stream.h"
+#include "ace/SOCK_Acceptor.h"
+#include "ace/OS_main.h"
+
+ACE_RCSID(WFMO_Reactor, Network_Events, "$Id$")
+
+class Network_Handler : public ACE_Event_Handler
+{
+public:
+ Network_Handler (ACE_SOCK_Stream &s);
+ // Default constructor
+
+ virtual int handle_input (ACE_HANDLE handle);
+ virtual int handle_close (ACE_HANDLE handle,
+ ACE_Reactor_Mask close_mask);
+ virtual ACE_HANDLE get_handle (void) const;
+
+ ACE_SOCK_Stream stream_;
+
+};
+
+Network_Handler::Network_Handler (ACE_SOCK_Stream &s)
+ : stream_ (s)
+{
+ this->reactor (ACE_Reactor::instance ());
+
+ int result = this->reactor ()->register_handler (this, READ_MASK);
+ ACE_ASSERT (result == 0);
+ ACE_UNUSED_ARG (result);
+}
+
+ACE_HANDLE
+Network_Handler::get_handle (void) const
+{
+ return this->stream_.get_handle ();
+}
+
+int
+Network_Handler::handle_input (ACE_HANDLE handle)
+{
+ ACE_DEBUG ((LM_DEBUG, "Network_Handler::handle_input handle = %d\n", handle));
+
+ while (1)
+ {
+ char message[BUFSIZ];
+ int result = this->stream_.recv (message, sizeof message);
+ if (result > 0)
+ {
+ message[result] = 0;
+ ACE_DEBUG ((LM_DEBUG, "Remote message: %s\n", message));
+ }
+ else if (result == 0)
+ {
+ ACE_DEBUG ((LM_DEBUG, "Connection closed\n"));
+ return -1;
+ }
+ else if (errno == EWOULDBLOCK)
+ {
+ return 0;
+ }
+ else
+ {
+ ACE_DEBUG ((LM_DEBUG, "Problems in receiving data, result = %d", result));
+ return -1;
+ }
+ }
+}
+
+int
+Network_Handler::handle_close (ACE_HANDLE handle,
+ ACE_Reactor_Mask)
+{
+ ACE_DEBUG ((LM_DEBUG, "Network_Handler::handle_close handle = %d\n", handle));
+
+ this->stream_.close ();
+ delete this;
+
+ ACE_Reactor::end_event_loop ();
+
+ return 0;
+}
+
+class Network_Listener : public ACE_Event_Handler
+{
+public:
+ Network_Listener (void);
+ // Default constructor
+ ~Network_Listener (void);
+ // Default constructor
+
+ virtual int handle_input (ACE_HANDLE handle);
+ virtual int handle_close (ACE_HANDLE handle,
+ ACE_Reactor_Mask close_mask);
+ ACE_HANDLE get_handle (void) const;
+
+ ACE_INET_Addr local_address_;
+ ACE_SOCK_Acceptor acceptor_;
+};
+
+Network_Listener::Network_Listener (void)
+ : local_address_ (ACE_DEFAULT_SERVER_PORT),
+ acceptor_ (local_address_, 1)
+{
+ this->reactor (ACE_Reactor::instance ());
+ int result = this->reactor ()->register_handler (this,
+ ACE_Event_Handler::ACCEPT_MASK);
+ ACE_ASSERT (result == 0);
+ ACE_UNUSED_ARG (result);
+}
+
+Network_Listener::~Network_Listener (void)
+{
+}
+
+ACE_HANDLE
+Network_Listener::get_handle (void) const
+{
+ return this->acceptor_.get_handle ();
+}
+
+int
+Network_Listener::handle_input (ACE_HANDLE handle)
+{
+ ACE_DEBUG ((LM_DEBUG, "Network_Listener::handle_input handle = %d\n", handle));
+
+ ACE_INET_Addr remote_address;
+ ACE_SOCK_Stream stream;
+
+ // Try to find out if the implementation of the reactor that we are
+ // using requires us to reset the event association for the newly
+ // created handle. This is because the newly created handle will
+ // inherit the properties of the listen handle, including its event
+ // associations.
+ int reset_new_handle = this->reactor ()->uses_event_associations ();
+
+ int result = this->acceptor_.accept (stream, // stream
+ &remote_address, // remote address
+ 0, // timeout
+ 1, // restart
+ reset_new_handle); // reset new handler
+ ACE_ASSERT (result == 0);
+ ACE_UNUSED_ARG (result);
+
+ ACE_DEBUG ((LM_DEBUG, "Remote connection from: "));
+ remote_address.dump ();
+
+ Network_Handler *handler;
+ ACE_NEW_RETURN (handler, Network_Handler (stream), -1);
+
+ return 0;
+}
+
+int
+Network_Listener::handle_close (ACE_HANDLE handle,
+ ACE_Reactor_Mask)
+{
+ ACE_DEBUG ((LM_DEBUG, "Network_Listener::handle_close handle = %d\n", handle));
+
+ this->acceptor_.close ();
+
+ delete this;
+
+ return 0;
+}
+
+int
+ACE_TMAIN (int, ACE_TCHAR *[])
+{
+ Network_Listener *listener = 0;
+ listener = new Network_Listener;
+
+ ACE_Reactor::run_event_loop ();
+
+ return 0;
+};
diff --git a/ACE/examples/Reactor/WFMO_Reactor/Prerun_State_Changes.cpp b/ACE/examples/Reactor/WFMO_Reactor/Prerun_State_Changes.cpp
new file mode 100644
index 00000000000..e276fd7d3f8
--- /dev/null
+++ b/ACE/examples/Reactor/WFMO_Reactor/Prerun_State_Changes.cpp
@@ -0,0 +1,66 @@
+// $Id$
+//
+// ============================================================================
+//
+// = LIBRARY
+// examples
+//
+// = FILENAME
+// Prerun_State_Changes.cpp
+//
+// = DESCRIPTION
+//
+// Tests the Reactor's ability to handle state changes before
+// getting a chance to run.
+//
+// = AUTHOR
+//
+// Irfan Pyarali
+//
+// ============================================================================
+
+#include "ace/Reactor.h"
+#include "ace/OS_main.h"
+
+ACE_RCSID(WFMO_Reactor, Prerun_State_Changes, "$Id$")
+
+class Event_Handler : public ACE_Event_Handler
+// = TITLE
+// Generic Event Handler.
+//
+{
+public:
+ virtual int handle_close (ACE_HANDLE handle, ACE_Reactor_Mask mask)
+ {
+ ACE_UNUSED_ARG(mask);
+ ACE_DEBUG ((LM_DEBUG,
+ "event handler %d closed.\n",
+ (size_t) handle));
+ delete this;
+ return 0;
+ }
+};
+
+int
+ACE_TMAIN (int, ACE_TCHAR *[])
+{
+ ACE_HANDLE handle = (ACE_HANDLE) ::socket (PF_INET, SOCK_STREAM, 0);
+
+ Event_Handler *event_handler = new Event_Handler;
+
+ int result = ACE_Reactor::instance ()->register_handler (handle,
+ event_handler,
+ ACE_Event_Handler::READ_MASK);
+ ACE_ASSERT (result == 0);
+
+ result = ACE_Reactor::instance ()->register_handler (handle,
+ event_handler,
+ ACE_Event_Handler::WRITE_MASK | ACE_Event_Handler::QOS_MASK);
+ ACE_ASSERT (result == 0);
+
+ result = ACE_Reactor::instance ()->remove_handler (handle,
+ ACE_Event_Handler::READ_MASK | ACE_Event_Handler::DONT_CALL);
+ ACE_ASSERT (result == 0);
+
+ return 0;
+}
diff --git a/ACE/examples/Reactor/WFMO_Reactor/Registration.cpp b/ACE/examples/Reactor/WFMO_Reactor/Registration.cpp
new file mode 100644
index 00000000000..a9429bdd433
--- /dev/null
+++ b/ACE/examples/Reactor/WFMO_Reactor/Registration.cpp
@@ -0,0 +1,169 @@
+// $Id$
+//
+// ============================================================================
+//
+// = LIBRARY
+// examples
+//
+// = FILENAME
+// Registration.cpp
+//
+// = DESCRIPTION
+//
+// This test application tests a wide range of registration,
+// suspension, resumption, and removal of events from Reactor.
+//
+// The application initially registers two events with Reactor. A
+// auxiliary thread is created to do the signaling on the
+// events. When the first event is signaled, the event is suspended
+// from Reactor. The event is then signaled again, but is "lost"
+// since the handler has been suspended. When the second event is
+// signal, the first event is resumed and the second is
+// suspended. When the first event is signaled again, both events
+// are removed from Reactor.
+//
+// This test shows off the following features of Reactor:
+// - Registration
+// - Suspension
+// - Resumption
+// - Removal (while active and while suspended)
+//
+// = AUTHOR
+// Irfan Pyarali
+//
+// ============================================================================
+
+#include "ace/OS_main.h"
+
+#if defined (ACE_WIN32)
+
+#include "ace/Reactor.h"
+#include "ace/Auto_Event.h"
+#include "ace/OS_NS_unistd.h"
+
+ACE_RCSID(WFMO_Reactor, Registration, "$Id$")
+
+// Globals for this test
+int stop_test = 0;
+ACE_Reactor reactor;
+
+
+class Simple_Handler : public ACE_Event_Handler
+{
+public:
+ Simple_Handler (void);
+ // Default constructor
+
+ virtual int handle_signal (int signum, siginfo_t * = 0, ucontext_t * = 0);
+ virtual int handle_close (ACE_HANDLE handle,
+ ACE_Reactor_Mask close_mask);
+
+ ACE_Auto_Event event1_;
+ ACE_Auto_Event event2_;
+ int handle_signal_count_;
+ int handle_close_count_;
+};
+
+Simple_Handler::Simple_Handler (void)
+ : handle_signal_count_ (0),
+ handle_close_count_ (0)
+{
+}
+
+int
+Simple_Handler::handle_signal (int, siginfo_t *s, ucontext_t *)
+{
+ ACE_HANDLE handle = s->si_handle_;
+ ACE_UNUSED_ARG (handle);
+
+ this->handle_signal_count_++;
+
+ if (this->handle_signal_count_ == 1)
+ this->reactor ()->suspend_handler (event1_.handle ());
+ else if (this->handle_signal_count_ == 2)
+ {
+ this->reactor ()->resume_handler (event1_.handle ());
+ this->reactor ()->suspend_handler (event2_.handle ());
+ }
+ else if (this->handle_signal_count_ == 3)
+ {
+ this->reactor ()->remove_handler (event1_.handle (),
+ ACE_Event_Handler::NULL_MASK);
+ this->reactor ()->remove_handler (event2_.handle (),
+ ACE_Event_Handler::NULL_MASK);
+ }
+ return 0;
+}
+
+int
+Simple_Handler::handle_close (ACE_HANDLE handle,
+ ACE_Reactor_Mask)
+{
+ ACE_DEBUG ((LM_DEBUG, "Simple_Handler::handle_close handle = %d\n", handle));
+ this->handle_close_count_++;
+
+ if (this->handle_close_count_ == 1)
+ stop_test = 0;
+ else if (this->handle_close_count_ == 2)
+ stop_test = 1;
+
+ return 0;
+}
+
+// Globals for this test
+Simple_Handler simple_handler;
+
+void
+worker (void)
+{
+ ACE_DEBUG ((LM_DEBUG, "(%t) Thread creation\n"));
+ ACE_DEBUG ((LM_DEBUG, "(%t) Thread sleeping\n"));
+ ACE_OS::sleep (1);
+ ACE_DEBUG ((LM_DEBUG, "(%t) Thread signaling %d\n", simple_handler.event1_.handle()));
+ simple_handler.event1_.signal ();
+ ACE_DEBUG ((LM_DEBUG, "(%t) Thread sleeping\n"));
+ ACE_OS::sleep (1);
+ ACE_DEBUG ((LM_DEBUG, "(%t) Thread signaling %d\n", simple_handler.event1_.handle()));
+ ACE_DEBUG ((LM_DEBUG, "Note: This signal should be \"lost\" because of the suspended handler\n"));
+ simple_handler.event1_.signal ();
+ ACE_DEBUG ((LM_DEBUG, "(%t) Thread sleeping\n"));
+ ACE_OS::sleep (1);
+ ACE_DEBUG ((LM_DEBUG, "(%t) Thread resetting %d\n", simple_handler.event1_.handle()));
+ simple_handler.event1_.reset ();
+ ACE_DEBUG ((LM_DEBUG, "(%t) Thread signaling %d\n", simple_handler.event2_.handle()));
+ simple_handler.event2_.signal ();
+ ACE_DEBUG ((LM_DEBUG, "(%t) Thread sleeping\n"));
+ ACE_OS::sleep (1);
+ ACE_DEBUG ((LM_DEBUG, "(%t) Thread signaling %d\n", simple_handler.event1_.handle()));
+ simple_handler.event1_.signal ();
+ ACE_DEBUG ((LM_DEBUG, "(%t) Thread death\n"));
+}
+
+int
+ACE_TMAIN (int, ACE_TCHAR *[])
+{
+ int result = reactor.register_handler (&simple_handler,
+ simple_handler.event1_.handle ());
+ ACE_ASSERT (result == 0);
+
+ result = reactor.register_handler (&simple_handler,
+ simple_handler.event2_.handle ());
+ ACE_ASSERT (result == 0);
+
+ result = ACE_OS::thr_create ((ACE_THR_FUNC) worker, 0, 0, 0);
+ ACE_ASSERT (result == 0);
+
+ result = 0;
+ while (!stop_test && result != -1)
+ {
+ result = reactor.handle_events ();
+ }
+ return 0;
+};
+#else /* !ACE_WIN32 */
+int
+ACE_TMAIN (int, ACE_TCHAR **)
+{
+ return 0;
+}
+#endif /* ACE_WIN32 */
diff --git a/ACE/examples/Reactor/WFMO_Reactor/Registry_Changes.cpp b/ACE/examples/Reactor/WFMO_Reactor/Registry_Changes.cpp
new file mode 100644
index 00000000000..be787293e65
--- /dev/null
+++ b/ACE/examples/Reactor/WFMO_Reactor/Registry_Changes.cpp
@@ -0,0 +1,146 @@
+// $Id$
+//
+// ============================================================================
+//
+// = LIBRARY
+// examples
+//
+// = FILENAME
+// Registry_Changes.cpp
+//
+// = DESCRIPTION
+//
+// This application tests the working of Reactor when users are
+// interested in monitoring changes in the registry.
+//
+// = AUTHOR
+// Irfan Pyarali
+//
+// ============================================================================
+
+#include "ace/OS_main.h"
+
+#if defined (ACE_WIN32)
+
+#include "ace/Reactor.h"
+#include "ace/Registry.h"
+#include "ace/Auto_Event.h"
+#include "ace/OS_NS_unistd.h"
+
+ACE_RCSID(WFMO_Reactor, Registry_Changes, "$Id$")
+
+static int stop_test = 0;
+static HKEY context_to_monitor = HKEY_CURRENT_USER;
+static const ACE_TCHAR *temp_context_name = ACE_TEXT ("ACE temporary context");
+
+class Event_Handler : public ACE_Event_Handler
+{
+public:
+ Event_Handler (ACE_Reactor &reactor);
+ ~Event_Handler (void);
+ int handle_signal (int signum, siginfo_t * = 0, ucontext_t * = 0);
+ int handle_close (ACE_HANDLE handle,
+ ACE_Reactor_Mask close_mask);
+ ACE_Registry::Naming_Context &context (void);
+
+private:
+ ACE_Auto_Event event_;
+ ACE_Registry::Naming_Context context_;
+};
+
+Event_Handler::Event_Handler (ACE_Reactor &reactor)
+ : context_ (context_to_monitor)
+{
+ this->reactor (&reactor);
+
+ if (::RegNotifyChangeKeyValue (this->context_.key (), // handle of key to watch
+ FALSE, // flag for subkey notification
+ REG_NOTIFY_CHANGE_NAME, // changes to be reported
+ this->event_.handle (), // handle of signaled event
+ TRUE // flag for asynchronous reporting
+ ) != ERROR_SUCCESS)
+ ACE_ERROR ((LM_ERROR, "RegNotifyChangeKeyValue could not be setup\n"));
+
+ if (this->reactor ()->register_handler (this,
+ this->event_.handle ()) != 0)
+ ACE_ERROR ((LM_ERROR, "Registration with Reactor could not be done\n"));
+}
+
+Event_Handler::~Event_Handler (void)
+{
+}
+
+int
+Event_Handler::handle_signal (int, siginfo_t *, ucontext_t *)
+{
+ if (stop_test)
+ this->reactor ()->close ();
+ else if (::RegNotifyChangeKeyValue (this->context_.key (), // handle of key to watch
+ FALSE, // flag for subkey notification
+ REG_NOTIFY_CHANGE_NAME, // changes to be reported
+ this->event_.handle (), // handle of signaled event
+ TRUE // flag for asynchronous reporting
+ ) != ERROR_SUCCESS)
+ ACE_ERROR ((LM_ERROR,
+ "RegNotifyChangeKeyValue could not be setup\n"));
+ return 0;
+}
+
+int
+Event_Handler::handle_close (ACE_HANDLE,
+ ACE_Reactor_Mask)
+{
+ ACE_DEBUG ((LM_DEBUG, "Event_Handler removed from Reactor\n"));
+ return 0;
+}
+
+ACE_Registry::Naming_Context &
+Event_Handler::context (void)
+{
+ return this->context_;
+}
+
+void
+worker (Event_Handler *event_handler)
+{
+ ACE_DEBUG ((LM_DEBUG, "(%t) Thread creation\n"));
+ ACE_DEBUG ((LM_DEBUG, "(%t) Thread creating temporary registry entry\n"));
+
+ ACE_Registry::Naming_Context temp_context;
+ int result = event_handler->context ().bind_new_context (temp_context_name,
+ temp_context);
+
+ if (result == -1)
+ ACE_ERROR ((LM_ERROR, "Error in creating %s: %p\n", temp_context_name, "bind_new_context"));
+ else
+ {
+ ACE_DEBUG ((LM_DEBUG, "(%t) Thread sleeping\n"));
+ ACE_OS::sleep (3);
+
+ ACE_DEBUG ((LM_DEBUG, "(%t) Thread removing registry entry\n"));
+ stop_test = 1;
+ event_handler->context ().unbind_context (temp_context_name);
+ }
+}
+
+int
+ACE_TMAIN (int, ACE_TCHAR *[])
+{
+ ACE_Reactor reactor;
+ Event_Handler handler (reactor);
+
+ int result = ACE_OS::thr_create ((ACE_THR_FUNC) worker, &handler, 0, 0);
+ ACE_ASSERT (result == 0);
+
+ for (result = 0; result != -1; result = reactor.handle_events ())
+ continue;
+
+ return 0;
+}
+#else /* !ACE_WIN32 */
+int
+ACE_TMAIN (int, ACE_TCHAR **)
+{
+ return 0;
+}
+#endif /* ACE_WIN32 */
diff --git a/ACE/examples/Reactor/WFMO_Reactor/Removals.cpp b/ACE/examples/Reactor/WFMO_Reactor/Removals.cpp
new file mode 100644
index 00000000000..260b9e897ee
--- /dev/null
+++ b/ACE/examples/Reactor/WFMO_Reactor/Removals.cpp
@@ -0,0 +1,114 @@
+// $Id$
+//
+// ============================================================================
+//
+// = LIBRARY
+// examples
+//
+// = FILENAME
+// Removals.cpp
+//
+// = DESCRIPTION
+//
+// Tests the Reactor's ability to handle simultaneous events. If
+// you pass anything on the command-line, then each handler
+// requests to be removed from the Reactor after each event.
+//
+// = AUTHOR
+// Tim Harrison
+// Irfan Pyarali
+//
+// ============================================================================
+
+#include "ace/OS_main.h"
+
+#if defined (ACE_WIN32)
+
+#include "ace/Reactor.h"
+#include "ace/Service_Config.h"
+#include "ace/Event.h"
+
+ACE_RCSID(WFMO_Reactor, Removals, "$Id$")
+
+class Event_Handler : public ACE_Event_Handler
+// = TITLE
+// Generic Event Handler.
+//
+// = DESCRIPTION
+//
+// Creates event. Registers with Reactor. 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)
+ {
+ if (ACE_Reactor::instance ()->register_handler (this,
+ this->event_.handle ()) == -1)
+ ACE_ERROR ((LM_ERROR, "%p\tevent handler %d cannot be added to Reactor\n", "", event_number_));
+ this->event_.signal ();
+ }
+
+ virtual int handle_signal (int, siginfo_t *, ucontext_t *)
+ {
+ 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
+ACE_TMAIN (int argc, ACE_TCHAR *[])
+{
+ int close_down = argc > 1 ? 1 : 0;
+
+ for (size_t i = 1; i <= ACE_Reactor::instance ()->size (); i++)
+ new Event_Handler (static_cast<int> (i), close_down);
+
+ int result = 0;
+ ACE_Time_Value time (1);
+ while (1)
+ {
+ result = ACE_Reactor::instance ()->handle_events (time);
+ if (result == 0 && errno == ETIME)
+ {
+ ACE_DEBUG ((LM_DEBUG, "No more work left: timing out\n"));
+ break;
+ }
+ if (result == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "%p.\n", "main"), -1);
+ }
+ return 0;
+}
+#else /* !ACE_WIN32 */
+int
+ACE_TMAIN (int , ACE_TCHAR *[])
+{
+ return 0;
+}
+#endif /* ACE_WIN32 */
diff --git a/ACE/examples/Reactor/WFMO_Reactor/Suspended_Removals.cpp b/ACE/examples/Reactor/WFMO_Reactor/Suspended_Removals.cpp
new file mode 100644
index 00000000000..ead467146a5
--- /dev/null
+++ b/ACE/examples/Reactor/WFMO_Reactor/Suspended_Removals.cpp
@@ -0,0 +1,173 @@
+// $Id$
+//
+// ============================================================================
+//
+// = LIBRARY
+// examples
+//
+// = FILENAME
+// Suspended_Removals.cpp
+//
+// = DESCRIPTION
+//
+// Tests the Reactor's ability to handle removal of suspended
+// handles.
+//
+// = AUTHOR
+// Irfan Pyarali
+//
+// ============================================================================
+
+#include "ace/OS_main.h"
+
+#if defined (ACE_WIN32)
+
+#include "ace/Reactor.h"
+#include "ace/WFMO_Reactor.h"
+
+ACE_RCSID(WFMO_Reactor, Suspended_Removals, "$Id$")
+
+class Event_Handler : public ACE_Event_Handler
+{
+public:
+
+ ACE_HANDLE get_handle (void) const
+ {
+ return this->event_.handle ();
+ }
+
+ ACE_Event event_;
+};
+
+class ACE_WFMO_Reactor_Test
+{
+public:
+ static void check_for_valid_state (ACE_WFMO_Reactor &wfmo_reactor,
+ size_t handles_to_be_added,
+ size_t handles_to_be_suspended,
+ size_t handles_to_be_resumed,
+ size_t handles_to_be_deleted)
+ {
+ ACE_ASSERT (wfmo_reactor.handler_rep_.handles_to_be_added_ == handles_to_be_added);
+ ACE_ASSERT (wfmo_reactor.handler_rep_.handles_to_be_suspended_ == handles_to_be_suspended);
+ ACE_ASSERT (wfmo_reactor.handler_rep_.handles_to_be_resumed_ == handles_to_be_resumed);
+ ACE_ASSERT (wfmo_reactor.handler_rep_.handles_to_be_deleted_ == handles_to_be_deleted);
+ }
+};
+
+int
+ACE_TMAIN (int, ACE_TCHAR *[])
+{
+ Event_Handler handler;
+ ACE_WFMO_Reactor reactor;
+ ACE_Reactor base_reactor (&reactor);
+ ACE_Time_Value time (1);
+
+ int result =
+ reactor.register_handler (&handler);
+ ACE_ASSERT (result == 0);
+
+ ACE_WFMO_Reactor_Test::check_for_valid_state (reactor,
+ 1, 0, 0, 0);
+
+ result =
+ reactor.remove_handler (&handler,
+ ACE_Event_Handler::DONT_CALL |
+ ACE_Event_Handler::ALL_EVENTS_MASK);
+ ACE_ASSERT (result == 0);
+
+ ACE_WFMO_Reactor_Test::check_for_valid_state (reactor,
+ 1, 0, 0, 1);
+
+ result = base_reactor.run_reactor_event_loop (time);
+ ACE_ASSERT (result != -1);
+
+ ACE_WFMO_Reactor_Test::check_for_valid_state (reactor,
+ 0, 0, 0, 0);
+
+ result =
+ reactor.register_handler (&handler);
+ ACE_ASSERT (result == 0);
+
+ ACE_WFMO_Reactor_Test::check_for_valid_state (reactor,
+ 1, 0, 0, 0);
+
+ result = base_reactor.run_reactor_event_loop (time);
+ ACE_ASSERT (result != -1);
+
+ ACE_WFMO_Reactor_Test::check_for_valid_state (reactor,
+ 0, 0, 0, 0);
+
+ result =
+ reactor.suspend_handler (&handler);
+ ACE_ASSERT (result == 0);
+
+ ACE_WFMO_Reactor_Test::check_for_valid_state (reactor,
+ 0, 1, 0, 0);
+
+ result =
+ reactor.remove_handler (&handler,
+ ACE_Event_Handler::DONT_CALL |
+ ACE_Event_Handler::ALL_EVENTS_MASK);
+ ACE_ASSERT (result == 0);
+
+ ACE_WFMO_Reactor_Test::check_for_valid_state (reactor,
+ 0, 0, 0, 1);
+
+ result = base_reactor.run_reactor_event_loop (time);
+ ACE_ASSERT (result != -1);
+
+ ACE_WFMO_Reactor_Test::check_for_valid_state (reactor,
+ 0, 0, 0, 0);
+
+ result =
+ reactor.register_handler (&handler);
+ ACE_ASSERT (result == 0);
+
+ ACE_WFMO_Reactor_Test::check_for_valid_state (reactor,
+ 1, 0, 0, 0);
+
+ result =
+ reactor.suspend_handler (&handler);
+ ACE_ASSERT (result == 0);
+
+ ACE_WFMO_Reactor_Test::check_for_valid_state (reactor,
+ 1, 1, 0, 0);
+
+ result = base_reactor.run_reactor_event_loop (time);
+ ACE_ASSERT (result != -1);
+
+ ACE_WFMO_Reactor_Test::check_for_valid_state (reactor,
+ 0, 0, 0, 0);
+
+ result =
+ reactor.resume_handler (&handler);
+ ACE_ASSERT (result == 0);
+
+ ACE_WFMO_Reactor_Test::check_for_valid_state (reactor,
+ 0, 0, 1, 0);
+
+ result =
+ reactor.remove_handler (&handler,
+ ACE_Event_Handler::DONT_CALL |
+ ACE_Event_Handler::ALL_EVENTS_MASK);
+ ACE_ASSERT (result == 0);
+
+ ACE_WFMO_Reactor_Test::check_for_valid_state (reactor,
+ 0, 0, 0, 1);
+
+ result = base_reactor.run_reactor_event_loop (time);
+ ACE_ASSERT (result != -1);
+
+ ACE_WFMO_Reactor_Test::check_for_valid_state (reactor,
+ 0, 0, 0, 0);
+
+ return 0;
+}
+#else /* !ACE_WIN32 */
+int
+ACE_TMAIN (int , ACE_TCHAR *[])
+{
+ return 0;
+}
+#endif /* ACE_WIN32 */
diff --git a/ACE/examples/Reactor/WFMO_Reactor/Talker.cpp b/ACE/examples/Reactor/WFMO_Reactor/Talker.cpp
new file mode 100644
index 00000000000..32438088614
--- /dev/null
+++ b/ACE/examples/Reactor/WFMO_Reactor/Talker.cpp
@@ -0,0 +1,594 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// examples
+//
+// = FILENAME
+// Talker.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, Reactor 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_Reactor. To enable a single thread
+// to run all these events, the Proactor is integrated with the
+// Reactor.
+//
+// The test application prototypes a simple talk 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 Reactor, 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 Reactor test application has the following participants:
+//
+// . Reactor -- The Reactor demultiplexes Win32 "waitable"
+// events using WaitForMultipleObjects.
+//
+// . Proactor -- The proactor initiates and demultiplexes
+// overlapped I/O operations. The Proactor registers with the
+// Reactor 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 Reactor, thanks MicroSlush!
+//
+// . Peer_Handler -- The Peer_Handler connects to another instance
+// of test_reactor. 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 notification strategy with message queue so
+// that it is notified when the STDIN_Handler posts a message
+// onto the queue.
+//
+// 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 Reactor. 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 Reactor.
+//
+// The main thread of control waits in the Reactor.
+//
+// . STDIN events -- When the STDIN_Handler thread reads from
+// STDIN, it puts the message on Peer_Handler's message queue. It
+// then returns to reading from STDIN.
+//
+// . Message enqueue -- The Reactor thread wakes up and calls
+// Peer_Handler::handle_output. 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 Reactor event loop.
+//
+// . Send complete event -- When a proactive send is complete, the
+// Proactor is notified by the Reactor. 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
+// Reactor event loop.
+//
+// . 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 Reactor. 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 Reactor. Exit_Hook::handle_signal sets a flag
+// to end the event loop and returns. This will cause the
+// application to exit.
+//
+//
+// To run example, start an instance of the test with an optional
+// local port argument (as the acceptor). Start the other instance
+// with -h <hostname> and -p <server port>. Type in either the
+// client or server windows and your message should show up in the
+// other window. Control C to exit.
+//
+// = AUTHOR
+// Tim Harrison
+// Irfan Pyarali
+//
+// ============================================================================
+
+#include "ace/OS_main.h"
+
+#if defined (ACE_WIN32)
+
+#include "ace/Reactor.h"
+#include "ace/Reactor_Notification_Strategy.h"
+#include "ace/WIN32_Proactor.h"
+#include "ace/Proactor.h"
+#include "ace/SOCK_Connector.h"
+#include "ace/SOCK_Acceptor.h"
+#include "ace/Get_Opt.h"
+#include "ace/Service_Config.h"
+#include "ace/Task.h"
+#include "ace/OS_NS_unistd.h"
+
+ACE_RCSID(WFMO_Reactor, Talker, "$Id$")
+
+typedef ACE_Task<ACE_MT_SYNCH> MT_TASK;
+
+class Peer_Handler : public MT_TASK, public ACE_Handler
+// = TITLE
+// Connect to a server. Receive messages from STDIN_Handler
+// and forward them to the server using proactive I/O.
+{
+public:
+ // = Initialization methods.
+ Peer_Handler (int argc, ACE_TCHAR *argv[]);
+ ~Peer_Handler (void);
+
+ 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 void handle_read_stream (const ACE_Asynch_Read_Stream::Result &result);
+ // This method will be called when an asynchronous read completes on a stream.
+ // 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 void handle_write_stream (const ACE_Asynch_Write_Stream::Result &result);
+ // This method will be called when an asynchronous write completes on a strea_m.
+ // One of our asynchronous writes to the remote peer has completed.
+ // Make sure it succeeded and then delete the message.
+
+ virtual ACE_HANDLE handle (void) const;
+ // Get the I/O handle used by this <handler>. This method will be
+ // called by the ACE_Asynch_* classes when an ACE_INVALID_HANDLE is
+ // passed to <open>.
+
+ void handle (ACE_HANDLE);
+ // Set the ACE_HANDLE value for this Handler.
+
+ virtual int handle_close (ACE_HANDLE, ACE_Reactor_Mask);
+ // We've been removed from the Reactor.
+
+ virtual int handle_output (ACE_HANDLE fd);
+ // Called when output events should start. Note that this is
+ // automatically invoked by the
+ // <ACE_Reactor_Notificiation_Strategy>.
+
+private:
+ ACE_SOCK_Stream stream_;
+ // Socket that we have connected to the server.
+
+ ACE_Reactor_Notification_Strategy strategy_;
+ // The strategy object that the reactor uses to notify us when
+ // something is added to the queue.
+
+ // = Remote peer info.
+ ACE_TCHAR *host_;
+ // Name of remote host.
+
+ u_short port_;
+ // Port number for remote host.
+
+ ACE_Asynch_Read_Stream rd_stream_;
+ // Read stream
+
+ ACE_Asynch_Write_Stream wr_stream_;
+ // Write stream
+
+ ACE_Message_Block mb_;
+ // Message Block for reading from the network
+};
+
+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);
+ // Initialization.
+
+ virtual int open (void * = 0);
+ // Activate object.
+
+ virtual int close (u_long = 0);
+ // Shut down.
+
+ int svc (void);
+ // Thread runs here as an active object.
+
+ int handle_close (ACE_HANDLE,
+ ACE_Reactor_Mask);
+
+private:
+ static void handler (int signum);
+ // Handle a ^C. (Do nothing, this just illustrates how we can catch
+ // signals along with the other things).
+
+ void register_thread_exit_hook (void);
+ // Helper function to register with the Reactor 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.
+
+ MT_TASK &ph_;
+ // Send all input to ph_.
+
+ ACE_HANDLE thr_handle_;
+ // Handle of our thread.
+};
+
+Peer_Handler::Peer_Handler (int argc, ACE_TCHAR *argv[])
+ : strategy_ (ACE_Reactor::instance (),
+ this,
+ ACE_Event_Handler::WRITE_MASK),
+ host_ (0),
+ port_ (ACE_DEFAULT_SERVER_PORT),
+ mb_ (BUFSIZ)
+{
+ // This code sets up the message to notify us when a new message is
+ // added to the queue. Actually, the queue notifies Reactor which
+ // then notifies us.
+ this->msg_queue ()->notification_strategy (&this->strategy_);
+
+ ACE_Get_Opt get_opt (argc, argv, ACE_TEXT("h:p:"));
+ int c;
+
+ while ((c = get_opt ()) != EOF)
+ {
+ switch (c)
+ {
+ case 'h':
+ host_ = get_opt.opt_arg ();
+ break;
+ case 'p':
+ port_ = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ }
+ }
+}
+
+Peer_Handler::~Peer_Handler (void)
+{
+}
+
+// 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, "(%t) 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, "(%t) accepted.\n"));
+ }
+
+ int result = this->rd_stream_.open (*this);
+ if (result != 0)
+ return result;
+
+ result = this->wr_stream_.open (*this);
+ if (result != 0)
+ return result;
+
+ result = this->rd_stream_.read (this->mb_,
+ this->mb_.size ());
+ return result;
+}
+
+// One of our asynchronous writes to the remote peer has completed.
+// Make sure it succeeded and then delete the message.
+
+void
+Peer_Handler::handle_write_stream (const ACE_Asynch_Write_Stream::Result &result)
+{
+ if (result.bytes_transferred () <= 0)
+ ACE_DEBUG ((LM_DEBUG, "(%t) %p bytes = %d\n", "Message failed",
+ result.bytes_transferred ()));
+
+ // This was allocated by the STDIN_Handler, queued, dequeued, passed
+ // to the proactor, and now passed back to us.
+ result.message_block ().release ();
+}
+
+// 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.
+
+
+void
+Peer_Handler::handle_read_stream (const ACE_Asynch_Read_Stream::Result &result)
+{
+ if (result.bytes_transferred () > 0 &&
+ this->mb_.length () > 0)
+ {
+ this->mb_.rd_ptr ()[result.bytes_transferred ()] = '\0';
+ // Print out the message received from the server.
+ ACE_DEBUG ((LM_DEBUG, "%s", this->mb_.rd_ptr ()));
+ }
+ else
+ {
+ // 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_Reactor::end_event_loop();
+ return;
+ }
+
+ // Reset pointers
+ this->mb_.wr_ptr (this->mb_.wr_ptr () - result.bytes_transferred ());
+
+ // Start off another read
+ if (this->rd_stream_.read (this->mb_,
+ this->mb_.size ()) == -1)
+ ACE_ERROR ((LM_ERROR, "%p Read initiate.\n", "Peer_Handler"));
+}
+
+// This is so the Proactor can get our handle.
+ACE_HANDLE
+Peer_Handler::handle (void) const
+{
+ return this->stream_.get_handle ();
+}
+
+void
+Peer_Handler::handle (ACE_HANDLE handle)
+{
+ this->stream_.set_handle (handle);
+}
+
+// We've been removed from the Reactor.
+int
+Peer_Handler::handle_close (ACE_HANDLE, ACE_Reactor_Mask)
+{
+ ACE_DEBUG ((LM_DEBUG, "(%t) Peer_Handler closing down\n"));
+ return 0;
+}
+
+// New stuff added to the message queue. Try to dequeue a message.
+int
+Peer_Handler::handle_output (ACE_HANDLE)
+{
+ ACE_Message_Block *mb;
+
+ ACE_Time_Value tv (ACE_Time_Value::zero);
+
+ // Forward the message to the remote peer receiver.
+ if (this->getq (mb, &tv) != -1)
+ {
+ if (this->wr_stream_.write (*mb,
+ mb->length ()) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "%p Write initiate.\n", "Peer_Handler"), -1);
+ }
+ return 0;
+}
+
+void
+STDIN_Handler::handler (int signum)
+{
+ ACE_DEBUG ((LM_DEBUG, "(%t) 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);
+ // Note that this call will first enqueue mb onto the peer
+ // handler's message queue, which will then turn around and
+ // notify the Reactor via the Notification_Strategy. This
+ // will subsequently signal the Peer_Handler, which will
+ // react by calling back to its handle_output() method,
+ // which dequeues the message and sends it to the peer
+ // across the network.
+ this->ph_.putq (mb);
+ }
+ else
+ {
+ mb->release ();
+ break;
+ }
+ }
+
+ // handle_signal will get called on the main proactor thread since
+ // we just exited and the main thread is waiting on our thread exit.
+ return 0;
+}
+
+// Register an exit hook with the reactor.
+
+void
+STDIN_Handler::register_thread_exit_hook (void)
+{
+ // Get a real handle to our thread.
+ ACE_Thread_Manager::instance ()->thr_self (this->thr_handle_);
+
+ // Register ourselves to get called back when our thread exits.
+
+ if (ACE_Reactor::instance ()->
+ register_handler (this, this->thr_handle_) == -1)
+ ACE_ERROR ((LM_ERROR, "Exit_Hook Register failed.\n"));
+}
+
+// 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 *si, ucontext_t *)
+{
+ if (si != 0)
+ {
+ ACE_ASSERT (this->thr_handle_ == si->si_handle_);
+ ACE_Reactor::end_event_loop ();
+ }
+ return 0;
+}
+
+int
+STDIN_Handler::handle_close (ACE_HANDLE,
+ ACE_Reactor_Mask)
+{
+ delete this;
+ return 0;
+}
+
+int
+ACE_TMAIN (int argc, ACE_TCHAR *argv[])
+{
+ // Let the proactor know that it will be used with Reactor
+ // Create specific proactor
+ ACE_WIN32_Proactor win32_proactor (0, 1);
+ // Get the interface proactor
+ ACE_Proactor proactor (&win32_proactor);
+ // Put it as the instance.
+ ACE_Proactor::instance (&proactor);
+
+ // 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 =
+ new STDIN_Handler (peer_handler);
+
+ // Spawn thread.
+ if (stdin_handler->open () == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "%p open failed, errno = %d.\n",
+ "stdin_handler", errno), 0);
+
+ // Register proactor with Reactor so that we can demultiplex
+ // "waitable" events and I/O operations from a single thread.
+ if (ACE_Reactor::instance ()->register_handler
+ (ACE_Proactor::instance ()->implementation ()) != 0)
+ ACE_ERROR_RETURN ((LM_ERROR, "%p failed to register Proactor.\n",
+ argv[0]), -1);
+
+ // Run main event demultiplexor.
+ ACE_Reactor::run_event_loop ();
+
+ // Remove proactor with Reactor.
+ if (ACE_Reactor::instance ()->remove_handler
+ (ACE_Proactor::instance ()->implementation (), ACE_Event_Handler::DONT_CALL) != 0)
+ ACE_ERROR_RETURN ((LM_ERROR, "%p failed to register Proactor.\n",
+ argv[0]), -1);
+
+ return 0;
+}
+#else /* !ACE_WIN32 */
+int
+ACE_TMAIN (int , ACE_TCHAR *[])
+{
+ return 0;
+}
+#endif /* ACE_WIN32 */
diff --git a/ACE/examples/Reactor/WFMO_Reactor/Timeouts.cpp b/ACE/examples/Reactor/WFMO_Reactor/Timeouts.cpp
new file mode 100644
index 00000000000..8cc37a940bc
--- /dev/null
+++ b/ACE/examples/Reactor/WFMO_Reactor/Timeouts.cpp
@@ -0,0 +1,83 @@
+// $Id$
+//
+// ============================================================================
+//
+// = LIBRARY
+// examples
+//
+// = FILENAME
+// Timeouts.cpp
+//
+// = DESCRIPTION
+//
+// This example application shows how to write Reactor event
+// loops that handle events for some fixed amount of time.
+//
+// Run this example (without arguments) to see the timers
+// expire. The order should be:
+//
+// foo, bar, foo, bar, foo, foo, bar, foo, bar, foo
+//
+// = AUTHOR
+// Tim Harrison
+// Irfan Pyarali
+//
+// ============================================================================
+
+#include "ace/Reactor.h"
+#include "ace/Service_Config.h"
+#include "ace/OS_main.h"
+
+ACE_RCSID(WFMO_Reactor, Timeouts, "$Id$")
+
+class Timeout_Handler : public ACE_Event_Handler
+// = TITLE
+// Generic timeout handler.
+{
+public:
+ Timeout_Handler (void)
+ : count_ (0) {}
+
+ virtual int handle_timeout (const ACE_Time_Value &tv,
+ const void *arg)
+ // Print out when timeouts occur.
+ {
+ ACE_UNUSED_ARG(tv);
+ ACE_DEBUG ((LM_DEBUG,
+ "%d timeout occurred for %s.\n",
+ ++count_,
+ (char *) arg));
+ return 0;
+ }
+
+private:
+ int count_;
+};
+
+int
+ACE_TMAIN (int, ACE_TCHAR *[])
+{
+ Timeout_Handler handler;
+
+ // Register a 3 second timer.
+ ACE_Time_Value bar_tv (3);
+ ACE_Reactor::instance ()->schedule_timer (&handler,
+ (void *) "Bar",
+ bar_tv,
+ bar_tv);
+
+ // Register a 2 second timer.
+ ACE_Time_Value foo_tv (2);
+ ACE_Reactor::instance ()->schedule_timer (&handler,
+ (void *) "Foo",
+ foo_tv,
+ foo_tv);
+ // Handle events for 12 seconds.
+ ACE_Time_Value run_time (12);
+ if (ACE_Reactor::run_event_loop(run_time) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "%p.\n", "main"), -1);
+
+ ACE_Reactor::instance ()->cancel_timer(&handler);
+
+ return 0;
+}
diff --git a/ACE/examples/Reactor/WFMO_Reactor/WFMO_Reactor.mpc b/ACE/examples/Reactor/WFMO_Reactor/WFMO_Reactor.mpc
new file mode 100644
index 00000000000..eec632ee696
--- /dev/null
+++ b/ACE/examples/Reactor/WFMO_Reactor/WFMO_Reactor.mpc
@@ -0,0 +1,118 @@
+// -*- MPC -*-
+// $Id$
+
+project(*Abandoned): aceexe, wfmo {
+ exename = abandoned
+ Source_Files {
+ Abandoned.cpp
+ }
+}
+
+project(*APC): aceexe, wfmo {
+ avoids += wince
+ exename = apc
+ Source_Files {
+ APC.cpp
+ }
+}
+
+project(*Console_Input): aceexe, wfmo {
+ exename = console_input
+ Source_Files {
+ Console_Input.cpp
+ }
+}
+
+project(*Directory_Changes): aceexe, wfmo {
+ exename = directory_changes
+ Source_Files {
+ Directory_Changes.cpp
+ }
+}
+
+project(*Exceptions): aceexe, wfmo {
+ exename = exceptions
+ Source_Files {
+ Exceptions.cpp
+ }
+}
+
+project(*Handle_Close): aceexe, wfmo {
+ exename = handle_close
+ Source_Files {
+ Handle_Close.cpp
+ }
+}
+
+project(*Multithreading): aceexe, wfmo {
+ exename = multithreading
+ Source_Files {
+ Multithreading.cpp
+ }
+}
+
+project(*Network_Events): aceexe, wfmo {
+ exename = network_events
+ Source_Files {
+ Network_Events.cpp
+ }
+}
+
+project(*Prerun_State_Changes): aceexe, wfmo {
+ exename = prerun_state_changes
+ Source_Files {
+ Prerun_State_Changes.cpp
+ }
+}
+
+project(*Registration): aceexe, wfmo {
+ exename = registration
+ Source_Files {
+ Registration.cpp
+ }
+}
+
+project(*Registry_Changes): aceexe, wfmo {
+ avoids += ace_for_tao wince
+ exename = registry_changes
+ Source_Files {
+ Registry_Changes.cpp
+ }
+}
+
+project(*Removals): aceexe, wfmo {
+ exename = removals
+ Source_Files {
+ Removals.cpp
+ }
+}
+
+project(*Suspended_Removals): aceexe, wfmo {
+ exename = suspended_removals
+ Source_Files {
+ Suspended_Removals.cpp
+ }
+}
+
+project(*Talker): aceexe, wfmo {
+ avoids += ace_for_tao wince
+ exename = talker
+ Source_Files {
+ Talker.cpp
+ }
+}
+
+project(*Timeouts): aceexe, wfmo {
+ exename = timeouts
+ Source_Files {
+ Timeouts.cpp
+ }
+}
+
+project(*Window_Messages): aceexe, wfmo {
+ avoids += ace_for_tao wince
+ exename = window_messages
+ Source_Files {
+ Window_Messages.cpp
+ }
+}
diff --git a/ACE/examples/Reactor/WFMO_Reactor/Window_Messages.cpp b/ACE/examples/Reactor/WFMO_Reactor/Window_Messages.cpp
new file mode 100644
index 00000000000..f5a1994168c
--- /dev/null
+++ b/ACE/examples/Reactor/WFMO_Reactor/Window_Messages.cpp
@@ -0,0 +1,100 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// examples
+//
+// = FILENAME
+// Window_Messages.cpp
+//
+// = DESCRIPTION
+//
+// Tests the Msg_WFMO_Reactor's ability to handle regular events
+// and window messages.
+//
+// = AUTHOR
+//
+// Irfan Pyarali <irfan@cs.wustl.edu>
+//
+// ============================================================================
+
+#include "ace/OS_main.h"
+
+#if defined (ACE_WIN32)
+
+#include "ace/Msg_WFMO_Reactor.h"
+#include "ace/Reactor.h"
+#include "ace/Auto_Ptr.h"
+#include "ace/Auto_Event.h"
+
+ACE_RCSID(WFMO_Reactor, Window_Messages, "$Id$")
+
+class Event_Handler : public ACE_Event_Handler
+{
+public:
+ int handle_signal (int signum, siginfo_t * = 0, ucontext_t * = 0);
+
+ ACE_Auto_Event handle_;
+ int iterations_;
+};
+
+int
+Event_Handler::handle_signal (int, siginfo_t *, ucontext_t *)
+{
+ --this->iterations_;
+
+ if (this->iterations_ == 0)
+ ACE_Reactor::end_event_loop ();
+
+ return 0;
+}
+
+static Event_Handler *global_event_handler;
+
+void WINAPI
+timer_callback (HWND,
+ UINT,
+ UINT,
+ DWORD dwTime)
+{
+ ACE_DEBUG ((LM_DEBUG, "(%t) timeout occured @ %u\n", dwTime));
+
+ global_event_handler->handle_.signal ();
+}
+
+int
+ACE_TMAIN (int, ACE_TCHAR*[])
+{
+ // Manage memory automagically.
+ ACE_Reactor_Impl *impl = new ACE_Msg_WFMO_Reactor;
+ auto_ptr<ACE_Reactor> reactor (new ACE_Reactor (impl, 1));
+ ACE_Reactor::instance (reactor.get ());
+
+ Event_Handler event_handler;
+ global_event_handler = &event_handler;
+
+ event_handler.iterations_ = 5;
+ int result = ACE_Reactor::instance ()->register_handler (&event_handler,
+ event_handler.handle_.handle ());
+ ACE_ASSERT (result == 0);
+
+ ACE_Time_Value timeout (1);
+ result = ::SetTimer (NULL, // handle of window for timer messages
+ 0, // timer identifier
+ timeout.msec (), // time-out value
+ (TIMERPROC) &timer_callback // address of timer procedure
+ );
+ ACE_ASSERT (result != 0);
+
+ ACE_Reactor::run_event_loop ();
+
+ return 0;
+}
+#else /* !ACE_WIN32 */
+int
+ACE_TMAIN (int , ACE_TCHAR *[])
+{
+ return 0;
+}
+#endif /* ACE_WIN32 */
diff --git a/ACE/examples/Reactor/WFMO_Reactor/run_test.pl b/ACE/examples/Reactor/WFMO_Reactor/run_test.pl
new file mode 100755
index 00000000000..cc445c64043
--- /dev/null
+++ b/ACE/examples/Reactor/WFMO_Reactor/run_test.pl
@@ -0,0 +1,68 @@
+eval '(exit $?0)' && eval 'exec perl -S $0 ${1+"$@"}'
+ & eval 'exec perl -S $0 $argv:q'
+ if 0;
+
+# $Id$
+# -*- perl -*-
+
+use lib '../../../bin';
+use PerlACE::Run_Test;
+
+#
+# These tests only run on Win32
+#
+if ($^O ne "MSWin32")
+{
+ exit;
+}
+
+$test_timeout = 60;
+
+@tests =
+ (
+ "Abandoned",
+ "APC",
+# "Console_Input", # This test is interactive
+ "Directory_Changes",
+ "Exceptions",
+ "Handle_Close",
+ "Multithreading",
+# "Network_Events", # This test is interactive
+ "Prerun_State_Changes",
+ "Registration",
+ "Registry_Changes",
+ "Removals",
+ "Suspended_Removals",
+# "Talker", # This test is interactive
+ "Timeouts",
+ "Window_Messages",
+ );
+
+for $test (@tests)
+{
+ print STDOUT "\n________________________________________\n";
+ print STDOUT "\nStarting test \"$test\"";
+ print STDOUT "\n________________________________________\n\n";
+
+ $test_process = new PerlACE::Process ($test);
+
+ if (! -x $test_process->Executable ()) {
+ print STDERR "Error: " . $test_process->Executable () .
+ " does not exist or is not runnable\n";
+ }
+ else
+ {
+ $test_process->Spawn ();
+ $test_result = $test_process->WaitKill ($test_timeout);
+
+ if ($test_result != 0)
+ {
+ print STDERR "\n________________________________________\n";
+ print STDERR "\nERROR: \"$test\" returned $test_result";
+ print STDERR "\n________________________________________\n";
+ }
+ }
+ print STDOUT "\n________________________________________\n";
+ print STDOUT "\n\"$test\" completed";
+ print STDOUT "\n________________________________________\n";
+}