summaryrefslogtreecommitdiff
path: root/ACE/netsvcs/clients
diff options
context:
space:
mode:
authorWilliam R. Otte <wotte@dre.vanderbilt.edu>2006-07-24 15:50:30 +0000
committerWilliam R. Otte <wotte@dre.vanderbilt.edu>2006-07-24 15:50:30 +0000
commitc44379cc7d9c7aa113989237ab0f56db12aa5219 (patch)
tree66a84b20d47f2269d8bdc6e0323f338763424d3a /ACE/netsvcs/clients
parent3aff90f4a822fcf5d902bbfbcc9fa931d6191a8c (diff)
downloadATCD-c44379cc7d9c7aa113989237ab0f56db12aa5219.tar.gz
Repo restructuring
Diffstat (limited to 'ACE/netsvcs/clients')
-rw-r--r--ACE/netsvcs/clients/Logger/Logger.mpc22
-rw-r--r--ACE/netsvcs/clients/Logger/Makefile.am58
-rw-r--r--ACE/netsvcs/clients/Logger/README18
-rw-r--r--ACE/netsvcs/clients/Logger/direct_logging.cpp84
-rw-r--r--ACE/netsvcs/clients/Logger/indirect_logging.cpp60
-rw-r--r--ACE/netsvcs/clients/Makefile.am14
-rw-r--r--ACE/netsvcs/clients/Naming/Client/Client.mpc21
-rw-r--r--ACE/netsvcs/clients/Naming/Client/Client_Test.cpp651
-rw-r--r--ACE/netsvcs/clients/Naming/Client/Client_Test.h13
-rw-r--r--ACE/netsvcs/clients/Naming/Client/Makefile.am59
-rw-r--r--ACE/netsvcs/clients/Naming/Client/README123
-rw-r--r--ACE/netsvcs/clients/Naming/Client/main.cpp80
-rw-r--r--ACE/netsvcs/clients/Naming/Client/svc.conf7
-rw-r--r--ACE/netsvcs/clients/Naming/Client/svc2.conf9
-rw-r--r--ACE/netsvcs/clients/Naming/Dump_Restore/Dump_Restore.cpp467
-rw-r--r--ACE/netsvcs/clients/Naming/Dump_Restore/Dump_Restore.h86
-rw-r--r--ACE/netsvcs/clients/Naming/Dump_Restore/Dump_Restore.mpc21
-rw-r--r--ACE/netsvcs/clients/Naming/Dump_Restore/Makefile.am59
-rw-r--r--ACE/netsvcs/clients/Naming/Dump_Restore/README66
-rw-r--r--ACE/netsvcs/clients/Naming/Dump_Restore/createfile.cpp34
-rw-r--r--ACE/netsvcs/clients/Naming/Dump_Restore/main.cpp26
-rw-r--r--ACE/netsvcs/clients/Naming/Makefile.am14
-rw-r--r--ACE/netsvcs/clients/README8
-rw-r--r--ACE/netsvcs/clients/Tokens/Makefile.am17
-rw-r--r--ACE/netsvcs/clients/Tokens/README34
-rw-r--r--ACE/netsvcs/clients/Tokens/collection/Makefile.am18
-rw-r--r--ACE/netsvcs/clients/Tokens/collection/README25
-rw-r--r--ACE/netsvcs/clients/Tokens/collection/collection.cpp210
-rw-r--r--ACE/netsvcs/clients/Tokens/collection/rw_locks.cpp173
-rw-r--r--ACE/netsvcs/clients/Tokens/deadlock/Makefile.am19
-rw-r--r--ACE/netsvcs/clients/Tokens/deadlock/README98
-rw-r--r--ACE/netsvcs/clients/Tokens/deadlock/deadlock_detection_test.cpp340
-rw-r--r--ACE/netsvcs/clients/Tokens/invariant/Makefile.am20
-rw-r--r--ACE/netsvcs/clients/Tokens/invariant/README27
-rw-r--r--ACE/netsvcs/clients/Tokens/invariant/invariant.cpp196
-rw-r--r--ACE/netsvcs/clients/Tokens/manual/Makefile.am24
-rw-r--r--ACE/netsvcs/clients/Tokens/manual/README67
-rw-r--r--ACE/netsvcs/clients/Tokens/manual/manual.cpp365
-rw-r--r--ACE/netsvcs/clients/Tokens/mutex/Makefile.am21
-rw-r--r--ACE/netsvcs/clients/Tokens/mutex/README23
-rw-r--r--ACE/netsvcs/clients/Tokens/mutex/test_mutex.cpp142
-rw-r--r--ACE/netsvcs/clients/Tokens/rw_lock/Makefile.am20
-rw-r--r--ACE/netsvcs/clients/Tokens/rw_lock/README40
-rw-r--r--ACE/netsvcs/clients/Tokens/rw_lock/rw_locks.cpp252
44 files changed, 4131 insertions, 0 deletions
diff --git a/ACE/netsvcs/clients/Logger/Logger.mpc b/ACE/netsvcs/clients/Logger/Logger.mpc
new file mode 100644
index 00000000000..e4dbe0a0046
--- /dev/null
+++ b/ACE/netsvcs/clients/Logger/Logger.mpc
@@ -0,0 +1,22 @@
+// -*- MPC -*-
+// $Id$
+
+project(direct logging) : aceexe {
+ avoids += ace_for_tao
+ exename = direct_logging
+ libs += netsvcs
+ after += netsvcs
+ Source_Files {
+ direct_logging.cpp
+ }
+}
+
+project(indirect logging) : aceexe {
+ avoids += ace_for_tao
+ exename = indirect_logging
+ libs += netsvcs
+ after += netsvcs
+ Source_Files {
+ indirect_logging.cpp
+ }
+}
diff --git a/ACE/netsvcs/clients/Logger/Makefile.am b/ACE/netsvcs/clients/Logger/Makefile.am
new file mode 100644
index 00000000000..8c3ae8decb3
--- /dev/null
+++ b/ACE/netsvcs/clients/Logger/Makefile.am
@@ -0,0 +1,58 @@
+## 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.direct_logging.am
+
+if !BUILD_ACE_FOR_TAO
+noinst_PROGRAMS += direct_logging
+
+direct_logging_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+direct_logging_SOURCES = \
+ direct_logging.cpp
+
+direct_logging_LDADD = \
+ $(top_builddir)/netsvcs/lib/libnetsvcs.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_ACE_FOR_TAO
+
+## Makefile.indirect_logging.am
+
+if !BUILD_ACE_FOR_TAO
+noinst_PROGRAMS += indirect_logging
+
+indirect_logging_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+indirect_logging_SOURCES = \
+ indirect_logging.cpp
+
+indirect_logging_LDADD = \
+ $(top_builddir)/netsvcs/lib/libnetsvcs.la \
+ $(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/netsvcs/clients/Logger/README b/ACE/netsvcs/clients/Logger/README
new file mode 100644
index 00000000000..87e324ab0d8
--- /dev/null
+++ b/ACE/netsvcs/clients/Logger/README
@@ -0,0 +1,18 @@
+This directory contains two sample logging applications that implement
+and test the ACE distributed logging service.
+
+ . indirect_logging.cpp
+
+ This program talks to the ACE Client Logging Daemon on
+ the localhost, which forwards the messages to Server
+ Logging Daemon. The Client Logging Daemon and Server
+ Logging Daemon both must be started before you can run
+ this test.
+
+ . direct_logging.cpp
+
+ This program talks directly to the Server Logging
+ Daemon. The Server Logging Daemon must be started
+ before you can run this test.
+
+To start these daemons, please check out the ../../servers/ directory.
diff --git a/ACE/netsvcs/clients/Logger/direct_logging.cpp b/ACE/netsvcs/clients/Logger/direct_logging.cpp
new file mode 100644
index 00000000000..4ed5e67aef3
--- /dev/null
+++ b/ACE/netsvcs/clients/Logger/direct_logging.cpp
@@ -0,0 +1,84 @@
+// $Id$
+
+// This program sends logging records directly to the server, rather
+// than going through the client logging daemon.
+
+#include "ace/SOCK_Connector.h"
+#include "ace/Log_Record.h"
+#include "ace/Log_Msg.h"
+#include "ace/OS_NS_time.h"
+#include "ace/OS_NS_stdlib.h"
+#include "ace/OS_NS_unistd.h"
+#include "ace/CDR_Stream.h"
+
+ACE_RCSID(Logger, direct_logging, "$Id$")
+
+static u_short LOGGER_PORT = ACE_DEFAULT_SERVER_PORT;
+static const ACE_TCHAR *const LOGGER_HOST = ACE_DEFAULT_SERVER_HOST;
+static const ACE_TCHAR *const DATA = ACE_TEXT ("hello world\n");
+
+int
+ACE_TMAIN (int argc, ACE_TCHAR *argv[])
+{
+ u_short logger_port = argc > 1 ? ACE_OS::atoi (argv[1]) : LOGGER_PORT;
+ const ACE_TCHAR *logger_host = argc > 2 ? argv[2] : LOGGER_HOST;
+
+ ACE_SOCK_Stream logger;
+ ACE_SOCK_Connector connector;
+ ACE_INET_Addr addr (logger_port, logger_host);
+ ACE_Log_Record log_record (LM_DEBUG,
+ ACE_OS::time ((time_t *) 0),
+ ACE_OS::getpid ());
+
+ if (connector.connect (logger, addr) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "open"), -1);
+
+ log_record.msg_data (DATA);
+ const size_t max_payload_size =
+ 4 // type()
+ + 8 // timestamp
+ + 4 // process id
+ + 4 // data length
+ + ACE_Log_Record::MAXLOGMSGLEN // data
+ + ACE_CDR::MAX_ALIGNMENT; // padding;
+
+ // Insert contents of <log_record> into payload stream.
+ ACE_OutputCDR payload (max_payload_size);
+ payload << log_record;
+
+ // Get the number of bytes used by the CDR stream.
+ ACE_CDR::ULong length = payload.total_length ();
+
+ // Send a header so the receiver can determine the byte order and
+ // size of the incoming CDR stream.
+ ACE_OutputCDR header (ACE_CDR::MAX_ALIGNMENT + 8);
+ header << ACE_OutputCDR::from_boolean (ACE_CDR_BYTE_ORDER);
+
+ // Store the size of the payload that follows
+ header << ACE_CDR::ULong (length);
+
+ // Use an iovec to send both buffer and payload simultaneously.
+ iovec iov[2];
+ iov[0].iov_base = header.begin ()->rd_ptr ();
+ iov[0].iov_len = 8;
+ iov[1].iov_base = payload.begin ()->rd_ptr ();
+ iov[1].iov_len = length;
+
+ if (logger.sendv_n (iov, 2) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "send"), -1);
+ else if (logger.close () == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "close"), -1);
+
+#if defined (ACE_WIN32)
+ // !!Important, Winsock is broken in that if you don't close
+ // down the connection before exiting main, you'll lose data.
+ // More over, your server might get "Access Violation" from
+ // within Winsock functions.
+
+ // Here we close down the connection to Logger by redirecting
+ // the logging destination back to stderr.
+ ACE_LOG_MSG->open (0, ACE_Log_Msg::STDERR, 0);
+#endif /* ACE_WIN32 */
+
+ return 0;
+}
diff --git a/ACE/netsvcs/clients/Logger/indirect_logging.cpp b/ACE/netsvcs/clients/Logger/indirect_logging.cpp
new file mode 100644
index 00000000000..40cd0d61e10
--- /dev/null
+++ b/ACE/netsvcs/clients/Logger/indirect_logging.cpp
@@ -0,0 +1,60 @@
+// $Id$
+
+// This is a simple test that sends logging records to the Client
+// Logging Daemon running on the localhost. This daemon then forwards
+// them to the Server Logging Daemon. If there is no Server Logging
+// Daemon, the logging records will be written to stderr.
+
+#include "ace/OS_NS_time.h"
+#include "ace/OS_NS_stdlib.h"
+#include "ace/Log_Msg.h"
+#include "ace/Log_Record.h"
+
+ACE_RCSID(Logger, indirect_logging, "$Id$")
+
+int
+ACE_TMAIN (int argc, ACE_TCHAR *argv[])
+{
+ const ACE_TCHAR *prog_name = argv[0];
+ int iterations = argc < 2 ? 10 : ACE_OS::atoi (argv[1]);
+ const ACE_TCHAR *logger_key = argc < 3 ? ACE_DEFAULT_LOGGER_KEY : argv[2];
+ int verbose = argc < 4 ? 0 : ACE_Log_Msg::VERBOSE;
+
+ ACE_OS::srand ((u_int) ACE_OS::time (0));
+
+ if (ACE_LOG_MSG->open (prog_name, ACE_Log_Msg::LOGGER, logger_key) == -1)
+ {
+ ACE_ERROR ((LM_ERROR, "Cannot open logger, using STDERR\n"));
+
+ if (ACE_LOG_MSG->open (prog_name, ACE_Log_Msg::STDERR | verbose) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "Cannot open logger\n"), -1);
+ }
+
+ ACE_DEBUG ((LM_STARTUP, "starting up the test\n"));
+
+ for (int i = 0; i < iterations; i++)
+ {
+ size_t priority = ACE_OS::rand () % int (LM_MAX);
+ ACE_POW (priority);
+ ACE_Log_Priority log_priority = ACE_Log_Priority (priority);
+ ACE_DEBUG ((log_priority,
+ "random message %s (%d)...\n",
+ ACE_Log_Record::priority_name (log_priority),
+ priority));
+ }
+
+ ACE_DEBUG ((LM_SHUTDOWN, "closing down the test\n"));
+
+#if defined (ACE_WIN32)
+ // !!Important, Winsock is broken in that if you don't close
+ // down the connection before exiting main, you'll lose data.
+ // More over, your server might get "Access Violation" from
+ // within Winsock functions.
+
+ // Here we close down the connection to Logger by redirecting
+ // the logging destination back to stderr.
+ ACE_LOG_MSG->open (0, ACE_Log_Msg::STDERR, 0);
+#endif /* ACE_WIN32 */
+
+ return 0;
+}
diff --git a/ACE/netsvcs/clients/Makefile.am b/ACE/netsvcs/clients/Makefile.am
new file mode 100644
index 00000000000..c959505ff73
--- /dev/null
+++ b/ACE/netsvcs/clients/Makefile.am
@@ -0,0 +1,14 @@
+## 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 = \
+ Logger \
+ Naming
+
diff --git a/ACE/netsvcs/clients/Naming/Client/Client.mpc b/ACE/netsvcs/clients/Naming/Client/Client.mpc
new file mode 100644
index 00000000000..54d828b8774
--- /dev/null
+++ b/ACE/netsvcs/clients/Naming/Client/Client.mpc
@@ -0,0 +1,21 @@
+// -*- MPC -*-
+// $Id$
+
+project(Netsvsc_Client_Test_Lib): acelib {
+ avoids += ace_for_tao
+ sharedname = Client_Test
+ dynamicflags += ACE_CLIENT_TEST_BUILD_DLL
+ Source_Files {
+ Client_Test.cpp
+ }
+}
+
+project(Netsvcs_Client_Test) : aceexe {
+ avoids += ace_for_tao
+ exename = main
+ libs += Client_Test
+ after += Client_Test Netsvsc_Client_Test_Lib
+ Source_Files {
+ main.cpp
+ }
+}
diff --git a/ACE/netsvcs/clients/Naming/Client/Client_Test.cpp b/ACE/netsvcs/clients/Naming/Client/Client_Test.cpp
new file mode 100644
index 00000000000..0cc05964720
--- /dev/null
+++ b/ACE/netsvcs/clients/Naming/Client/Client_Test.cpp
@@ -0,0 +1,651 @@
+// $Id$
+
+#define ACE_BUILD_SVC_DLL
+
+#include "ace/Service_Config.h"
+#include "ace/Naming_Context.h"
+#include "ace/Dynamic_Service.h"
+#include "ace/Thread_Manager.h"
+#include "Client_Test.h"
+#include "ace/Reactor.h"
+#include "ace/os_include/os_ctype.h"
+#include "ace/OS_NS_signal.h"
+#include "ace/OS_NS_stdio.h"
+#include "ace/OS_NS_string.h"
+#include "ace/OS_NS_unistd.h"
+#include "ace/os_include/os_assert.h"
+
+ACE_RCSID (Client,
+ Client_Test,
+ "$Id$")
+
+class ACE_Svc_Export Client_Test : public ACE_Service_Object
+{
+public:
+ Client_Test (void);
+
+ int open (void);
+ // Cache reactor and then register self with reactor
+
+ int close (void);
+ // Close things down and free up resources.
+
+ virtual int handle_input (ACE_HANDLE handle);
+ // Handle user entered commands
+
+ virtual int init (int argc, ACE_TCHAR *argv[]);
+ // Initialize name options and naming context when dynamically
+ // linked.
+
+ virtual int fini (void);
+ // Close down the test when dynamically unlinked.
+
+ void list_options (void);
+ // Print name options
+
+ int bind (const char *key,
+ const char *value,
+ const char *type = "");
+ // Bind a key to a value
+
+ int unbind (const char *key);
+ // Unbind a name binding
+
+ int rebind (const char *key,
+ const char *value,
+ const char *type = "");
+ // Rebind a name binding
+
+ int find (const char *key);
+ // Find the value associated with a key
+
+ int list_names (const char *pattern);
+ // Find all names that match pattern
+
+ int list_values (const char *pattern);
+ // Find all values that match pattern
+
+ int list_types (const char *pattern);
+ // Find all types that match pattern
+
+ int list_name_entries (const char *pattern);
+ // Find all names that match pattern
+
+ int list_value_entries (const char *pattern);
+ // Find all values that match pattern
+
+ int list_type_entries (const char *pattern);
+ // Find all types that match pattern
+
+private:
+ ACE_Name_Options *name_options_;
+ // Name Options associated with the Naming Context
+
+ void display_menu (void);
+ // Display user menu
+
+ int set_proc_local (void);
+ // Set options to use PROC_LOCAL naming context
+
+ int set_node_local (void);
+ // Set options to use NODE_LOCAL naming context
+
+ int set_host (const char *hostname, int port);
+ // Set options to use NET_LOCAL naming context specifying host name
+ // and port number
+
+ int quit (void);
+ // Gracefully exit
+};
+
+// The following Factory is used by the ACE_Service_Config and
+// svc.conf file to dynamically initialize the state of the client
+// test.
+
+ACE_SVC_FACTORY_DEFINE (Client_Test)
+
+// Get the instance of Name_Service using Dynamic_Service
+
+//inline Name_Service *
+//NAME_SERVICE (void)
+
+inline ACE_Naming_Context *
+NAMING_CONTEXT (void)
+{
+ return ACE_Dynamic_Service<ACE_Naming_Context>::instance ("ACE_Naming_Context");
+}
+
+Client_Test::Client_Test (void)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ "Client_Test::Client_Test\n"));
+}
+
+int
+Client_Test::init (int /* argc */,
+ ACE_TCHAR * /* argv */ [])
+{
+ ACE_DEBUG ((LM_DEBUG, "Client_Test::init\n"));
+
+ // Cache the name options.
+ this->name_options_ = NAMING_CONTEXT ()->name_options ();
+ return this->open ();
+}
+
+int
+Client_Test::open (void)
+{
+ this->display_menu ();
+
+ if (ACE_Event_Handler::register_stdin_handler (this,
+ ACE_Reactor::instance (),
+ ACE_Thread_Manager::instance ()) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "%p\n",
+ "register_stdin_handler"),
+ -1);
+ return 0;
+}
+
+
+int
+Client_Test::close (void)
+{
+ // Deregister this handler with the ACE_Reactor.
+ return ACE_Reactor::instance ()->remove_handler
+ (ACE_STDIN,
+ ACE_Event_Handler::DONT_CALL | ACE_Event_Handler::READ_MASK);
+}
+
+int
+Client_Test::fini (void)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ "Client_Test::fini\n"));
+ return this->close ();
+}
+
+int
+Client_Test::handle_input (ACE_HANDLE)
+{
+ char option[BUFSIZ];
+ char buf1[BUFSIZ];
+ char buf2[BUFSIZ];
+ char buf3[BUFSIZ];
+ char *temp_buf;
+ int port;
+ char input[1024];
+
+ if (::scanf ("%s", option) <= 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "%p Try again!\n",
+ "Client_Test::handle_input"),
+ 0);
+
+ int result = -1;
+
+ switch (isupper (option[0]) ? tolower (option[0]) : option[0])
+ {
+ case 'p' :
+ result = this->set_proc_local ();
+ break;
+ case 'n' :
+ result = this->set_node_local ();
+ break;
+ case 'h' :
+ if (::scanf ("%s %d", buf1, &port) <= 0)
+ break;
+ result = this->set_host (buf1, port);
+ break;
+ case 'b' :
+ // get the input from stdin
+ ACE_OS::fgets (input, sizeof input, stdin);
+
+ // get the key
+ if ((temp_buf = ACE_OS::strtok (input, " ")))
+ {
+ ACE_OS::strcpy (buf1, temp_buf);
+
+ temp_buf = ACE_OS::strtok (0, " ");
+
+ // get the value
+ if (temp_buf)
+ {
+ ACE_OS::strcpy (buf2, temp_buf);
+
+ temp_buf = ACE_OS::strtok (0, " ");
+
+ // get the type (if entered).
+ if (temp_buf)
+ {
+ ACE_OS::strcpy (buf3, temp_buf);
+ result = this->bind (buf1, buf2, buf3);
+ }
+ else
+ result = this->bind (buf1, buf2);
+ }
+ else
+ ACE_ERROR ((LM_ERROR,
+ "Bind Failed! Value not entered.\n"));
+ }
+ else
+ ACE_ERROR ((LM_ERROR,
+ "Bind Failed! Key and Value not entered.\n"));
+ break;
+ case 'u' :
+ if (::scanf ("%s", buf1) <= 0)
+ break;
+ result = this->unbind (buf1);
+ break;
+ case 'r' :
+ // get the input from stdin
+ ACE_OS::fgets (input, sizeof input, stdin);
+
+ temp_buf = ACE_OS::strtok (input, " ");
+ // get the key
+ if (temp_buf)
+ {
+ ACE_OS::strcpy (buf1, temp_buf);
+
+ temp_buf = ACE_OS::strtok (0, " ");
+
+ // get the value
+ if (temp_buf)
+ {
+ ACE_OS::strcpy (buf2, temp_buf);
+
+ temp_buf = ACE_OS::strtok (0, " ");
+ // get the type (if entered)
+ if (temp_buf)
+ {
+ ACE_OS::strcpy (buf3, temp_buf);
+ result = this->rebind (buf1, buf2, buf3);
+ }
+ else
+ result = this->rebind (buf1, buf2);
+ }
+ else
+ ACE_ERROR ((LM_ERROR,
+ "Rebind Failed! Value not entered.\n"));
+ }
+ else
+ ACE_ERROR ((LM_ERROR,
+ "Reind Failed! Key and value not entered.\n"));
+ break;
+ case 'f' :
+ if (::scanf ("%s", buf1) <= 0)
+ break;
+ result = this->find (buf1);
+ break;
+ case 'j' :
+ if (::scanf ("%s", buf1) <= 0)
+ break;
+ else
+ result = this->list_names (buf1);
+ break;
+ case 'k' :
+ if (::scanf ("%s", buf1) <= 0)
+ break;
+ else
+ result = this->list_values (buf1);
+ break;
+ case 'l' :
+ if (::scanf ("%s", buf1) <= 0)
+ break;
+ else
+ result = this->list_types (buf1);
+ break;
+ case 'c' :
+ if (::scanf ("%s", buf1) <= 0)
+ break;
+ else
+ result = this->list_name_entries (buf1);
+ break;
+ case 'd' :
+ if (::scanf ("%s", buf1) <= 0)
+ break;
+ else
+ result = this->list_value_entries (buf1);
+ break;
+ case 'e' :
+ if (::scanf ("%s", buf1) <= 0)
+ break;
+ else
+ result = this->list_type_entries (buf1);
+ break;
+ case 'q' :
+ result = this->quit ();
+ break;
+ default :
+ ACE_DEBUG ((LM_DEBUG,
+ "Unrecognized command.\n"));
+ }
+
+ this->display_menu ();
+ return result;
+}
+
+void
+Client_Test::display_menu (void)
+{
+ ACE_DEBUG ((LM_DEBUG, "\n"));
+ this->list_options ();
+ ACE_DEBUG ((LM_DEBUG, " Name Service Main Menu\n"));
+ ACE_DEBUG ((LM_DEBUG, " ----------------------\n"));
+ ACE_DEBUG ((LM_DEBUG, "<P> Use Process Local Database\n"));
+ ACE_DEBUG ((LM_DEBUG, "<N> Use Node Local Database\n"));;
+ ACE_DEBUG ((LM_DEBUG, "<H> Set Remote Name server <host> and <port>\n\n"));
+ ACE_DEBUG ((LM_DEBUG, "<B> Bind <key> <value> [<type>]\n"));
+ ACE_DEBUG ((LM_DEBUG, "<U> Unbind <key>\n"));
+ ACE_DEBUG ((LM_DEBUG, "<R> Rebind <key> <value> [<type>]\n"));
+ ACE_DEBUG ((LM_DEBUG, "<F> Find <key>\n"));
+ ACE_DEBUG ((LM_DEBUG, "<J> Lookup keys matching <pattern>\n"));
+ ACE_DEBUG ((LM_DEBUG, "<K> Lookup values matching <pattern>\n"));
+ ACE_DEBUG ((LM_DEBUG, "<L> Lookup types matching <pattern>\n"));
+ ACE_DEBUG ((LM_DEBUG, "<C> Complete lookup keys matching <pattern>\n"));
+ ACE_DEBUG ((LM_DEBUG, "<D> Complete lookup values matching <pattern>\n"));
+ ACE_DEBUG ((LM_DEBUG, "<E> Complete lookup types matching <pattern>\n"));
+
+ ACE_DEBUG ((LM_DEBUG, "<Q> or ^C (exit)\n"));
+}
+
+void
+Client_Test::list_options (void)
+{
+ switch (this->name_options_->context ())
+ {
+ case ACE_Naming_Context::PROC_LOCAL:
+ ACE_DEBUG ((LM_DEBUG,
+ " *** Using Process Local Database\n"));
+ break;
+ case ACE_Naming_Context::NODE_LOCAL:
+ ACE_DEBUG ((LM_DEBUG,
+ " *** Using Node Local Database\n"));
+ break;
+ case ACE_Naming_Context::NET_LOCAL:
+ ACE_DEBUG ((LM_DEBUG,
+ " *** Hostname: %s\n",
+ this->name_options_->nameserver_host ()));
+ ACE_DEBUG ((LM_DEBUG,
+ " *** Port Number: %d\n",
+ this->name_options_->nameserver_port ()));
+ break;
+ default:
+ ACE_ERROR ((LM_ERROR, "ERROR: shouldn't occur!\n"));
+ break;
+ }
+ ACE_DEBUG ((LM_DEBUG,
+ " *** Namespace directory is %s ***\n",
+ this->name_options_->namespace_dir ()));
+}
+
+int
+Client_Test::set_proc_local (void)
+{
+ // Close down original name space
+ NAMING_CONTEXT ()->close ();
+ this->name_options_->nameserver_host (ACE_TEXT ("localhost"));
+ this->name_options_->context (ACE_Naming_Context::PROC_LOCAL);
+ return NAMING_CONTEXT ()->open (ACE_Naming_Context::PROC_LOCAL);
+}
+
+int
+Client_Test::set_node_local (void)
+{
+ // Close down original name space
+ NAMING_CONTEXT ()->close ();
+ this->name_options_->nameserver_host (ACE_TEXT ("localhost"));
+ this->name_options_->context (ACE_Naming_Context::NODE_LOCAL);
+ return NAMING_CONTEXT ()->open (ACE_Naming_Context::NODE_LOCAL);
+}
+
+int
+Client_Test::set_host (const char *hostname, int port)
+{
+ // Close down original name space
+ NAMING_CONTEXT ()->close ();
+
+ this->name_options_->context (ACE_Naming_Context::NET_LOCAL);
+ // Set Name Options
+ this->name_options_->nameserver_host (ACE_TEXT_CHAR_TO_TCHAR (hostname));
+ this->name_options_->nameserver_port (port);
+
+ return NAMING_CONTEXT ()->open (ACE_Naming_Context::NET_LOCAL);
+}
+
+int
+Client_Test::quit (void)
+{
+ // Send ourselves a SIGINT!
+ return ACE_OS::kill (ACE_OS::getpid (), SIGINT);
+}
+
+int
+Client_Test::bind (const char *key,
+ const char *value,
+ const char *type)
+{
+ if (NAMING_CONTEXT ()->bind (key, value, type) != 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "%p Bind failed! Key %s exists\n",
+ "Client_Test::bind",
+ key),
+ 0);
+ return 0;
+}
+
+int
+Client_Test::unbind (const char *key)
+{
+ if (NAMING_CONTEXT ()->unbind (key) != 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "%p Unbind failed! Key %s not found\n",
+ "Client_Test::unbind",
+ key),
+ 0);
+ return 0;
+}
+
+int
+Client_Test::rebind (const char *key,
+ const char *value,
+ const char *type)
+{
+ int result = NAMING_CONTEXT ()->rebind (key, value, type );
+ return result == 1 ? 0 : result;
+}
+
+int
+Client_Test::list_names (const char *pattern)
+{
+ ACE_PWSTRING_SET set;
+
+ if (NAMING_CONTEXT ()->list_names (set, pattern) != 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "%p Pattern matching failed!\n",
+ "Client_Test::list_names"),
+ 0);
+ else
+ {
+ ACE_PWSTRING_ITERATOR set_iterator (set);
+
+ for (ACE_NS_WString *name = 0;
+ set_iterator.next (name) !=0;
+ set_iterator.advance())
+ ACE_DEBUG ((LM_DEBUG,
+ "%s\n",
+ name->char_rep ()));
+ }
+ return 0;
+}
+
+int
+Client_Test::list_values (const char *pattern)
+{
+ ACE_PWSTRING_SET set;
+
+ if (NAMING_CONTEXT ()->list_values (set, pattern) != 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "%p Pattern matching failed!\n",
+ "Client_Test::list_values"),
+ 0);
+ else
+ {
+ ACE_PWSTRING_ITERATOR set_iterator (set);
+
+ for (ACE_NS_WString *value = 0;
+ set_iterator.next (value) !=0;
+ set_iterator.advance())
+ ACE_DEBUG ((LM_DEBUG,
+ "%s\n",
+ value->char_rep ()));
+ }
+ return 0;
+}
+
+int
+Client_Test::list_types (const char *pattern)
+{
+ ACE_PWSTRING_SET set;
+
+ if (NAMING_CONTEXT ()->list_types (set, pattern) != 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "%p Pattern matching failed!\n",
+ "Client_Test::list_types"),
+ 0);
+ else
+ {
+ ACE_PWSTRING_ITERATOR set_iterator (set);
+
+ for (ACE_NS_WString *type = 0;
+ set_iterator.next (type) !=0;
+ set_iterator.advance())
+ ACE_DEBUG ((LM_DEBUG,
+ "%s\n",
+ type->char_rep ()));
+ }
+ return 0;
+}
+
+int
+Client_Test::list_name_entries (const char *pattern)
+{
+ ACE_BINDING_SET set;
+
+ if (NAMING_CONTEXT ()->list_name_entries (set, pattern) != 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "%p Pattern matching failed!\n",
+ "Client_Test::list_names"),
+ 0);
+ else
+ {
+ ACE_BINDING_ITERATOR set_iterator (set);
+
+ for (ACE_Name_Binding *entry = 0;
+ set_iterator.next (entry) !=0;
+ set_iterator.advance())
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ "%s\t",
+ entry->name_.char_rep ()));
+ ACE_DEBUG ((LM_DEBUG,
+ "%s\t",
+ entry->value_.char_rep ()));
+ if (entry->type_)
+ ACE_DEBUG ((LM_DEBUG,
+ "%s\n",
+ entry->type_));
+ }
+ }
+ return 0;
+}
+
+int
+Client_Test::list_value_entries (const char *pattern)
+{
+ ACE_BINDING_SET set;
+
+ if (NAMING_CONTEXT ()->list_value_entries (set, pattern) != 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "%p Pattern matching failed!\n",
+ "Client_Test::list_values"),
+ 0);
+ else
+ {
+ ACE_BINDING_ITERATOR set_iterator (set);
+ for (ACE_Name_Binding *entry = 0;
+ set_iterator.next (entry) !=0;
+ set_iterator.advance())
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ "%s\t",
+ entry->name_.char_rep ()));
+ ACE_DEBUG ((LM_DEBUG,
+ "%s\t",
+ entry->value_.char_rep ()));
+ if (entry->type_)
+ ACE_DEBUG ((LM_DEBUG,
+ "%s\n",
+ entry->type_));
+ }
+ }
+ return 0;
+}
+
+int
+Client_Test::list_type_entries (const char *pattern)
+{
+ ACE_BINDING_SET set;
+
+ if (NAMING_CONTEXT ()->list_type_entries (set, pattern) != 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "%p Pattern matching failed!\n",
+ "Client_Test::list_types"),
+ 0);
+ else
+ {
+ ACE_BINDING_ITERATOR set_iterator (set);
+
+ for (ACE_Name_Binding *entry = 0;
+ set_iterator.next (entry) !=0;
+ set_iterator.advance())
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ "%s\t",
+ entry->name_.char_rep ()));
+ ACE_DEBUG ((LM_DEBUG,
+ "%s\t",
+ entry->value_.char_rep ()));
+ ACE_DEBUG ((LM_DEBUG,
+ "%s\n",
+ entry->type_));
+ }
+ }
+ return 0;
+}
+
+int
+Client_Test::find (const char *key)
+{
+ char *value = 0;
+ char *type = 0;
+
+ if (NAMING_CONTEXT ()->resolve (key, value, type) != 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "%p Find failed! Key %s not found\n",
+ "Client_Test::list_find",
+ key),
+ 0);
+ else
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ "Binding for %s : value = %s\ttype = %s\n",
+ key,
+ value,
+ type));
+ if (type)
+ delete [] type;
+ return 0;
+ }
+}
+
diff --git a/ACE/netsvcs/clients/Naming/Client/Client_Test.h b/ACE/netsvcs/clients/Naming/Client/Client_Test.h
new file mode 100644
index 00000000000..1df4c5c0e05
--- /dev/null
+++ b/ACE/netsvcs/clients/Naming/Client/Client_Test.h
@@ -0,0 +1,13 @@
+// -*- C++ -*-
+//
+// $Id$
+
+#include "ace/svc_export.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+// Define the external Client_Test interface.
+
+ACE_SVC_FACTORY_DECLARE (Client_Test)
diff --git a/ACE/netsvcs/clients/Naming/Client/Makefile.am b/ACE/netsvcs/clients/Naming/Client/Makefile.am
new file mode 100644
index 00000000000..548b9be4a8e
--- /dev/null
+++ b/ACE/netsvcs/clients/Naming/Client/Makefile.am
@@ -0,0 +1,59 @@
+## 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.Netsvsc_Client_Test_Lib.am
+
+if !BUILD_ACE_FOR_TAO
+
+noinst_LTLIBRARIES = libClient_Test.la
+
+libClient_Test_la_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR) \
+ -DACE_CLIENT_TEST_BUILD_DLL
+
+libClient_Test_la_SOURCES = \
+ Client_Test.cpp
+
+noinst_HEADERS = \
+ Client_Test.h
+
+endif !BUILD_ACE_FOR_TAO
+
+## Makefile.Netsvcs_Client_Test.am
+
+if !BUILD_ACE_FOR_TAO
+noinst_PROGRAMS = main
+
+main_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+main_SOURCES = \
+ main.cpp \
+ Client_Test.h
+
+main_LDADD = \
+ libClient_Test.la \
+ $(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/netsvcs/clients/Naming/Client/README b/ACE/netsvcs/clients/Naming/Client/README
new file mode 100644
index 00000000000..68e69b6b3bf
--- /dev/null
+++ b/ACE/netsvcs/clients/Naming/Client/README
@@ -0,0 +1,123 @@
+This directory contains a test for the ACE_Name_Server library. This
+test program also illustrates how to use the ACE Service_Config
+mechanism, which enables the client code to be dynamically linked into
+the process at installation-time or run-time.
+
+The client test is an application that allows the user to vary the
+test parameters through the following menu driven interface:
+
+ Name Service Main Menu
+ ----------------------
+ *** Using Process Local Database ***
+
+<P> Use Process Local Database
+<N> Use Node Local Database
+<H> Set Remote Name server <host> and <port>
+
+<B> Bind <key> <value> [<type>]
+<U> Unbind <key>
+<R> Rebind <key> <value> [<type>]
+<F> Find <key>
+<J> Lookup keys matching <pattern>
+<K> Lookup values matching <pattern>
+<L> Lookup types matching <pattern>
+<C> Complete lookup keys matching <pattern>
+<D> Complete lookup values matching <pattern>
+<E> Complete lookup types matching <pattern>
+
+<Q> or ^C (exit)
+
+Initially, the user can select the type of database -- process local,
+node local, or net local -- from the menu.
+
+<P> uses the process local database (i.e., the database is called the
+ same name as the process and stored in /tmp).
+<N> uses the node local database (which defaults to /tmp/localnames).
+<H> uses the net local database by specifying host and port number (by
+ default this is stored in a file called /tmp/globalnames on the server).
+
+The user can then create new bindings, delete existing bindings, or
+rebind bindings:
+
+<B> Bind <key> <value> [<type>]
+ -- binds the key to the value and adds the
+ binding to the database. Note that type
+ information is optional.
+<U> Unbind <key> -- unbind a binding whose key is <key>
+<R> Rebind <key> <value> [<type>]
+ -- rebind <key> to <value>. Once again <type> is optional.
+<F> Find <key> -- find the binding associated with key <key>
+<Q> or ^C (exit) -- exit gracefully, saving the contents of the
+ Name Server in persistent shared memory.
+
+In addition, the user can do pattern matching for keys, values, and
+types. Note that pattern matching is supported using regular expressions.
+
+<J> Lookup keys matching <pattern>
+ -- find all keys that match <pattern>
+<K> Lookup values matching <pattern>
+ -- find all values that match <pattern>
+<L> Lookup types matching <pattern>
+ -- find all types that match <pattern>
+
+<C> Complete lookup keys matching <pattern>
+ -- find all bindings whose keys match <pattern>
+<D> Complete lookup values matching <pattern>
+ -- find all bindings whose values match <pattern>
+<E> Complete lookup types matching <pattern>
+ -- find all bindings whose types match <pattern>
+
+-------------------------
+Running the tests:
+
+The test program uses a DLL supported by the svc.conf file, which
+allows them to configure the client-side dynamically. The client test
+program accomplishes this by making use of a Singleton proxy object
+(Name_Service) to provide an interface to the client-side.
+
+The test programs rely on svc.conf to provide the necessary parameters
+for dynamically linking the Name Service library and then
+executing. In the absence of svc.conf, the test programs would use
+static binding.
+
+client:
+
+The client test can be started without any parameters. However, if the
+user wants to use the net local database, the hostname and the port
+number of the server containing the net local database can be given at
+"command line" in the svc.conf file, e.g.:
+
+dynamic ACE_Naming_Context Service_Object * libACE.so:_make_ACE_Naming_Context ()
+ "main -h tango.cs -p 7891"
+dynamic Name_Server_test Service_Object * .shobj/Client_Test.so:_make_Client_Test () ""
+
+The above example starts the client test application and sets up a
+connection to port 7891 to a Name Server running on tango.cs, which
+has the net local database. The Client_Test directive must come after
+ACE_Naming_Context since it relies on the ACE_Naming_Context having
+been dynamically linked.
+
+Note that you can also use environment variables in the "command
+line", as follows:
+
+dynamic ACE_Naming_Context Service_Object * libACE.so:_make_ACE_Naming_Context ()
+ "main -s $DB -p $PORT -h tango"
+dynamic Name_Server_test Service_Object * .shobj/Client_Test.so:_make_Client_Test () ""
+
+In this example, $DB and $PORT are environment variables that are
+automatically interpreted and substituted by ACE. In addition, note
+how you can give a relative name for the libACE_svcs.so and ACE will
+locate this for you automatically by reading your LD search path.
+
+server:
+
+The name server is needed only in the case where the net local
+database needs to be accessed. The server test needs to run on the
+machine that contains the net local database. To execute the server
+test, the user has to specify the port number at which the server will
+be listening in the svc.conf file. An implementation of a name
+service for ACE is available in the $ACE_ROOT/netsvcs/{lib,servers}
+directories. Please see the README files there for an explanation of
+how to run the server.
+
+
diff --git a/ACE/netsvcs/clients/Naming/Client/main.cpp b/ACE/netsvcs/clients/Naming/Client/main.cpp
new file mode 100644
index 00000000000..e355386f4bb
--- /dev/null
+++ b/ACE/netsvcs/clients/Naming/Client/main.cpp
@@ -0,0 +1,80 @@
+// $Id$
+
+// Test the client-side of the ACE Name Server...
+
+#include "ace/Service_Config.h"
+#include "ace/Naming_Context.h"
+#include "ace/ARGV.h"
+#include "ace/Log_Msg.h"
+#include "ace/Reactor.h"
+
+#include "Client_Test.h"
+
+ACE_RCSID (Client,
+ main,
+ "$Id$")
+
+int
+ACE_TMAIN (int, ACE_TCHAR *argv[])
+{
+ ACE_Service_Config daemon;
+ ACE_ARGV new_args;
+
+ // Load the existing <argv> into our new one.
+ new_args.add (argv);
+ // Enable loading of static services.
+ new_args.add (ACE_TEXT ("-y"));
+ // Enable debugging within dynamically linked services.
+ new_args.add (ACE_TEXT ("-d"));
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("argc = %d\n"),
+ new_args.argc ()));
+
+ // Print the contents of the combined <ACE_ARGV>.
+ for (int i = 0; i < new_args.argc (); i++)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%d) %s\n"),
+ i,
+ new_args.argv ()[i]));
+
+ if (daemon.open (new_args.argc (),
+ new_args.argv ()) == -1)
+ {
+ if (errno != ENOENT)
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("open")),
+ 1);
+ else // Use static binding.
+ {
+ ACE_ARGV args;
+
+ args.add (argv[0]);
+ args.add (ACE_TEXT ("-p10011")); // Port number.
+ ACE_Service_Object *so =
+ ACE_SVC_INVOKE (ACE_Naming_Context);
+
+ if (so->init (args.argc (),
+ args.argv ()) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("ACE_Naming_Context")),
+ 1);
+
+ so = ACE_SVC_INVOKE (Client_Test);
+
+ if (so->init (0,
+ args.argv ()) == -1)
+ ACE_ERROR ((LM_ERROR,
+ "%p\n%a",
+ "Client_Test",
+ 1));
+ }
+ }
+
+ // Run forever, performing the configured services until we are shut
+ // down by a SIGINT/SIGQUIT signal.
+
+ ACE_Reactor::run_event_loop ();
+
+ return 0;
+}
diff --git a/ACE/netsvcs/clients/Naming/Client/svc.conf b/ACE/netsvcs/clients/Naming/Client/svc.conf
new file mode 100644
index 00000000000..ba583b0d446
--- /dev/null
+++ b/ACE/netsvcs/clients/Naming/Client/svc.conf
@@ -0,0 +1,7 @@
+# Note that $PORT is an environment variable that is
+# automatically interpreted and substituted by ACE!
+# static ACE_Naming_Context "main -p $PORT -h tango"
+dynamic ACE_Naming_Context Service_Object * ACE:_make_ACE_Naming_Context () "main -p $PORT -h tango"
+dynamic Name_Server_test Service_Object * Client_Test:_make_Client_Test ()
+# Note: Client_Test must come after ACE_Naming_Context since it relies
+# on the ACE_Naming_Context having been linked...
diff --git a/ACE/netsvcs/clients/Naming/Client/svc2.conf b/ACE/netsvcs/clients/Naming/Client/svc2.conf
new file mode 100644
index 00000000000..44a276a4a44
--- /dev/null
+++ b/ACE/netsvcs/clients/Naming/Client/svc2.conf
@@ -0,0 +1,9 @@
+# Note that $DB and $PORT are environment variables that are
+# automatically interpreted and substituted by ACE! In addition, note
+# how you can give a relative name for the libACE_svcs.so and ACE will
+# locate this for you automatically by reading your LD search path!
+dynamic ACE_Naming_Context Service_Object * ACE:_make_ACE_Naming_Context () "main -s $DB"
+dynamic ACE_Naming_Context2 Service_Object * ACE:_make_ACE_Naming_Context () "main -s $DB"
+dynamic Name_Server_test Service_Object * Client_Test:_make_Client_Test ()
+# Note: Client_Test must come after ACE_Naming_Context since it relies
+# on the ACE_Naming_Context having been dynamically linked.
diff --git a/ACE/netsvcs/clients/Naming/Dump_Restore/Dump_Restore.cpp b/ACE/netsvcs/clients/Naming/Dump_Restore/Dump_Restore.cpp
new file mode 100644
index 00000000000..bfda59cd09f
--- /dev/null
+++ b/ACE/netsvcs/clients/Naming/Dump_Restore/Dump_Restore.cpp
@@ -0,0 +1,467 @@
+// $Id$
+
+#include "ace/Malloc_Base.h"
+#include "ace/Service_Config.h"
+#include "ace/Read_Buffer.h"
+#include "ace/Thread_Manager.h"
+
+// FUZZ: disable check_for_streams_include
+#include "ace/streams.h" /* Because dump () uses ofstream. */
+
+#include "Dump_Restore.h"
+#include "ace/OS_NS_signal.h"
+#include "ace/OS_NS_stdio.h"
+#include "ace/OS_NS_string.h"
+#include "ace/OS_NS_unistd.h"
+
+ACE_RCSID(Dump_Restore, Dump_Restore, "$Id$")
+
+Dump_Restore::Dump_Restore (int argc, ACE_TCHAR *argv[])
+ : infile_ (0)
+{
+ ACE_NEW (this->ns_context_,
+ ACE_Naming_Context);
+
+ // Cache the name options
+ this->name_options_ = this->ns_context_->name_options ();
+ this->name_options_->parse_args (argc, argv);
+
+ //determine name context
+ if (ACE_OS::strcmp (this->name_options_->nameserver_host (),
+ ACE_TEXT ("localhost")) == 0)
+ {
+ if (ns_context_->open (ACE_Naming_Context::PROC_LOCAL) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("ns_context_->open")));
+ }
+ else
+ {
+ // Don't really need to do this but it's a hack to fix the
+ // problme of Display () not printing the right hostname
+ ACE_OS::strcpy (this->hostname_,
+ this->name_options_->nameserver_host ());
+ this->port_ =
+ this->name_options_->nameserver_port ();
+
+ if (this->ns_context_->open (ACE_Naming_Context::NET_LOCAL) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("ns_context_->open")));
+ }
+
+ this->display_menu ();
+
+ if (ACE_Event_Handler::register_stdin_handler (this,
+ ACE_Reactor::instance (),
+ ACE_Thread_Manager::instance ()) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("register_stdin_handler")));
+}
+
+Dump_Restore::~Dump_Restore (void)
+{
+ // Deregister this handler with the ACE_Reactor.
+ ACE_Reactor::instance ()->remove_handler
+ (ACE_STDIN,
+ ACE_Event_Handler::DONT_CALL | ACE_Event_Handler::READ_MASK);
+
+ ACE_OS::fclose (this->infile_);
+}
+
+int
+Dump_Restore::handle_input (ACE_HANDLE)
+{
+ char option[BUFSIZ];
+ char buf1[BUFSIZ];
+ u_short port;
+
+ if (::scanf ("%s", option) <= 0)
+ {
+ ACE_DEBUG ((LM_ERROR,
+ ACE_TEXT ("try again\n")));
+ return 0;
+ }
+
+ switch (option[0])
+ {
+ case 'P' :
+ case 'p' :
+ set_proc_local ();
+ break;
+ case 'N' :
+ case 'n' :
+ set_node_local ();
+ break;
+ case 'H' :
+ case 'h' :
+ if (::scanf ("%s %hu", buf1, &port) <= 0)
+ break;
+ set_host (ACE_TEXT_CHAR_TO_TCHAR (buf1), port);
+ break;
+ case 'F':
+ case 'f':
+ if (::scanf ("%s", filename_) <= 0)
+ break;
+ if (this->infile_)
+ ACE_OS::fclose (this->infile_);
+ this->infile_ = fopen(filename_,"r");
+ break;
+ case 'B' :
+ case 'b' :
+ populate (Dump_Restore::BIND);
+ break;
+ case 'U' :
+ case 'u' :
+ populate (Dump_Restore::UNBIND);
+ break;
+ case 'R' :
+ case 'r' :
+ populate (Dump_Restore::REBIND);
+ break;
+ case 'D':
+ case 'd':
+ if (::scanf ("%s", dump_filename_) <= 0)
+ break;
+ this->dump ();
+ break;
+ case 'Q' :
+ case 'q' :
+ quit ();
+ break;
+ default :
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Unrecognized command.\n")));
+ }
+
+ display_menu ();
+ return 0;
+}
+
+void
+Dump_Restore::display_menu (void)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\n")));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Name Service Main Menu\n")));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("----------------------\n")));
+
+ // Check if using local name space or remote name space
+ if (ACE_OS::strcmp (this->name_options_->nameserver_host (),
+ ACE_TEXT ("localhost")) == 0)
+ {
+ if (this->ns_scope_ == ACE_Naming_Context::PROC_LOCAL)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT (" *** Using Process Local Database ***\n\n")));
+ else
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT (" *** Using Node Local Database ***\n\n")));
+ }
+ else
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT (" Hostname: %s\n"),
+ this->hostname_));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT (" Port Number: %d\n"),
+ this->port_));
+ }
+
+ if (this->infile_)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Input File: %C\n"),
+ this->filename_));
+ else
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("** No Input File Specified **\n")));
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("<P> Use Process Local Database\n")));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("<N> Use Node Local Database\n")));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("<H> Set Remote Name server <host> and <port>\n")));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("<F> Set Input File <file name>\n")));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("<B> Bind\n")));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("<U> Unbind\n")));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("<R> Rebind\n")));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("<D> Dump <file name>\n")));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("<Q> or ^C (exit) \n")));
+}
+
+
+int
+Dump_Restore::set_proc_local (void)
+{
+ // Set Name Options
+ this->name_options_->nameserver_host (ACE_TEXT ("localhost"));
+ this->name_options_->nameserver_port (0);
+
+ // Set Naming Context scope
+ this->ns_scope_ =
+ ACE_Naming_Context::PROC_LOCAL;
+
+ // Remove old naming context
+ delete this->ns_context_;
+
+ // Create new Naming Context
+ ACE_NEW_RETURN (this->ns_context_,
+ ACE_Naming_Context,
+ -1);
+
+ if (this->ns_context_->open (ACE_Naming_Context::PROC_LOCAL) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("ns_context_->open")),
+ -1);
+
+ return 0;
+}
+
+int
+Dump_Restore::set_node_local (void)
+{
+ // Set Name Options
+ this->name_options_->nameserver_host (ACE_TEXT ("localhost"));
+ this->name_options_->nameserver_port (0);
+
+ // Set Naming Context scope
+ this->ns_scope_ = ACE_Naming_Context::NODE_LOCAL;
+
+ // Remove old naming context
+ delete this->ns_context_;
+
+ // Create new Naming Context
+ ACE_NEW_RETURN (this->ns_context_,
+ ACE_Naming_Context,
+ -1);
+
+ if (ns_context_->open (ACE_Naming_Context::NODE_LOCAL) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("ns_context_->open")),
+ -1);
+ return 0;
+}
+
+int
+Dump_Restore::set_host (const ACE_TCHAR *hostname,
+ int port)
+{
+ // Set Name Options
+ this->name_options_->nameserver_host (hostname);
+ this->name_options_->nameserver_port (port);
+
+ // Don't really need to do this but it's a hack to fix the problme
+ // of Display () not printing the right hostname
+ ACE_OS::strcpy (this->hostname_, hostname);
+ this->port_ = port;
+ this->ns_scope_ = ACE_Naming_Context::NET_LOCAL;
+
+ // remove old naming context
+ delete this->ns_context_;
+
+ // Create new Naming Context
+ ACE_NEW_RETURN (this->ns_context_,
+ ACE_Naming_Context,
+ -1);
+
+ // assume net_local context
+ if (ns_context_->open (ACE_Naming_Context::NET_LOCAL) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("ns_context_->open")),
+ -1);
+ return 0;
+}
+
+int
+Dump_Restore::doit (Dump_Restore::Operation_Type op,
+ const char *name,
+ const char *value,
+ const char *type)
+{
+ int result = -1;
+
+ switch (op)
+ {
+ case Dump_Restore::BIND:
+ {
+ result = this->bind (name, value, type);
+ break;
+ }
+ case Dump_Restore::UNBIND:
+ {
+ result = this->unbind (name);
+ break;
+ }
+ case Dump_Restore::REBIND:
+ {
+ result = this->rebind (name, value, type);
+ break;
+ }
+ }
+
+ return result;
+}
+
+int
+Dump_Restore::populate (Dump_Restore::Operation_Type op)
+{
+ if (this->infile_)
+ {
+ int result = -1;
+ enum State { NAME, VALUE, TYPE };
+
+ State state = NAME;
+ // reset file pointer
+ ACE_OS::rewind (this->infile_);
+
+ ACE_Allocator *allocator =
+ ACE_Allocator::instance ();
+ ACE_Read_Buffer read_buffer (this->infile_,
+ 0,
+ allocator);
+
+ for (char *temp;
+ (temp = read_buffer.read ('\n')) != 0;
+ )
+ {
+ char *name = 0;
+ const char *actual_name = 0;
+ char *value = 0;
+ const char *actual_value = 0;
+ char *type = 0;
+ const char *actual_type = 0;
+
+ switch (state)
+ {
+ case NAME:
+ name = temp;
+ ACE_OS::strtok (name, "=");
+ actual_name = ACE_OS::strtok (0, "=");
+ state = VALUE;
+ break;
+ case VALUE:
+ value = temp;
+ ACE_OS::strtok (value, "=");
+ actual_value = ACE_OS::strtok (0, "=");
+ state = TYPE;
+ break;
+ case TYPE:
+ type = temp;
+ ACE_OS::strtok (type, "=");
+ actual_type = ACE_OS::strtok (0, "=");
+
+ if (actual_type)
+ result = this->doit (op,
+ actual_name,
+ actual_value,
+ actual_type);
+ else
+ result = this->doit (op,
+ actual_name,
+ actual_value);
+ if (name)
+ allocator->free(name);
+ if (value)
+ allocator->free(value);
+ if (type)
+ allocator->free(type);
+ state = NAME;
+ break;
+ default:
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("populate")),
+ -1);
+ /* NOTREACHED */
+ }
+ }
+
+ return result;
+ }
+ else
+ return -1;
+}
+
+int
+Dump_Restore::bind (const char *key,
+ const char *value,
+ const char *type)
+{
+ int result = ns_context_->bind (key,
+ value,
+ type);
+ if (result == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("ns_context_->bind")),
+ -1);
+ else if (result == 1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%s%s%s\n"),
+ ACE_TEXT ("key <"),
+ key,
+ ACE_TEXT ("> already bound")),
+ 1);
+ return 0;
+}
+
+int
+Dump_Restore::unbind (const char *key)
+{
+ int result = ns_context_->unbind (key);
+
+ if (result == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("ns_context_->unbind")),
+ -1);
+ return 0;
+}
+
+int
+Dump_Restore::rebind (const char *key,
+ const char *value,
+ const char *type)
+{
+ if (ns_context_->rebind (key,
+ value,
+ type) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("ns_context_->rebind")),
+ -1);
+ return 0;
+}
+
+int
+Dump_Restore::quit (void)
+{
+ return ACE_OS::kill (ACE_OS::getpid (), SIGINT);
+}
+
+void
+Dump_Restore::dump (void)
+{
+ ofstream output_file (dump_filename_);
+
+ ostream *orig_stream = ACE_Log_Msg::instance ()->msg_ostream ();
+ ACE_Log_Msg::instance ()->msg_ostream (&output_file);
+ ACE_Log_Msg::instance ()->clr_flags (ACE_Log_Msg::STDERR | ACE_Log_Msg::LOGGER );
+ ACE_Log_Msg::instance ()->set_flags (ACE_Log_Msg::OSTREAM);
+
+ ns_context_->dump ();
+
+ ACE_Log_Msg::instance ()->msg_ostream (orig_stream);
+ ACE_Log_Msg::instance ()->clr_flags (ACE_Log_Msg::STDERR);
+}
diff --git a/ACE/netsvcs/clients/Naming/Dump_Restore/Dump_Restore.h b/ACE/netsvcs/clients/Naming/Dump_Restore/Dump_Restore.h
new file mode 100644
index 00000000000..1cdd2113f8e
--- /dev/null
+++ b/ACE/netsvcs/clients/Naming/Dump_Restore/Dump_Restore.h
@@ -0,0 +1,86 @@
+// -*- C++ -*-
+//
+// $Id$
+
+#include "ace/Event_Handler.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "ace/Reactor.h"
+#include "ace/Naming_Context.h"
+#include "ace/svc_export.h"
+
+class ACE_Svc_Export Dump_Restore : public ACE_Event_Handler
+{
+public:
+ enum Operation_Type
+ {
+ BIND,
+ UNBIND,
+ REBIND
+ };
+ Dump_Restore (int argc, ACE_TCHAR *argv[]);
+ // Initialize name options and naming context
+
+ ~Dump_Restore (void);
+
+ virtual int handle_input (ACE_HANDLE handle);
+ // Handle user entered commands
+
+ void dump (void);
+
+private:
+ ACE_TCHAR hostname_[MAXHOSTNAMELEN + 1];
+ // Cache the hostname and port number for remote case
+
+ void display_menu (void);
+ // Display user menu.
+
+ int set_proc_local (void);
+ // Set options to use PROC_LOCAL naming context.
+
+ int set_node_local (void);
+ // Set options to use NODE_LOCAL naming context.
+
+ int set_host (const ACE_TCHAR *hostname,
+ int port);
+ // Set options to use NET_LOCAL naming context specifying host name
+ // and port number.
+
+ int quit (void);
+ // Gracefully exit.
+
+ int populate (Dump_Restore::Operation_Type op);
+
+ int doit (Dump_Restore::Operation_Type op,
+ const char *name,
+ const char *value,
+ const char *type = "");
+ int bind (const char *key,
+ const char *value,
+ const char *type = "");
+ int unbind (const char *key);
+ int rebind (const char *key,
+ const char *value,
+ const char *type = "");
+
+ char filename_[MAXPATHLEN + 1];
+ char dump_filename_[MAXPATHLEN + 1];
+
+ u_short port_;
+ // port server is listening on
+
+ ACE_Naming_Context *ns_context_;
+ // Current naming context
+
+ ACE_Naming_Context::Context_Scope_Type ns_scope_;
+ // Defines the scope of the naming context
+
+ FILE *infile_;
+ // input file
+
+ ACE_Name_Options *name_options_;
+ // Name Options associated with the Naming Context
+};
diff --git a/ACE/netsvcs/clients/Naming/Dump_Restore/Dump_Restore.mpc b/ACE/netsvcs/clients/Naming/Dump_Restore/Dump_Restore.mpc
new file mode 100644
index 00000000000..c88bb05e2e2
--- /dev/null
+++ b/ACE/netsvcs/clients/Naming/Dump_Restore/Dump_Restore.mpc
@@ -0,0 +1,21 @@
+// -*- MPC -*-
+// $Id$
+
+project(Netsvcs_Dump_Restore_Lib): acelib {
+ avoids += ace_for_tao
+ sharedname = Dump_Restore
+ dynamicflags += ACE_BUILD_SVC_DLL
+ Source_Files {
+ Dump_Restore.cpp
+ }
+}
+
+project(Netsvcs_Dump_Restore) : aceexe {
+ avoids += ace_for_tao
+ exename = main
+ libs += Dump_Restore
+ after += Netsvcs_Dump_Restore_Lib
+ Source_Files {
+ main.cpp
+ }
+}
diff --git a/ACE/netsvcs/clients/Naming/Dump_Restore/Makefile.am b/ACE/netsvcs/clients/Naming/Dump_Restore/Makefile.am
new file mode 100644
index 00000000000..38ed1977b42
--- /dev/null
+++ b/ACE/netsvcs/clients/Naming/Dump_Restore/Makefile.am
@@ -0,0 +1,59 @@
+## 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.Netsvcs_Dump_Restore_Lib.am
+
+if !BUILD_ACE_FOR_TAO
+
+noinst_LTLIBRARIES = libDump_Restore.la
+
+libDump_Restore_la_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR) \
+ -DACE_BUILD_SVC_DLL
+
+libDump_Restore_la_SOURCES = \
+ Dump_Restore.cpp
+
+noinst_HEADERS = \
+ Dump_Restore.h
+
+endif !BUILD_ACE_FOR_TAO
+
+## Makefile.Netsvcs_Dump_Restore.am
+
+if !BUILD_ACE_FOR_TAO
+noinst_PROGRAMS = main
+
+main_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+main_SOURCES = \
+ main.cpp \
+ Dump_Restore.h
+
+main_LDADD = \
+ libDump_Restore.la \
+ $(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/netsvcs/clients/Naming/Dump_Restore/README b/ACE/netsvcs/clients/Naming/Dump_Restore/README
new file mode 100644
index 00000000000..25b1243d03f
--- /dev/null
+++ b/ACE/netsvcs/clients/Naming/Dump_Restore/README
@@ -0,0 +1,66 @@
+This file describes the usage of the Dump-Restore utility for the ACE
+Name Server.
+
+Similar to the test application provided in the ../Client/ directory,
+a simple ASCII menu-driven interface is provided to the user:
+
+ Name Service Main Menu
+ ----------------------
+ *** Using Process Local Database ***
+
+** No Input File Specified **
+<P> Use Process Local Database
+<N> Use Node Local Database
+<H> Set Remote Name server <host> and <port>
+<F> Set Input File <file name>
+
+<B> Bind
+<U> Unbind
+<R> Rebind
+<D> Dump <file name>
+<Q> or ^C (exit)
+
+Initially, the user can select the type of database from the menu:
+
+<P> uses the process local database (i.e., the
+ database is called the same name as the process
+ and stored in /tmp).
+<N> uses the node local database (which defaults
+ to /tmp/localnames).
+<H> uses the net local database by specifying host and port
+ number (by default this is stored in a file called
+ /tmp/globalnames on the server).
+<F> Sets the name of the input file that will be used by the
+ test application to populate the database. The format of
+ the file should be:
+
+ name=<name1>
+ value=<value1>
+ type=[<type1>]
+ name=<name2>
+ value=<value2>
+ type=[<type2>]
+ .
+ .
+ .
+
+ Note that the type field is optional. However, if no type
+ information is associated with a name binding, a null entry still
+ needs to be present (i.e., type=).
+
+Once the input file has been specified, the user can then do one of
+the following:
+
+<B> Bind -- bind all the bindings in the file to the database.
+ This can be used to "restore" the state of the
+ Name Server.
+<U> Unbind -- unbind all the bindings in the file from the database.
+<R> Rebind -- rebind all the bindings in the file to the database.
+<D> Dump <file name> -- dump the state of the database to <filename>.
+<Q> or ^C (exit) -- exit gracefully, saving the contents of the
+ Name Server in persistent shared memory.
+
+Note that the dump file is stored in ASCII with exactly the same
+format as the input file. Also, one can easily change the test
+application so that a call to Dump results in the state of the
+database dumped to standard output instead of a file.
diff --git a/ACE/netsvcs/clients/Naming/Dump_Restore/createfile.cpp b/ACE/netsvcs/clients/Naming/Dump_Restore/createfile.cpp
new file mode 100644
index 00000000000..25bf2fb803c
--- /dev/null
+++ b/ACE/netsvcs/clients/Naming/Dump_Restore/createfile.cpp
@@ -0,0 +1,34 @@
+// $Id$
+
+#include <stdio.h>
+#include <string.h>
+#include "ace/ACE.h"
+
+ACE_RCSID(Dump_Restore, createfile, "$Id$")
+
+int
+main (int argc, char **argv)
+{
+ FILE *infile, *outfile;
+ char buf[BUFSIZ];
+
+ if ((infile = fopen (argv[1], "r")) == NULL)
+ return -1;
+
+ if ((outfile = fopen (argv[2], "w")) == NULL)
+ return -1;
+
+ int count = 0;
+ while (::fgets (buf, BUFSIZ, infile))
+ {
+ buf[::strlen(buf) - 1] = '\0';
+ fputs (buf, outfile);
+ if (count % 2 == 0)
+ fputs (" ", outfile);
+ else
+ fputs ("\n", outfile);
+ count++;
+ }
+ fclose (outfile);
+ fclose (infile);
+}
diff --git a/ACE/netsvcs/clients/Naming/Dump_Restore/main.cpp b/ACE/netsvcs/clients/Naming/Dump_Restore/main.cpp
new file mode 100644
index 00000000000..46d298357bc
--- /dev/null
+++ b/ACE/netsvcs/clients/Naming/Dump_Restore/main.cpp
@@ -0,0 +1,26 @@
+// $Id$
+
+// Test the client-side of the ACE Name Server...
+
+#include "ace/Service_Config.h"
+#include "ace/Log_Msg.h"
+#include "Dump_Restore.h"
+
+ACE_RCSID(Dump_Restore, main, "$Id$")
+
+int
+ACE_TMAIN (int argc, ACE_TCHAR *argv[])
+{
+ ACE_Service_Config daemon (argv[0]);
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("entering main\n")));
+
+ // Get a handler
+ Dump_Restore client_handler (argc, argv);
+
+ ACE_Reactor::run_event_loop ();
+
+ /* NOTREACHED */
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("leaving main\n")));
+ return 0;
+}
diff --git a/ACE/netsvcs/clients/Naming/Makefile.am b/ACE/netsvcs/clients/Naming/Makefile.am
new file mode 100644
index 00000000000..883b9bab54d
--- /dev/null
+++ b/ACE/netsvcs/clients/Naming/Makefile.am
@@ -0,0 +1,14 @@
+## 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 = \
+ Client \
+ Dump_Restore
+
diff --git a/ACE/netsvcs/clients/README b/ACE/netsvcs/clients/README
new file mode 100644
index 00000000000..d47c9bfe7ff
--- /dev/null
+++ b/ACE/netsvcs/clients/README
@@ -0,0 +1,8 @@
+This directory contains a number of test programs that illustrate how
+to write clients for the various ACE network services.
+
+ . Logger -- client programs that illustrate the ACE logging service.
+
+ . Naming -- client programs that illustrate the ACE name service.
+
+ . Tokens -- client programs that illustrate the ACE token service.
diff --git a/ACE/netsvcs/clients/Tokens/Makefile.am b/ACE/netsvcs/clients/Tokens/Makefile.am
new file mode 100644
index 00000000000..37d4b007538
--- /dev/null
+++ b/ACE/netsvcs/clients/Tokens/Makefile.am
@@ -0,0 +1,17 @@
+##----------------------------------------------------------------------------
+## $Id$
+##
+## Makefile for the Token tests
+##----------------------------------------------------------------------------
+
+##
+## Process this file with automake to create Makefile.in
+##
+
+SUBDIRS = \
+ collection \
+ deadlock \
+ invariant \
+ manual \
+ mutex \
+ rw_lock
diff --git a/ACE/netsvcs/clients/Tokens/README b/ACE/netsvcs/clients/Tokens/README
new file mode 100644
index 00000000000..3b6313a1df7
--- /dev/null
+++ b/ACE/netsvcs/clients/Tokens/README
@@ -0,0 +1,34 @@
+This directory contains a set of tests for the ACE Tokens library.
+
+ . mutex
+
+ Runs a few tests on ACE_Local_Mutex and
+ ACE_Remote_Mutex. Tests recursive acquisition and
+ global vs local proxies.
+
+ . rw_locks
+
+ App for testing ACE_Local_RLock, ACE_Local_WLock,
+ ACE_Remote_RLock, and ACE_Remote_WLock.
+
+ . deadlock
+
+ Tests the deadlock detection algorithm of the token
+ manager using ACE_Local_Mutex and ACE_Remote_Mutex.
+
+ . collection
+
+ Tests the ACE_Token_Collection utility. Uses local
+ and remote tokens and readers/writer locks.
+
+ . invariant
+
+ Tests the token Invariant testing utilities. Yes,
+ this tests a testing utility.
+
+ . manual
+
+ Gives users a text-based interactive interface to
+ local or remote tokens. This is extremely useful for
+ manually testing the token server and setting up
+ deadlock scenarios.
diff --git a/ACE/netsvcs/clients/Tokens/collection/Makefile.am b/ACE/netsvcs/clients/Tokens/collection/Makefile.am
new file mode 100644
index 00000000000..9d3fbcc5ddd
--- /dev/null
+++ b/ACE/netsvcs/clients/Tokens/collection/Makefile.am
@@ -0,0 +1,18 @@
+##----------------------------------------------------------------------------
+## $Id$
+##
+## Makefile for repeating token client application
+##----------------------------------------------------------------------------
+
+##
+## Process this file with automake to create Makefile.in
+##
+
+AM_CPPFLAGS = -I$(top_builddir) -I$(top_srcdir)
+
+noinst_PROGRAMS = \
+ collection
+
+collection_SOURCES = collection.cpp
+collection_LDADD = $(top_builddir)/netsvcs/lib/libnetsvcs.la \
+ $(top_builddir)/ace/libACE.la
diff --git a/ACE/netsvcs/clients/Tokens/collection/README b/ACE/netsvcs/clients/Tokens/collection/README
new file mode 100644
index 00000000000..4c25a1f729e
--- /dev/null
+++ b/ACE/netsvcs/clients/Tokens/collection/README
@@ -0,0 +1,25 @@
+
+Shows how applications can use the ACE_Token_Collection utility. This
+example creates three collections and spawns a thread to operate on
+each. The threads use the collective acquire, renew, and release
+features of ACE_Token_Collection.
+
+Here are the command-line parameters for collection:
+
+./collection:
+[-h <remote host>]
+[-p <remote port>]
+[-n <iterations>]
+[-d debug]
+
+To run the collection locally with debugging info, type
+
+% ./collection -d
+
+To run the collection remotely with debugging info, first start a
+token server and the type:
+
+% ./collection -d -h <token-server-host> -p <token-server-port>
+
+The -n <iterations> option is to control how often each thread
+iterates on the acquire, renew, release cycle.
diff --git a/ACE/netsvcs/clients/Tokens/collection/collection.cpp b/ACE/netsvcs/clients/Tokens/collection/collection.cpp
new file mode 100644
index 00000000000..8df0ae625fc
--- /dev/null
+++ b/ACE/netsvcs/clients/Tokens/collection/collection.cpp
@@ -0,0 +1,210 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// examples
+//
+// = FILENAME
+// collection.cpp
+//
+// = DESCRIPTION
+// Shows how applications can use the ACE_Token_Collection
+// utility. This example creates three collections and spawns a
+// thread to operate on each. The threads use the collective
+// acquire, renew, and release features of ACE_Token_Collection.
+//
+// = AUTHOR
+// Tim Harrison
+//
+// ============================================================================
+
+#include "ace/Get_Opt.h"
+#include "ace/Local_Tokens.h"
+#include "ace/Token_Collection.h"
+#include "ace/Remote_Tokens.h"
+#include "ace/Thread_Manager.h"
+#include "ace/Service_Config.h"
+
+ACE_RCSID(collection, collection, "$Id$")
+
+#if defined (ACE_HAS_THREADS) && defined (ACE_HAS_THREADS_LIBRARY)
+
+static const char *server_host = ACE_DEFAULT_SERVER_HOST;
+static int server_port = ACE_DEFAULT_SERVER_PORT;
+// unused: static int threads = 2;
+static int iterations = 50;
+static int debug = 0;
+static int remote = 0;
+// unused: static int tokens = 5;
+
+static void *
+run_thread (void *vp)
+{
+ ACE_Token_Proxy *collection = (ACE_Token_Proxy *) vp;
+
+ int count = iterations;
+ while (count--)
+ {
+ if (collection->acquire () == -1)
+ {
+ if (ACE_OS::last_error () == EDEADLK)
+ {
+ ACE_DEBUG ((LM_DEBUG, "deadlock detected in acquire"));
+ continue;
+ }
+ ACE_ERROR ((LM_ERROR, "(%t) %p acquire failed\n","run_thread"));
+ return (void *) -1;
+ }
+
+ ACE_DEBUG ((LM_DEBUG, "(%t) %s acquired.\n", collection->name ()));
+
+ if (collection->renew () == -1)
+ {
+ if (ACE_OS::last_error () == EDEADLK)
+ {
+ ACE_DEBUG ((LM_DEBUG, "deadlock detected"));
+ goto deadlock;
+ }
+ ACE_ERROR ((LM_ERROR, "(%t) %p renew failed\n","run_thread"));
+ return (void *) -1;
+ }
+
+ ACE_DEBUG ((LM_DEBUG, "(%t) %s renewed.\n", collection->name ()));
+
+ deadlock:
+ if (collection->release () == -1)
+ {
+ ACE_ERROR ((LM_ERROR, "(%t) %p release failed\n","run_thread"));
+ return (void *) -1;
+ }
+
+ ACE_DEBUG ((LM_DEBUG, "(%t) %s released.\n", collection->name ()));
+ }
+
+
+ ACE_DEBUG ((LM_DEBUG, "(%t) thread exiting.\n"));
+ return 0;
+}
+
+static int
+parse_args (int argc, char *argv[])
+{
+ ACE_LOG_MSG->open (argv[0], ACE_Log_Msg::STDERR); // | ACE_Log_Msg::VERBOSE);
+
+ ACE_Get_Opt get_opt (argc, argv, "un:dp:h:", 1);
+
+ for (int c; (c = get_opt ()) != -1; )
+ {
+ switch (c)
+ {
+ case 'h': // specify the host machine on which the server is running
+ server_host = get_opt.opt_arg ();
+ remote = 1;
+ break;
+ case 'p': // specify the port on which the server is running
+ server_port = ACE_OS::atoi (get_opt.opt_arg ());
+ remote = 1;
+ break;
+ case 'd':
+ debug = 1;
+ break;
+ case 'n':
+ iterations = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'u':
+ // usage: fallthrough
+ default:
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "%n:\n"
+ "[-h <remote host>]\n"
+ "[-p <remote port>]\n"
+ "[-n <iterations>]\n"
+ "[-d debug]\n", 1), -1);
+ /* NOTREACHED */
+ }
+ }
+
+ return 0;
+}
+
+int
+main (int argc, char* argv[])
+{
+ if (parse_args (argc, argv) == -1)
+ return -1;
+
+ ACE_Token_Proxy *A; // Mutex *A*.
+ ACE_Token_Proxy *B; // Mutex *B*.
+ ACE_Token_Proxy *R; // *R*eader Lock.
+ ACE_Token_Proxy *W; // *W*riter Lock.
+
+ // Depending on the command line arguments, we will create local or
+ // remote tokens. The names of the tokens are not important as long
+ // as they are unique.
+ if (remote)
+ {
+ ACE_Remote_Mutex::set_server_address (ACE_INET_Addr (server_port, server_host));
+ A = new ACE_Remote_Mutex ("R Mutex A", 0, debug);
+ B = new ACE_Remote_Mutex ("R Mutex B", 0, debug);
+ R = new ACE_Remote_RLock ("R Reader Lock", 0, debug);
+ W = new ACE_Remote_WLock ("R Writer Lock", 0, debug);
+ }
+ else
+ {
+ A = new ACE_Local_Mutex ("L Mutex A", 0, debug);
+ B = new ACE_Local_Mutex ("L Mutex B", 0, debug);
+ R = new ACE_Local_RLock ("L Reader Lock", 0, debug);
+ W = new ACE_Local_WLock ("L Writer Lock", 0, debug);
+ }
+
+ // These collections will be treated as Tokens by the threads.
+ ACE_Token_Collection collectionAR (debug, "A and Reader");
+ ACE_Token_Collection collectionAW (debug, "A and Writer");
+ ACE_Token_Collection collectionBR (debug, "B and Reader");
+
+ // AR and BR can run concurrently. Neither AR or BR can run when AW
+ // is running.
+ collectionAR.insert (*A);
+ collectionAR.insert (*R);
+
+ collectionAW.insert (*A);
+ collectionAW.insert (*W);
+
+ collectionBR.insert (*B);
+ collectionBR.insert (*R);
+
+ // Spawn off three threads.
+ ACE_Thread_Manager *mgr = ACE_Thread_Manager::instance ();
+
+ if (mgr->spawn (ACE_THR_FUNC (run_thread),
+ (void *) &collectionAR, THR_BOUND | THR_SUSPENDED) == -1)
+ ACE_ERROR_RETURN ((LM_DEBUG, "%p\n", "spawn 1 failed"), -1);
+
+ if (mgr->spawn (ACE_THR_FUNC (run_thread),
+ (void *) &collectionAW, THR_BOUND | THR_SUSPENDED) == -1)
+ ACE_ERROR_RETURN ((LM_DEBUG, "%p\n", "spawn 2 failed"), -1);
+
+ if (mgr->spawn (ACE_THR_FUNC (run_thread),
+ (void *) &collectionBR, THR_BOUND | THR_SUSPENDED) == -1)
+ ACE_ERROR_RETURN ((LM_DEBUG, "%p\n", "spawn 3 failed"), -1);
+
+#if ! defined (ACE_HAS_PTHREADS)
+ if (mgr->resume_all () == -1)
+ ACE_ERROR_RETURN ((LM_DEBUG, "%p\n", "resume failed"), -1);
+#endif
+
+ // Wait for all threads to exit.
+ mgr->wait ();
+
+ return 0;
+}
+
+#else
+int
+main (int, char *[])
+{
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "threads not supported on this platform\n"), -1);
+}
+#endif /* ACE_HAS_THREADS && ACE_HAS_TOKENS_LIBRARY */
diff --git a/ACE/netsvcs/clients/Tokens/collection/rw_locks.cpp b/ACE/netsvcs/clients/Tokens/collection/rw_locks.cpp
new file mode 100644
index 00000000000..2670f99214f
--- /dev/null
+++ b/ACE/netsvcs/clients/Tokens/collection/rw_locks.cpp
@@ -0,0 +1,173 @@
+// $Id$
+
+#include "ace/Get_Opt.h"
+#include "ace/Local_Tokens.h"
+#include "ace/Remote_Tokens.h"
+#include "ace/Thread_Manager.h"
+
+#if defined (ACE_HAS_THREADS) && defined (ACE_HAS_THREADS_LIBRARY)
+
+ACE_RCSID(collection, rw_locks, "$Id$")
+
+static ACE_Token_Proxy *global_rlock;
+static ACE_Token_Proxy *global_wlock;
+
+static char *server_host = ACE_DEFAULT_SERVER_HOST;
+static int server_port = ACE_DEFAULT_SERVER_PORT;
+static int ignore_deadlock = 0;
+static int threads = 2;
+static int iterations = 50;
+static int debug = 0;
+static int remote = 0;
+static int reads = 4;
+static int write_sleep = 0;
+
+static void *
+run_thread (void *vp)
+{
+ for (int x = 0; x < iterations; x++)
+ {
+ int y = 0;
+ for (; y < reads; y++)
+ {
+ if (global_rlock->acquire () == -1)
+ {
+ if (ACE_Log_Msg::instance ()->errnum () == EDEADLK)
+ {
+ ACE_DEBUG ((LM_DEBUG, "rlock deadlock detected\n"));
+ goto READ_DEADLOCK;
+ }
+ else return 0;
+ }
+
+ ACE_DEBUG ((LM_DEBUG, "(%t) rlock acquired.\n"));
+ }
+
+ READ_DEADLOCK:
+
+ for (; y > 0; y--)
+ {
+ if (global_rlock->release () == 0)
+ ACE_DEBUG ((LM_DEBUG, "(%t) r-released.\n"));
+ }
+
+ if (global_wlock->acquire () == -1)
+ {
+ ACE_DEBUG ((LM_DEBUG, "wlock deadlock detected\n"));
+ }
+ else
+ {
+ if (write_sleep)
+ ACE_OS::sleep (1);
+ ACE_DEBUG ((LM_DEBUG, "\t\t(%t) wlock acquired.\n"));
+ if (global_wlock->release () == 0)
+ ACE_DEBUG ((LM_DEBUG, "\t\t(%t) w-released.\n"));
+ }
+ }
+
+ ACE_DEBUG ((LM_DEBUG, "(%t) thread exiting.\n"));
+ return 0;
+}
+
+static int
+parse_args (int argc, char *argv[])
+{
+ ACE_LOG_MSG->open (argv[0], ACE_Log_Msg::STDERR); // | ACE_Log_Msg::VERBOSE);
+
+ ACE_Get_Opt get_opt (argc, argv, "t:iun:drR:sp:h:", 1);
+
+ for (int c; (c = get_opt ()) != -1; )
+ {
+ switch (c)
+ {
+ case 'h': // specify the host machine on which the server is running
+ server_host = get_opt.opt_arg ();
+ break;
+ case 'p': // specify the port on which the server is running
+ server_port = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 't':
+ threads = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'R':
+ reads = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'd':
+ debug = 1;
+ break;
+ case 'r':
+ remote = 1;
+ break;
+ case 's':
+ write_sleep = 1;
+ break;
+ case 'n':
+ iterations = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'i':
+ ignore_deadlock = 1;
+ break;
+ case 'u':
+ // usage: fallthrough
+ default:
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "%n:\n"
+ "[-i ignore deadlock]\n"
+ "[-n <iterations>]\n"
+ "[-R <reads>]\n"
+ "[-r use remote locks]\n"
+ "[-d debug]\n"
+ "[-s sleep during writes]\n"
+ "[-t <threads>\n", 1), -1);
+ break;
+ }
+ }
+
+ return 0;
+}
+
+int
+main (int argc, char* argv[])
+{
+ if (parse_args (argc, argv) == -1)
+ return -1;
+
+ if (remote)
+ {
+ ACE_Remote_Mutex::set_server_address (ACE_INET_Addr (server_port, server_host));
+ global_rlock = (ACE_Token_Proxy *) new
+ ACE_Remote_RLock ("THE_TOKEN", ignore_deadlock, debug);
+ global_wlock = (ACE_Token_Proxy *) new
+ ACE_Remote_WLock ("THE_TOKEN", ignore_deadlock, debug);
+ }
+ else
+ {
+ global_rlock = (ACE_Token_Proxy *) new
+ ACE_Local_RLock ("THE_TOKEN", ignore_deadlock, debug);
+ global_wlock = (ACE_Token_Proxy *) new
+ ACE_Local_WLock ("THE_TOKEN", ignore_deadlock, debug);
+ }
+
+ ACE_Thread_Manager mgr;
+
+ if (mgr.spawn_n (threads, ACE_THR_FUNC (run_thread),
+ (void *) 0,
+ THR_BOUND | THR_SUSPENDED) == -1)
+ ACE_ERROR_RETURN ((LM_DEBUG, "%p\n", "spawn failed"), -1);
+
+ if (mgr.resume_all () == -1)
+ ACE_ERROR_RETURN ((LM_DEBUG, "%p\n", "resume failed"), -1);
+
+ mgr.wait ();
+
+ return 0;
+}
+
+#else
+int
+main (int, char *[])
+{
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "threads not supported on this platform\n"), -1);
+}
+#endif /* ACE_HAS_THREADS */
diff --git a/ACE/netsvcs/clients/Tokens/deadlock/Makefile.am b/ACE/netsvcs/clients/Tokens/deadlock/Makefile.am
new file mode 100644
index 00000000000..d995e71620b
--- /dev/null
+++ b/ACE/netsvcs/clients/Tokens/deadlock/Makefile.am
@@ -0,0 +1,19 @@
+##----------------------------------------------------------------------------
+## $Id$
+##
+## Makefile for repeating token client application
+##----------------------------------------------------------------------------
+
+##
+## Process this file with automake to create Makefile.in
+##
+
+AM_CPPFLAGS = -I$(top_builddir) -I$(top_srcdir)
+
+noinst_PROGRAMS = \
+ deadlock_detection_test
+
+deadlock_detection_test_SOURCES = deadlock_detection_test.cpp
+deadlock_detection_test_LDADD = \
+ $(top_builddir)/netsvcs/lib/libnetsvcs.la \
+ $(top_builddir)/ace/libACE.la
diff --git a/ACE/netsvcs/clients/Tokens/deadlock/README b/ACE/netsvcs/clients/Tokens/deadlock/README
new file mode 100644
index 00000000000..74fffde05cd
--- /dev/null
+++ b/ACE/netsvcs/clients/Tokens/deadlock/README
@@ -0,0 +1,98 @@
+
+deadlock_detection_test
+
+This example contains two deadlock tests, mutex and rwlock tests.
+% ./deadlock_detection_test -u
+./deadlock_detection_test:
+[-r test readers/writer locks]
+[-n <iterations>]
+[-h <remote host>]
+[-p <remote port>]
+[-i ignore deadlock]
+
+For both mutex and rwlock tests, -h and -p specify to use remote
+mutexes. -i specifies to ignore deadlock. -n is repetitions through
+the respective algorithms (default 100). Both tests also use Token
+Invariants to ensure correctness of the mutexes and readers/writer
+locks.
+
+------------------------------------------------------------
+
+If you run ./deadlock_detection_test without -r, then the following
+mutex test is run.
+
+The mutex test spawns two threads which attempt to deadlock.
+Logically, there are two tokens A and B. Here is what both threads
+try to do:
+
+Thread 1 Thread 2
+-------- --------
+Repeat 100 times Repeat 100 times
+ acquire A acquire B
+ acquire B acquire A
+ release A and B release A and B
+repeat repeat
+
+Notice that A and B are reversed in 1 and 2. If the token manager
+(which is not in the public interface, but hidden behind
+ACE_Local_Mutex) works properly, they should detect the deadlock. If
+a thread detects deadlock, the resources held are released, and it
+starts the whole process over again.
+
+What can be confusing about the test program is all the other tricks
+I'm pulling to test other aspects of the library. For instance, I'm
+using both "global" and "local" ACE_Local_Mutexes. This is to test
+the ability to have multiple threads using one token proxy as well as
+multiple threads each using their own proxies. All the while, the
+same logical token is being used. If this doesn't make sense, don't
+worry about it. Just use the ACE_Local_Mutex any way you want.
+
+Another confusing trick is that I'm testing recursive acquisition.
+(Two acquires in a row.) I have to make sure that the token manager
+doesn't detect a recursive acquire as deadlock.
+
+To run a test, simply type:
+% ./deadlock_detection_test
+
+This should run 100 times through the above pseudo code. If the
+application halts, then we have trouble. It should never ever halt.
+I've included a little flag with the ACE_Local_Mutex class to allow
+deadlock detection to be ignored. So, if you run the test as follows,
+deadlock detection will be ignored.
+
+% ./deadlock_detection_test -i
+
+In this case, the application should only run about a second before
+deadlock occurs and the application halts. This is good.
+
+------------------------------------------------------------
+
+If you run ./deadlock_detection_test *with* -r, then the following
+rwlock test is run:
+
+There are four tokens and four threads in the rwlock test. The
+readers/writer tokens are:
+
+reader first
+writer first 1
+writer first 2
+writer first 3
+
+There are three reader threads that only acquire reader locks on the
+above tokens. Each of the reader threads first acquire "reader first"
+and then one "writer first <tid>" (where <tid> is the corresponding
+thread's id). So reader thread 1 acquires "reader first" and then
+"writer first 1".
+
+There is a single writer thread that uses the following algorithm:
+
+repeat 100
+ acquire "writer first 1"
+ acquire "reader first"
+ acquire "writer first 2"
+ acquire "reader first"
+ acquire "writer first 3"
+ acquire "reader first"
+
+This strange mix of readers and writer create an interesting graph of
+tokens that the deadlock detection algorithm must traverse.
diff --git a/ACE/netsvcs/clients/Tokens/deadlock/deadlock_detection_test.cpp b/ACE/netsvcs/clients/Tokens/deadlock/deadlock_detection_test.cpp
new file mode 100644
index 00000000000..e1a9d60ccd6
--- /dev/null
+++ b/ACE/netsvcs/clients/Tokens/deadlock/deadlock_detection_test.cpp
@@ -0,0 +1,340 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// examples
+//
+// = FILENAME
+// deadlock_detection_test.cpp
+//
+// = DESCRIPTION
+//
+// = AUTHOR
+// Tim Harrison
+//
+// ============================================================================
+
+#include "ace/Token_Manager.h"
+#include "ace/Remote_Tokens.h"
+#include "ace/Thread.h"
+#include "ace/Thread_Manager.h"
+#include "ace/Get_Opt.h"
+#include "ace/Token_Invariants.h"
+
+#if defined (ACE_HAS_THREADS) && defined (ACE_HAS_THREADS_LIBRARY)
+
+ACE_RCSID(deadlock, deadlock_detection_test, "$Id$")
+
+typedef ACE_Token_Invariant_Manager ACE_TOKEN_INVARIANTS;
+
+static ACE_Token_Proxy *global_mutex;
+
+struct Two_Tokens
+{
+public:
+ Two_Tokens (ACE_Thread_Manager *tm): thr_mgr_ (tm) {}
+ ACE_Token_Proxy *first_;
+ ACE_Token_Proxy *second_;
+ ACE_Thread_Manager *thr_mgr_;
+};
+
+struct Four_Tokens
+{
+public:
+ Four_Tokens (ACE_Thread_Manager *tm): thr_mgr_ (tm) {}
+ ACE_Token_Proxy *first1_;
+ ACE_Token_Proxy *first2_;
+ ACE_Token_Proxy *first3_;
+ ACE_Token_Proxy *second_;
+ ACE_Thread_Manager *thr_mgr_;
+};
+
+static int ignore_deadlock = 0;
+static int remote_mutexes = 0;
+static const char *server_host = ACE_DEFAULT_SERVER_HOST;
+static int server_port = ACE_DEFAULT_SERVER_PORT;
+static int iterations = 100;
+static int rwlocks = 0;
+
+static void *
+two_token_thread (void *vp)
+{
+ Two_Tokens* tm = (Two_Tokens *) vp;
+
+ for (int x = 0; x < iterations; x++)
+ {
+ if (tm->first_->acquire () == -1)
+ {
+ ACE_DEBUG ((LM_DEBUG, "Deadlock detected\n"));
+ continue;
+ }
+
+ if (ACE_TOKEN_INVARIANTS::instance ()->acquired (tm->first_) == 0)
+ {
+ tm->first_->dump ();
+ ACE_ERROR_RETURN ((LM_ERROR, "violated invariant.\n"), 0);
+ }
+
+ if (tm->second_->acquire () == -1)
+ {
+ ACE_DEBUG ((LM_DEBUG, "Deadlock Detected\n"));
+ goto G1;
+ }
+
+ if (ACE_TOKEN_INVARIANTS::instance ()->acquired (tm->second_) == 0)
+ {
+ tm->second_->dump ();
+ ACE_ERROR_RETURN ((LM_ERROR, "violated invariant.\n"), 0);
+ }
+
+ ACE_TOKEN_INVARIANTS::instance ()->releasing (tm->second_);
+
+ tm->second_->release ();
+ G1:
+ ACE_TOKEN_INVARIANTS::instance ()->releasing (tm->first_);
+
+ tm->first_->release ();
+ }
+
+ ACE_DEBUG ((LM_DEBUG, "thread %t exiting\n"));
+ return 0;
+}
+
+static void *
+run_writer (void *vp)
+{
+ Four_Tokens *ft = (Four_Tokens *) vp;
+ int acquire_number = 0;
+
+ for (int x = 0; x < iterations; x++)
+ {
+ // Cycle through each of the first three tokens.
+ ACE_Token_Proxy *t = 0;
+ switch (acquire_number)
+ {
+ case 0:
+ t = ft->first1_;
+ break;
+ case 1:
+ t = ft->first2_;
+ break;
+ case 2:
+ t = ft->first3_;
+ break;
+ }
+
+ acquire_number = (acquire_number + 1) % 3;
+
+ if (t->acquire () == -1)
+ {
+ ACE_ASSERT (errno == EDEADLK);
+ ACE_DEBUG ((LM_DEBUG, "Deadlock detected.\n"));
+ continue;
+ }
+
+ if (ACE_TOKEN_INVARIANTS::instance ()->acquired (t) == 0)
+ {
+ t->dump ();
+ ACE_ERROR_RETURN ((LM_ERROR, "violated invariant.\n"), 0);
+ }
+
+ if (ft->second_->acquire () == -1)
+ {
+ ACE_ASSERT (errno == EDEADLK);
+ ACE_DEBUG ((LM_DEBUG, "Deadlock Detected..\n"));
+ goto G1;
+ }
+
+ if (ACE_TOKEN_INVARIANTS::instance ()->acquired (ft->second_) == 0)
+ {
+ ft->second_->dump ();
+ ACE_ERROR_RETURN ((LM_ERROR, "violated invariant.\n"), 0);
+ }
+
+ ACE_TOKEN_INVARIANTS::instance ()->releasing (ft->second_);
+
+ ft->second_->release ();
+ G1:
+ ACE_TOKEN_INVARIANTS::instance ()->releasing (t);
+
+ t->release ();
+ }
+
+ ACE_DEBUG ((LM_DEBUG, "thread %t exiting\n"));
+ return 0;
+}
+
+static int
+parse_args (int argc, char *argv[])
+{
+ ACE_LOG_MSG->open (argv[0]);
+
+ ACE_Get_Opt get_opt (argc, argv, "iuh:rp:n:", 1);
+
+ for (int c; (c = get_opt ()) != -1; )
+ {
+ switch (c)
+ {
+ case 'r':
+ rwlocks = 1;
+ break;
+ case 'i':
+ ignore_deadlock = 1;
+ break;
+ case 'h':
+ server_host = get_opt.opt_arg ();
+ remote_mutexes = 1;
+ break;
+ case 'p':
+ server_port = ACE_OS::atoi (get_opt.opt_arg ());
+ remote_mutexes = 1;
+ break;
+ case 'n':
+ iterations = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'u':
+ default:
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "%n:\n"
+ "[-r test readers/writer locks]\n"
+ "[-n <iterations>]\n"
+ "[-h <remote host>]\n"
+ "[-p <remote port>]\n"
+ "[-i ignore deadlock]\n%a", 1), -1);
+ }
+ }
+
+ return 0;
+}
+
+int
+mutex_test (void)
+{
+ ACE_Thread_Manager thr_mgr;
+
+ Two_Tokens one (&thr_mgr);
+ Two_Tokens two (&thr_mgr);
+
+ if (remote_mutexes == 0)
+ {
+ global_mutex = new ACE_Local_Mutex ("global proxy", ignore_deadlock, 1);
+ one.first_ = new ACE_Local_Mutex ("local proxy", ignore_deadlock, 1);
+ two.second_ = new ACE_Local_Mutex ("local proxy", ignore_deadlock, 1);
+ }
+ else
+ {
+ ACE_Remote_Mutex::set_server_address (ACE_INET_Addr (server_port, server_host));
+ global_mutex = new ACE_Remote_Mutex ("global proxy", ignore_deadlock, 1);
+ one.first_ = new ACE_Remote_Mutex ("local proxy", ignore_deadlock, 1);
+ two.second_ = new ACE_Remote_Mutex ("local proxy", ignore_deadlock, 1);
+ }
+
+ one.second_ = global_mutex;
+ two.first_ = global_mutex;
+
+ // Tell the token manager to be verbose when reporting deadlock.
+ ACE_Token_Manager::instance ()->debug (1);
+
+ if (thr_mgr.spawn (ACE_THR_FUNC (two_token_thread),
+ (void *) &one, THR_BOUND) == -1)
+ ACE_ERROR_RETURN ((LM_DEBUG, "%p\n", "first spawn"), -1);
+
+ if (thr_mgr.spawn (ACE_THR_FUNC (two_token_thread),
+ (void *) &two, THR_BOUND) == -1)
+ ACE_ERROR_RETURN ((LM_DEBUG, "%p\n", "second spawn"), -1);
+
+ // Wait for all threads to exit.
+ thr_mgr.wait ();
+
+ return 0;
+}
+
+static int
+rwlock_test (void)
+{
+ ACE_Thread_Manager thr_mgr;
+
+ Two_Tokens reader1 (&thr_mgr);
+ Two_Tokens reader2 (&thr_mgr);
+ Two_Tokens reader3 (&thr_mgr);
+ Four_Tokens writer (&thr_mgr);
+
+ if (remote_mutexes == 0)
+ {
+ reader1.first_ = new ACE_Local_RLock ("reader first", ignore_deadlock, 1);
+ reader1.second_ = new ACE_Local_RLock ("writer first 1", ignore_deadlock, 1);
+ reader2.first_ = new ACE_Local_RLock ("reader first", ignore_deadlock, 1);
+ reader2.second_ = new ACE_Local_RLock ("writer first 2", ignore_deadlock, 1);
+ reader3.first_ = new ACE_Local_RLock ("reader first", ignore_deadlock, 1);
+ reader3.second_ = new ACE_Local_RLock ("writer first 3", ignore_deadlock, 1);
+
+ writer.first1_ = new ACE_Local_WLock ("writer first 1", ignore_deadlock, 1);
+ writer.first2_ = new ACE_Local_WLock ("writer first 2", ignore_deadlock, 1);
+ writer.first3_ = new ACE_Local_WLock ("writer first 3", ignore_deadlock, 1);
+ writer.second_ = new ACE_Local_WLock ("reader first", ignore_deadlock, 1);
+ }
+ else
+ {
+ ACE_Remote_Mutex::set_server_address (ACE_INET_Addr (server_port, server_host));
+
+ reader1.first_ = new ACE_Remote_RLock ("writer first 1", ignore_deadlock, 1);
+ reader1.second_ = new ACE_Remote_RLock ("reader first", ignore_deadlock, 1);
+ reader2.first_ = new ACE_Remote_RLock ("writer first 2", ignore_deadlock, 1);
+ reader2.second_ = new ACE_Remote_RLock ("reader first", ignore_deadlock, 1);
+ reader3.first_ = new ACE_Remote_RLock ("writer first 3", ignore_deadlock, 1);
+ reader3.second_ = new ACE_Remote_RLock ("reader first", ignore_deadlock, 1);
+
+ writer.first1_ = new ACE_Remote_WLock ("writer first 1", ignore_deadlock, 1);
+ writer.first2_ = new ACE_Remote_WLock ("writer first 2", ignore_deadlock, 1);
+ writer.first3_ = new ACE_Remote_WLock ("writer first 3", ignore_deadlock, 1);
+ writer.second_ = new ACE_Remote_WLock ("reader first", ignore_deadlock, 1);
+ }
+
+ // Tell the token manager to be verbose when reporting deadlock.
+ ACE_Token_Manager::instance ()->debug (1);
+
+ if (thr_mgr.spawn (ACE_THR_FUNC (two_token_thread),
+ (void *) &reader1, THR_BOUND) == -1)
+ ACE_ERROR_RETURN ((LM_DEBUG, "%p\n", "first spawn"), -1);
+
+ if (thr_mgr.spawn (ACE_THR_FUNC (two_token_thread),
+ (void *) &reader2, THR_BOUND) == -1)
+ ACE_ERROR_RETURN ((LM_DEBUG, "%p\n", "first spawn"), -1);
+
+ if (thr_mgr.spawn (ACE_THR_FUNC (two_token_thread),
+ (void *) &reader3, THR_BOUND) == -1)
+ ACE_ERROR_RETURN ((LM_DEBUG, "%p\n", "first spawn"), -1);
+
+ if (thr_mgr.spawn (ACE_THR_FUNC (run_writer),
+ (void *) &writer, THR_BOUND) == -1)
+ ACE_ERROR_RETURN ((LM_DEBUG, "%p\n", "second spawn"), -1);
+
+ // Wait for all threads to exit.
+ thr_mgr.wait ();
+
+ return 0;
+}
+
+int
+main (int argc, char* argv[])
+{
+ if (parse_args (argc, argv) == -1)
+ return -1;
+
+ if (rwlocks)
+ rwlock_test ();
+ else
+ mutex_test ();
+
+ ACE_DEBUG ((LM_DEBUG, "test exiting.\n"));
+ return 0;
+}
+#else
+int
+main (int, char *[])
+{
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "threads not supported on this platform\n"), -1);
+}
+#endif /* ACE_HAS_THREADS */
diff --git a/ACE/netsvcs/clients/Tokens/invariant/Makefile.am b/ACE/netsvcs/clients/Tokens/invariant/Makefile.am
new file mode 100644
index 00000000000..37817911015
--- /dev/null
+++ b/ACE/netsvcs/clients/Tokens/invariant/Makefile.am
@@ -0,0 +1,20 @@
+##----------------------------------------------------------------------------
+## $Id$
+##
+## Makefile for repeating token client application
+##----------------------------------------------------------------------------
+
+##
+## Process this file with automake to create Makefile.in
+##
+
+AM_CPPFLAGS = -I$(top_builddir) -I$(top_srcdir)
+
+noinst_PROGRAMS = \
+ invariant
+
+invariant_SOURCES = invariant.cpp
+invariant_LDADD = \
+ $(top_builddir)/netsvcs/lib/libnetsvcs.la \
+ $(top_builddir)/ace/libACE.la
+
diff --git a/ACE/netsvcs/clients/Tokens/invariant/README b/ACE/netsvcs/clients/Tokens/invariant/README
new file mode 100644
index 00000000000..f078c2d6be4
--- /dev/null
+++ b/ACE/netsvcs/clients/Tokens/invariant/README
@@ -0,0 +1,27 @@
+
+invariants.cpp tests the ACE Token Invariant utilities. The ACE Token
+Invariant utilities allow an application to test the correctness of
+mutex and readers/writer locks.
+
+invariants.cpp takes no command-line arguments. invariants.cpp first
+tests readers/writer locks. This is done by spawning two threads
+which simulate reader and writer acquire/renew/release loops.
+However, the loops are performed without actual locks, so the
+competing threads quickly reach and invalid state. The test should
+report this violation of readers/writer lock invariants and both
+threads should exit.
+
+The second test is for mutexes. Similar to the readers/writer lock
+test, this test spawns two threads which perform acquire/renew/release
+loops. When to two threads reach an invalid mutex state, the error
+should be reported and the threads should exit.
+
+For these two previous tests, it is theoretically possible that the
+threads never reach an invalid token state. However, it is highly
+unlikely since the threads would have to execute the same code
+simultaneously for the duration of the test. Nevertheless, it is
+possible.
+
+The last test hardwires invalid token states. It runs two mutex and
+two readers/writer lock tests. It should report "succeeded" for the
+four tests.
diff --git a/ACE/netsvcs/clients/Tokens/invariant/invariant.cpp b/ACE/netsvcs/clients/Tokens/invariant/invariant.cpp
new file mode 100644
index 00000000000..cda1f54f6f7
--- /dev/null
+++ b/ACE/netsvcs/clients/Tokens/invariant/invariant.cpp
@@ -0,0 +1,196 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// examples
+//
+// = FILENAME
+// invariant.cpp
+//
+// = DESCRIPTION
+//
+// = AUTHOR
+// Tim Harrison
+//
+// ============================================================================
+
+#include "ace/Get_Opt.h"
+#include "ace/Singleton.h"
+#include "ace/Thread_Manager.h"
+#include "ace/Token_Invariants.h"
+
+#if defined (ACE_HAS_THREADS) && defined (ACE_HAS_THREADS_LIBRARY)
+
+ACE_RCSID(invariant, invariant, "$Id$")
+
+typedef ACE_Token_Invariant_Manager ACE_TOKEN_INVARIANTS;
+
+static const char *rwname = "reader/writer";
+static const char *mutexname = "mutex";
+
+static void *
+run_reader_writer (void *)
+{
+ for (int x = 0; x < 50; x++)
+ {
+ int y = 0;
+ for (; y < 5; y++)
+ {
+ if (ACE_TOKEN_INVARIANTS::instance ()->reader_acquired (rwname) == 0)
+ ACE_ERROR_RETURN ((LM_ERROR, "reader acquire violated invariant.\n"), 0);
+
+ ACE_DEBUG ((LM_DEBUG, "(%t) rlock acquired.\n"));
+ }
+
+ ACE_TOKEN_INVARIANTS::instance ()->rwlock_releasing (rwname);
+
+ if (ACE_TOKEN_INVARIANTS::instance ()->reader_acquired (rwname) == 0)
+ ACE_ERROR_RETURN ((LM_ERROR, "reader renew violated invariant.\n"), 0);
+
+ ACE_DEBUG ((LM_DEBUG, "(%t) rlock renewed.\n"));
+
+ for (; y > 0; y--)
+ {
+ ACE_TOKEN_INVARIANTS::instance ()->rwlock_releasing (rwname);
+ ACE_DEBUG ((LM_DEBUG, "(%t) r-released.\n"));
+ }
+
+ if (ACE_TOKEN_INVARIANTS::instance ()->writer_acquired (rwname) == 0)
+ ACE_ERROR_RETURN ((LM_ERROR, "writer acquire violated invariant.\n"), 0);
+
+ ACE_DEBUG ((LM_DEBUG, "\t\t(%t) wlock acquired.\n"));
+
+ ACE_TOKEN_INVARIANTS::instance ()->rwlock_releasing (rwname);
+
+ if (ACE_TOKEN_INVARIANTS::instance ()->writer_acquired (rwname) == 0)
+ ACE_ERROR_RETURN ((LM_ERROR, "writer renew violated invariant.\n"), 0);
+
+ ACE_DEBUG ((LM_DEBUG, "(%t) rlock renewed.\n"));
+
+ ACE_TOKEN_INVARIANTS::instance ()->rwlock_releasing (rwname);
+ }
+
+ ACE_DEBUG ((LM_DEBUG, "(%t) thread exiting.\n"));
+ return 0;
+}
+
+static void *
+run_mutex (void *)
+{
+ for (int x = 0; x < 50; x++)
+ {
+ if (ACE_TOKEN_INVARIANTS::instance ()->mutex_acquired (mutexname) == 0)
+ ACE_ERROR_RETURN ((LM_ERROR, "mutex acquire violated invariant.\n"), 0);
+
+ ACE_DEBUG ((LM_DEBUG, "(%t) mutex acquired.\n"));
+
+ ACE_TOKEN_INVARIANTS::instance ()->mutex_releasing (mutexname);
+
+ if (ACE_TOKEN_INVARIANTS::instance ()->mutex_acquired (mutexname) == 0)
+ ACE_ERROR_RETURN ((LM_ERROR, "mutex renew violated invariant.\n"), 0);
+
+ ACE_DEBUG ((LM_DEBUG, "(%t) mutex renewed.\n"));
+
+ ACE_TOKEN_INVARIANTS::instance ()->mutex_releasing (mutexname);
+ ACE_DEBUG ((LM_DEBUG, "(%t) mutex released.\n"));
+ }
+
+ ACE_DEBUG ((LM_DEBUG, "(%t) thread exiting.\n"));
+ return 0;
+}
+
+static int
+run_final_test (void)
+{
+ ACE_DEBUG ((LM_DEBUG, "starting mutex tests 1 & 2\n"));
+
+ // Mutex tests.
+ if (ACE_TOKEN_INVARIANTS::instance ()->mutex_acquired ("testing mutex") == 0)
+ ACE_ERROR_RETURN ((LM_ERROR, "mutex test 1 failed.\n"), 0);
+ if (ACE_TOKEN_INVARIANTS::instance ()->mutex_acquired ("testing mutex2") == 0)
+ ACE_ERROR_RETURN ((LM_ERROR, "mutex test 2 failed.\n"), 0);
+ if (ACE_TOKEN_INVARIANTS::instance ()->mutex_acquired ("testing mutex") == 0)
+ ACE_DEBUG ((LM_DEBUG, "mutex test 1 succeeded.\n"));
+ else
+ ACE_ERROR_RETURN ((LM_ERROR, "mutex test 1 failed..\n"), 0);
+
+ if (ACE_TOKEN_INVARIANTS::instance ()->mutex_acquired ("testing mutex2") == 0)
+ ACE_DEBUG ((LM_DEBUG, "mutex test 2 succeeded.\n"));
+ else
+ ACE_ERROR_RETURN ((LM_ERROR, "mutex test 2 failed..\n"), 0);
+
+ // RW tests.
+ ACE_DEBUG ((LM_DEBUG, "starting rwlock tests 1 & 2\n"));
+
+ // Multiple readers.
+ if (ACE_TOKEN_INVARIANTS::instance ()->reader_acquired ("testing rwlock") == 0)
+ ACE_ERROR_RETURN ((LM_ERROR, "rwlock test 1 failed.\n"), 0);
+ if (ACE_TOKEN_INVARIANTS::instance ()->reader_acquired ("testing rwlock 2") == 0)
+ ACE_ERROR_RETURN ((LM_ERROR, "rwlock test 2 failed.\n"), 0);
+ if (ACE_TOKEN_INVARIANTS::instance ()->reader_acquired ("testing rwlock") == 0)
+ ACE_ERROR_RETURN ((LM_ERROR, "rwlock test 1 failed..\n"), 0);
+ if (ACE_TOKEN_INVARIANTS::instance ()->reader_acquired ("testing rwlock 2") == 0)
+ ACE_ERROR_RETURN ((LM_ERROR, "rwlock test 2 failed..\n"), 0);
+
+ // Writer.
+ if (ACE_TOKEN_INVARIANTS::instance ()->writer_acquired ("testing rwlock") == 0)
+ ACE_DEBUG ((LM_ERROR, "rwlock test 1 succeded.\n"));
+ else
+ ACE_ERROR_RETURN ((LM_ERROR, "rwlock test 1 failed...\n"), 0);
+
+ // Releasing reader.
+ ACE_TOKEN_INVARIANTS::instance ()->rwlock_releasing ("testing rwlock 2");
+ ACE_TOKEN_INVARIANTS::instance ()->rwlock_releasing ("testing rwlock 2");
+
+ // Writer.
+ if (ACE_TOKEN_INVARIANTS::instance ()->writer_acquired ("testing rwlock 2") == 0)
+ ACE_ERROR_RETURN ((LM_ERROR, "rwlock test 2 failed....\n"), 0);
+
+ // Reader.
+ if (ACE_TOKEN_INVARIANTS::instance ()->reader_acquired ("testing rwlock 2") == 0)
+ ACE_DEBUG ((LM_DEBUG, "rwlock test 2 succeeded.\n"));
+ else
+ ACE_ERROR_RETURN ((LM_ERROR, "rwlock test 2 failed.....\n"), 0);
+
+ return 0;
+}
+
+int
+main (int /* argc */, char* /* argv */ [])
+{
+ ACE_Thread_Manager mgr;
+
+ // Run reader/writer test
+ if (mgr.spawn_n (2, ACE_THR_FUNC (run_reader_writer),
+ (void *) 0,
+ THR_NEW_LWP | THR_DETACHED) == -1)
+ ACE_ERROR_RETURN ((LM_DEBUG, "%p\n", "spawn failed"), -1);
+
+ mgr.wait ();
+
+ ACE_OS::sleep (2);
+
+ // Run mutex test.
+ if (mgr.spawn_n (2, ACE_THR_FUNC (run_mutex),
+ (void *) 0,
+ THR_NEW_LWP | THR_DETACHED) == -1)
+ ACE_ERROR_RETURN ((LM_DEBUG, "%p\n", "spawn failed"), -1);
+
+ mgr.wait ();
+
+ ACE_OS::sleep (2);
+
+ run_final_test ();
+
+ return 0;
+}
+
+#else
+int
+main (int, char *[])
+{
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "threads not supported on this platform\n"), -1);
+}
+#endif /* ACE_HAS_THREADS */
diff --git a/ACE/netsvcs/clients/Tokens/manual/Makefile.am b/ACE/netsvcs/clients/Tokens/manual/Makefile.am
new file mode 100644
index 00000000000..b2945a96bd3
--- /dev/null
+++ b/ACE/netsvcs/clients/Tokens/manual/Makefile.am
@@ -0,0 +1,24 @@
+##----------------------------------------------------------------------------
+## $Id$
+##
+## Makefile for repeating token client application
+##----------------------------------------------------------------------------
+
+##
+## Process this file with automake to create Makefile.in
+##
+
+AM_CPPFLAGS = -I$(top_builddir) -I$(top_srcdir)
+
+noinst_PROGRAMS = \
+ manual
+
+manual_SOURCES = manual.cpp
+manual_LDADD = \
+ $(top_builddir)/netsvcs/lib/libnetsvcs.la \
+ $(top_builddir)/ace/libACE.la
+
+## Clean up template repositories, etc.
+clean-local:
+ -rm -f *.bak *.rpo *.sym lib*.*_pure_* Makefile.old core
+ -rm -rf ptrepository Templates.DB gcctemp.c gcctemp so_locations
diff --git a/ACE/netsvcs/clients/Tokens/manual/README b/ACE/netsvcs/clients/Tokens/manual/README
new file mode 100644
index 00000000000..09b9b9a365a
--- /dev/null
+++ b/ACE/netsvcs/clients/Tokens/manual/README
@@ -0,0 +1,67 @@
+
+./manual gives users a text-based interactive interface to local or
+remote tokens. This is extremely useful for manually testing the
+token server and setting up deadlock scenarios.
+
+Run it as follows
+
+% ./manual -u
+./manual:
+[-h <remote host>]
+[-p <remote port>]
+[-i ignore deadlock]
+[-d debug]
+
+./manual gives you the following prompt.
+<tid> <token> <type> <operation>
+
+<tid> This is the client id of the current operation. This is set
+ manually by ./manual for every operation. Be careful when
+ using multiple <tid>'s during a remote session (see BUGS
+ below).
+
+<token> This is the name of the token for the operation.
+
+<type> This is the type of the token. This can be:
+ M - Corresponds to a Mutex lock.
+ R - Corresponds to Readers/Writer lock.
+ W - Corresponds to Readers/Writer lock.
+ Obviously, a single <token> can be M or it can R and/or W. If
+ you perform and operation like this "tid1 tokenA M A" then
+ don't do this "tid1 tokenA R A". This doesn't make sense.
+
+<operation> This is the operation to perform on the
+ <tid>-<token>-<type> proxy. These include:
+ A - acquire.
+ N - renew.
+ R - release.
+ T - tryacquire.
+
+BUGS!!!!
+
+When performing remote tests, be careful when using a single running
+./manual to impersonate two <tid>'s. The Token Server client
+connection policy is currently, one per thread. The Token Server
+assumes that the same <tid> is always on the other end of a
+connection. If you do something like the following, you will break
+it:
+
+lambada:Tokens/manual> ./manual -h tango -p 20202
+<tid> <token> <type> <operation>
+tid1 tokenA M A
+ACE_TSS_Connection new connection
+(1) acquired tokenA remotely.
+Succeeded.
+<tid> <token> <type> <operation>
+tid2 tokenA M A
+(1) acquired tokenA remotely. <------ This is remote BADness!!!
+Succeeded.
+Violated invariant. <------ Locally detected badness.
+<tid> <token> <type> <operation>
+
+
+Notice that the local side discovered that this was incorrect.
+However, the Token Server thinks it was a recursive acquisition for
+tid1. Keep in mind that this is not a problem with the Token library.
+It is just a problem with how this primitive ./manual application maps
+STDIN to the ACE Token API.
diff --git a/ACE/netsvcs/clients/Tokens/manual/manual.cpp b/ACE/netsvcs/clients/Tokens/manual/manual.cpp
new file mode 100644
index 00000000000..d75c2b543b1
--- /dev/null
+++ b/ACE/netsvcs/clients/Tokens/manual/manual.cpp
@@ -0,0 +1,365 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// examples
+//
+// = FILENAME
+// manual.cpp
+//
+// = DESCRIPTION
+// Allows manual operations on local and remote tokens.
+//
+// = AUTHOR
+// Tim Harrison
+//
+// ============================================================================
+
+#include "ace/Get_Opt.h"
+#include "ace/Local_Tokens.h"
+#include "ace/Remote_Tokens.h"
+#include "ace/Singleton.h"
+#include "ace/Thread_Manager.h"
+#include "ace/Token_Invariants.h"
+#include "ace/Token_Collection.h"
+#include "ace/Map_Manager.h"
+#include "ace/Service_Config.h"
+
+#if defined (ACE_HAS_THREADS) && defined (ACE_HAS_THREADS_LIBRARY)
+
+ACE_RCSID(manual, manual, "$Id$")
+
+typedef ACE_Token_Invariant_Manager ACE_TOKEN_INVARIANTS;
+
+class STDIN_Token : public ACE_Event_Handler
+ // = TITLE
+ // STDIN Token
+ //
+ // = DESCRIPTION
+ // Translates STDIN commands to ACE Token commands.
+{
+public:
+ STDIN_Token (void);
+ // Construction.
+
+ int parse_args (int argc, char *argv[]);
+ // Parse command-line arguments.
+
+ int open (int argc, char *argv[]);
+ // Register with whatever event dispatcher is needed and run.
+
+ // = Event_Handler methods.
+ int handle_input (ACE_HANDLE);
+ int handle_exception (ACE_HANDLE);
+
+ typedef ACE_CString TID;
+
+private:
+
+ void display_menu (void);
+ // Display options.
+
+ ACE_Token_Proxy *get_proxy (const char *tid, const char *token, char type);
+ // Get or make a proxy to <token> with a <tid> client id.
+
+ ACE_Token_Proxy *create_proxy (const char *token, char type);
+ // Create a proxy to <token> with a <tid> client id.
+
+ // = Mapping from tid to Token_Collection.
+ typedef ACE_Map_Manager<TID, ACE_Token_Collection *, ACE_Null_Mutex>
+ COLLECTIONS;
+ // COLLECTION maintains a mapping from tid to a collection.
+
+ typedef ACE_Map_Iterator<TID, ACE_Token_Collection *, ACE_Null_Mutex>
+ COLLECTIONS_ITERATOR;
+ // Allows iterations through collections_.
+
+ typedef ACE_Map_Entry<TID, ACE_Token_Collection *>
+ COLLECTIONS_ENTRY;
+ // Allows iterations through collections_.
+
+ COLLECTIONS collections_;
+ // A collection for each <tid>.
+
+ const char *server_host_;
+ int server_port_;
+ int ignore_deadlock_;
+ int debug_;
+ int remote_;
+};
+
+STDIN_Token::STDIN_Token (void)
+ : server_host_ (ACE_DEFAULT_SERVER_HOST),
+ server_port_ (ACE_DEFAULT_SERVER_PORT),
+ ignore_deadlock_ (0),
+ debug_ (0),
+ remote_ (0)
+{
+}
+
+int
+STDIN_Token::parse_args (int argc, char *argv[])
+{
+ ACE_LOG_MSG->open (argv[0], ACE_Log_Msg::STDERR);
+
+ ACE_Get_Opt get_opt (argc, argv, "h:p:diu", 1);
+
+ for (int c; (c = get_opt ()) != -1; )
+ {
+ switch (c)
+ {
+ case 'h': // specify the host machine on which the server is running
+ server_host_ = get_opt.opt_arg ();
+ remote_ = 1;
+ break;
+ case 'p': // specify the port on which the server is running
+ server_port_ = ACE_OS::atoi (get_opt.opt_arg ());
+ remote_ = 1;
+ break;
+ case 'd':
+ debug_ = 1;
+ break;
+ case 'i':
+ ignore_deadlock_ = 1;
+ break;
+ case 'u':
+ // usage: fallthrough
+ default:
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "%n:\n"
+ "[-h <remote host>]\n"
+ "[-p <remote port>]\n"
+ "[-i ignore deadlock]\n"
+ "[-d debug]\n", 1), -1);
+ }
+ }
+
+ if (remote_)
+ ACE_Remote_Mutex::set_server_address (ACE_INET_Addr (server_port_,
+ server_host_));
+
+ return 0;
+}
+
+int
+STDIN_Token::open (int argc, char *argv[])
+{
+ if (this->parse_args (argc, argv) == -1)
+ return -1;
+
+ // Register for signals.
+ if (ACE_Reactor::instance ()->register_handler
+ (SIGINT, this) == -1)
+ ACE_DEBUG ((LM_DEBUG, "Can't register signal handler\n"));
+
+#if defined (ACE_WIN32)
+
+#else
+ // Register for STDIN events with Reactor.
+ if (ACE_Reactor::instance ()->register_handler
+ (ACE_STDIN, this, ACE_Event_Handler::READ_MASK) == -1)
+ ACE_ERROR_RETURN ((LM_DEBUG, "Can't register signal handler\n"), 0);
+
+
+#endif /* ACE_WIN32 */
+
+
+ this->display_menu ();
+
+#if defined (ACE_WIN32)
+
+#else
+ ACE_Reactor::run_event_loop ();
+#endif /* ACE_WIN32 */
+
+ ACE_OS::printf ("Exiting...\n");
+ return 0;
+}
+
+int
+STDIN_Token::handle_input (ACE_HANDLE fd)
+{
+ ACE_UNUSED_ARG (fd);
+
+ char tid[BUFSIZ];
+ char token[BUFSIZ];
+ char type[16];
+ char operation[16];
+
+ if (::scanf ("%s %s %s %s", tid, token, type, operation) <= 0)
+ {
+ ACE_OS::printf ("Try again.\n");
+ return 0;
+ }
+
+ ACE_Token_Proxy *proxy =
+ this->get_proxy (tid, token, type[0]);
+
+ if (proxy == 0)
+ return -1;
+
+ switch (operation[0])
+ {
+ case 'a':
+ case 'A':
+ if (proxy->acquire () == 0)
+ {
+ ACE_OS::printf ("Succeeded.\n");
+ if (ACE_TOKEN_INVARIANTS::instance ()->acquired (proxy) == 0)
+ ACE_OS::printf ("Violated invariant.\n");
+ }
+ else
+ ACE_ERROR ((LM_ERROR, "%p.\n", "Acquire failed"));
+ break;
+
+ case 'n':
+ case 'N':
+ ACE_TOKEN_INVARIANTS::instance ()->releasing (proxy);
+ if (proxy->renew () == 0)
+ {
+ ACE_OS::printf ("Succeeded.\n");
+ if (ACE_TOKEN_INVARIANTS::instance ()->acquired (proxy) == 0)
+ ACE_OS::printf ("Violated invariant.\n");
+ }
+ else
+ ACE_ERROR ((LM_ERROR, "%p.\n", "Renew failed"));
+ break;
+
+ case 'r':
+ case 'R':
+ ACE_TOKEN_INVARIANTS::instance ()->releasing (proxy);
+ if (proxy->release () == 0)
+ ACE_OS::printf ("Succeeded.\n");
+ else
+ ACE_ERROR ((LM_ERROR, "%p.\n", "Release failed"));
+ break;
+
+ case 't':
+ case 'T':
+ if (proxy->tryacquire () == 0)
+ {
+ ACE_OS::printf ("Succeeded.\n");
+ if (ACE_TOKEN_INVARIANTS::instance ()->acquired (proxy) == 0)
+ ACE_OS::printf ("Violated invariant.\n");
+ }
+ else
+ ACE_ERROR ((LM_ERROR, "%p.\n", "Tryacquire failed"));
+ break;
+ }
+
+ this->display_menu ();
+ return 0;
+}
+
+void
+STDIN_Token::display_menu (void)
+{
+ ACE_OS::printf ("<tid> <token> <type> <operation>\n");
+}
+
+int
+STDIN_Token::handle_exception (ACE_HANDLE fd)
+{
+ ACE_UNUSED_ARG (fd);
+
+ ACE_Reactor::run_event_loop ();
+ return -1;
+}
+
+ACE_Token_Proxy *
+STDIN_Token::get_proxy (const char *_tid, const char *token, char type)
+{
+ ACE_Token_Collection *proxy_collection;
+
+ TID tid (_tid);
+
+ if (collections_.find (tid, proxy_collection) == -1)
+ // We did not find a proxy_collection.
+ {
+ // Make one.
+ proxy_collection = new ACE_Token_Collection (debug_, "no name collection");
+
+ // Put it in the collections.
+ if (collections_.bind (tid, proxy_collection) == -1)
+ {
+ delete proxy_collection;
+ return 0;
+ }
+ }
+
+ // Either way, we have a proxy_collection now.
+
+ // See if the proxy already exists in the collection.
+ ACE_Token_Proxy *proxy = proxy_collection->is_member (token);
+
+ // If not, create one.
+ if (proxy == 0)
+ {
+ proxy = this->create_proxy (token, type);
+
+ // Put the new_proxy in this tid's collection.
+ if (proxy_collection->insert (*proxy) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "insert failed\n"), 0);
+
+ // Delete our copy (one was created in the collection).
+ delete proxy;
+ proxy = proxy_collection->is_member (token);
+
+ if (proxy == 0)
+ ACE_ERROR_RETURN ((LM_ERROR, "is_member failed\n"), 0);
+
+ // Set the client_id (it was set to 1 since we're
+ // single-threaded.
+ proxy->client_id (_tid);
+ }
+
+ return proxy;
+}
+
+ACE_Token_Proxy *
+STDIN_Token::create_proxy (const char *token, char type)
+{
+ switch (type)
+ {
+ case 'm':
+ case 'M':
+ if (remote_)
+ return new ACE_Remote_Mutex (token, ignore_deadlock_, debug_);
+ else
+ return new ACE_Local_Mutex (token, ignore_deadlock_, debug_);
+
+ case 'r':
+ case 'R':
+ if (remote_)
+ return new ACE_Remote_RLock (token, ignore_deadlock_, debug_);
+ else
+ return new ACE_Local_RLock (token, ignore_deadlock_, debug_);
+
+ case 'w':
+ case 'W':
+ if (remote_)
+ return new ACE_Remote_WLock (token, ignore_deadlock_, debug_);
+ else
+ return new ACE_Local_WLock (token, ignore_deadlock_, debug_);
+ }
+
+ // should never get here, but this avoids a compiler warning . . .
+ return 0;
+}
+
+int
+main (int argc, char* argv[])
+{
+ STDIN_Token st;
+ return st.open (argc, argv);
+}
+
+#else
+int
+main (int, char *[])
+{
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "threads or ACE_HAS_TOKENS_LIBRARY not supported on this platform\n"), -1);
+}
+#endif /* ACE_HAS_THREADS && ACE_HAS_TOKENS_LIBRARY */
diff --git a/ACE/netsvcs/clients/Tokens/mutex/Makefile.am b/ACE/netsvcs/clients/Tokens/mutex/Makefile.am
new file mode 100644
index 00000000000..63d02af7d97
--- /dev/null
+++ b/ACE/netsvcs/clients/Tokens/mutex/Makefile.am
@@ -0,0 +1,21 @@
+##----------------------------------------------------------------------------
+## $Id$
+##
+## Makefile for repeating token client application
+##----------------------------------------------------------------------------
+
+##
+## Process this file with automake to create Makefile.in
+##
+
+AM_CPPFLAGS = -I$(top_builddir) -I$(top_srcdir)
+
+noinst_PROGRAMS = \
+ test_mutex
+
+test_mutex_SOURCES = test_mutex.cpp
+test_mutex_LDADD = \
+ $(top_builddir)/netsvcs/lib/libnetsvcs.la \
+ $(top_builddir)/ace/libACE.la
+
+
diff --git a/ACE/netsvcs/clients/Tokens/mutex/README b/ACE/netsvcs/clients/Tokens/mutex/README
new file mode 100644
index 00000000000..cbd1e9c7d6c
--- /dev/null
+++ b/ACE/netsvcs/clients/Tokens/mutex/README
@@ -0,0 +1,23 @@
+
+test_mutex
+
+test_mutex tests ACE_Local_Mutex and ACE_Remote_Mutex with both local
+and global proxies. "Local proxies" mean that each thread uses its
+own proxy (but same logical token.) "Global proxy" means that all
+threads access the same proxy (and, of course, the same logical
+token.)
+
+test_mutex can take the number of threads to run from the
+command-line. Thus, to run the test with one thread and local
+mutexes, type:
+
+% ./test_mutex
+
+To run the test with 10 threads and local mutexes, type:
+
+% ./test_mutex -t 10
+
+To run the test with 10 threads and remote mutexes, type:
+
+% ./test_mutex -t 10 -r
+
diff --git a/ACE/netsvcs/clients/Tokens/mutex/test_mutex.cpp b/ACE/netsvcs/clients/Tokens/mutex/test_mutex.cpp
new file mode 100644
index 00000000000..73a33cb6c6e
--- /dev/null
+++ b/ACE/netsvcs/clients/Tokens/mutex/test_mutex.cpp
@@ -0,0 +1,142 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// examples
+//
+// = FILENAME
+// test_mutex.cpp
+//
+// = DESCRIPTION
+//
+// = AUTHOR
+// Tim Harrison
+//
+// ============================================================================
+
+#include "ace/Get_Opt.h"
+#include "ace/Local_Tokens.h"
+#include "ace/Remote_Tokens.h"
+#include "ace/Thread.h"
+#include "ace/Thread_Manager.h"
+
+#if defined (ACE_HAS_THREADS) && defined (ACE_HAS_THREADS_LIBRARY)
+
+ACE_RCSID(mutex, test_mutex, "$Id$")
+
+static ACE_Token_Proxy *mutex;
+static int remote_mutexes = 0;
+static const char *server_host = ACE_DEFAULT_SERVER_HOST;
+static int server_port = ACE_DEFAULT_SERVER_PORT;
+static int iterations = 100;
+static int spawn_count = 2;
+
+static void *
+run_test (void *)
+{
+ int count = iterations;
+ // test recursive acquisition of a global proxy
+ while (count--)
+ {
+ if (mutex->acquire () == -1)
+ {
+ ACE_ERROR ((LM_ERROR, "(%t) %p acquire failed\n","test_mutex"));
+ return (void *) -1;
+ }
+
+// mutex->acquire ();
+ if (mutex->renew () == -1)
+ {
+ ACE_ERROR ((LM_ERROR, "(%t) %p renew failed\n","test_mutex"));
+ return (void *) -1;
+ }
+
+ if (mutex->release () == -1)
+ {
+ ACE_ERROR ((LM_ERROR, "(%t) %p release failed\n","test_mutex"));
+ return (void *) -1;
+ }
+
+// mutex->release ();
+ }
+
+ return 0;
+}
+
+static int
+parse_args (int argc, char *argv[])
+{
+ ACE_LOG_MSG->open (argv[0]);
+
+ ACE_Get_Opt get_opt (argc, argv, "t:uh:p:n:", 1);
+
+ for (int c; (c = get_opt ()) != -1; )
+ {
+ switch (c)
+ {
+ case 't':
+ spawn_count = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'h': // specify the host machine on which the server is running
+ server_host = get_opt.opt_arg ();
+ remote_mutexes = 1;
+ break;
+ case 'p': // specify the port on which the server is running
+ server_port = ACE_OS::atoi (get_opt.opt_arg ());
+ remote_mutexes = 1;
+ break;
+ case 'n': // specify the port on which the server is running
+ iterations = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'u':
+ default:
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "%n:\n"
+ "[-h <remote host>]\n"
+ "[-p <remote port>]\n"
+ "[-n <iterations>]\n"
+ "[-t <threads>]\n"
+ "[-h <remote host>]\n"
+ "[-p <remote port>]\n", 1), -1);
+ /* NOTREACHED */
+ }
+ }
+
+ return 0;
+}
+
+int
+main (int argc, char *argv[])
+{
+ ACE_Thread_Manager thread_mgr;
+
+ if (parse_args (argc, argv) == -1)
+ return -1;
+
+ if (remote_mutexes)
+ {
+ ACE_Remote_Mutex::set_server_address (ACE_INET_Addr (server_port, server_host));
+ mutex = new ACE_Remote_Mutex ("Remote TOKEN", 0, 1);
+ }
+ else
+ {
+ mutex = new ACE_Local_Mutex ("Local TOKEN", 0, 1);
+ }
+
+ if (thread_mgr.spawn_n (spawn_count,
+ ACE_THR_FUNC (run_test),
+ 0,
+ THR_BOUND) == -1)
+ ACE_ERROR_RETURN ((LM_DEBUG, "%p\n", "spawn"), -1);
+
+ thread_mgr.wait ();
+
+ return 0;
+}
+#else
+int main (int, char *[])
+{
+ ACE_ERROR_RETURN ((LM_ERROR, "you must have threads to run this test program\n"), -1);
+}
+#endif /* ACE_HAS_THREADS */
diff --git a/ACE/netsvcs/clients/Tokens/rw_lock/Makefile.am b/ACE/netsvcs/clients/Tokens/rw_lock/Makefile.am
new file mode 100644
index 00000000000..265a3a09558
--- /dev/null
+++ b/ACE/netsvcs/clients/Tokens/rw_lock/Makefile.am
@@ -0,0 +1,20 @@
+##----------------------------------------------------------------------------
+## $Id$
+##
+## Makefile for repeating token client application
+##----------------------------------------------------------------------------
+
+##
+## Process this file with automake to create Makefile.in
+##
+
+AM_CPPFLAGS = -I$(top_builddir) -I$(top_srcdir)
+
+noinst_PROGRAMS = \
+ rw_locks
+
+rw_locks_SOURCES = rw_locks.cpp
+rw_locks_LDADD = \
+ $(top_builddir)/netsvcs/lib/libnetsvcs.la \
+ $(top_builddir)/ace/libACE.la
+
diff --git a/ACE/netsvcs/clients/Tokens/rw_lock/README b/ACE/netsvcs/clients/Tokens/rw_lock/README
new file mode 100644
index 00000000000..dabc0a3741d
--- /dev/null
+++ b/ACE/netsvcs/clients/Tokens/rw_lock/README
@@ -0,0 +1,40 @@
+
+test_rw_locks shows how to use ACE_Local_RLock, ACE_Local_WLock,
+ACE_Remote_RLock, and ACE_Remote_WLock.
+
+Here are the options to test_rw_locks:
+% ./test_rw_lock -u
+ -i ignore deadlock
+ -n <iterations>
+ -r <reads>
+ -d debug
+ -s sleep during writes
+ -t <threads>
+
+test_rw_locks spawns <threads> number of threads which perform the
+following algorithm:
+
+for <iterations>
+ {
+ for <reads>
+ acquire read lock
+ for <reads>
+ release read lock
+
+ acquire write lock
+ if (sleep during writes)
+ sleep for 1 second
+ release write lock
+ }
+
+
+The output should show that multiple readers can acquire the lock for
+reading simultaneously (note that this also tests recursive
+acquisition.) When a writer lock is acquired, the output should show
+that no thread holds a reader lock.
+
+To run a test, simply type:
+% ./test_rw_lock
+
+This should show output as described above.
+
diff --git a/ACE/netsvcs/clients/Tokens/rw_lock/rw_locks.cpp b/ACE/netsvcs/clients/Tokens/rw_lock/rw_locks.cpp
new file mode 100644
index 00000000000..5d0d95af876
--- /dev/null
+++ b/ACE/netsvcs/clients/Tokens/rw_lock/rw_locks.cpp
@@ -0,0 +1,252 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// examples
+//
+// = FILENAME
+// rw_locks.cpp
+//
+// = DESCRIPTION
+// test_rw_locks shows how to use ACE_Local_RLock, ACE_Local_WLock,
+// ACE_Remote_RLock, and ACE_Remote_WLock.
+//
+// = AUTHOR
+// Tim Harrison
+//
+// ============================================================================
+
+#include "ace/Get_Opt.h"
+#include "ace/Local_Tokens.h"
+#include "ace/Remote_Tokens.h"
+#include "ace/Thread_Manager.h"
+#include "ace/Token_Invariants.h"
+
+#if defined (ACE_HAS_THREADS) && defined (ACE_HAS_THREADS_LIBRARY)
+
+ACE_RCSID(rw_lock, rw_locks, "$Id$")
+
+typedef ACE_Token_Invariant_Manager ACE_TOKEN_INVARIANTS;
+
+static ACE_Token_Proxy *global_rlock;
+static ACE_Token_Proxy *global_wlock;
+
+static const char *server_host = ACE_DEFAULT_SERVER_HOST;
+static int server_port = ACE_DEFAULT_SERVER_PORT;
+static int ignore_deadlock = 0;
+static int threads = 2;
+static int iterations = 50;
+static int debug = 0;
+static int remote = 0;
+static int reads = 4;
+static int write_sleep = 0;
+static int renew = 0;
+
+static void *
+run_thread (void *)
+{
+ for (int x = 0; x < iterations; x++)
+ {
+ int y = 0;
+ for (; y < reads; y++)
+ {
+ if (global_rlock->acquire () == -1)
+ {
+ if (ACE_Log_Msg::instance ()->errnum () == EDEADLK)
+ {
+ ACE_DEBUG ((LM_DEBUG, "rlock deadlock detected\n"));
+ goto READ_DEADLOCK;
+ }
+ else return 0;
+ }
+
+ if (ACE_TOKEN_INVARIANTS::instance ()->acquired (global_rlock) == 0)
+ ACE_ERROR_RETURN ((LM_ERROR, "reader acquire violated invariant.\n"), 0);
+
+ ACE_DEBUG ((LM_DEBUG, "(%t) rlock acquired.\n"));
+ }
+
+ if (renew)
+ {
+ ACE_TOKEN_INVARIANTS::instance ()->releasing (global_rlock);
+
+ if (global_rlock->renew () == -1)
+ {
+ if (ACE_Log_Msg::instance ()->errnum () == EDEADLK)
+ {
+ ACE_DEBUG ((LM_DEBUG, "rlock deadlock detected during renew\n"));
+ goto READ_DEADLOCK;
+ }
+ else return 0;
+ }
+
+ ACE_DEBUG ((LM_DEBUG, "(%t) rlock renewed.\n"));
+
+ if (ACE_TOKEN_INVARIANTS::instance ()->acquired (global_rlock) == 0)
+ ACE_ERROR_RETURN ((LM_ERROR, "reader renew violated invariant.\n"), 0);
+ }
+
+ READ_DEADLOCK:
+
+ for (; y > 0; y--)
+ {
+ ACE_TOKEN_INVARIANTS::instance ()->releasing (global_rlock);
+ if (global_rlock->release () == 0)
+ ACE_DEBUG ((LM_DEBUG, "(%t) r-released.\n"));
+ }
+
+ if (global_wlock->acquire () == -1)
+ ACE_DEBUG ((LM_DEBUG, "wlock deadlock detected\n"));
+ else
+ {
+ if (write_sleep)
+ ACE_OS::sleep (1);
+ ACE_DEBUG ((LM_DEBUG, "\t\t(%t) wlock acquired.\n"));
+
+ if (ACE_TOKEN_INVARIANTS::instance ()->acquired (global_wlock) == 0)
+ ACE_ERROR_RETURN ((LM_ERROR, "writer acquire violated invariant.\n"), 0);
+
+ if (renew)
+ {
+ ACE_TOKEN_INVARIANTS::instance ()->releasing (global_wlock);
+
+ if (global_wlock->renew () == -1)
+ {
+ if (ACE_Log_Msg::instance ()->errnum () == EDEADLK)
+ {
+ ACE_DEBUG ((LM_DEBUG, "wlock deadlock detected during renew\n"));
+ }
+ else return 0;
+ }
+
+ ACE_DEBUG ((LM_DEBUG, "(%t) rlock renewed.\n"));
+
+ if (ACE_TOKEN_INVARIANTS::instance ()->acquired (global_wlock) == 0)
+ ACE_ERROR_RETURN ((LM_ERROR, "writer renew violated invariant.\n"), 0);
+ }
+
+ ACE_TOKEN_INVARIANTS::instance ()->releasing (global_wlock);
+
+ if (global_wlock->release () == 0)
+ ACE_DEBUG ((LM_DEBUG, "\t\t(%t) w-released.\n"));
+ }
+ }
+
+ ACE_DEBUG ((LM_DEBUG, "(%t) thread exiting.\n"));
+ return 0;
+}
+
+static int
+parse_args (int argc, char *argv[])
+{
+ ACE_LOG_MSG->open (argv[0], ACE_Log_Msg::STDERR); // | ACE_Log_Msg::VERBOSE);
+
+ ACE_Get_Opt get_opt (argc, argv, "t:iun:dr:sp:h:R", 1);
+
+ for (int c; (c = get_opt ()) != -1; )
+ {
+ switch (c)
+ {
+ case 'h': // specify the host machine on which the server is running
+ server_host = get_opt.opt_arg ();
+ remote = 1;
+ break;
+ case 'p': // specify the port on which the server is running
+ server_port = ACE_OS::atoi (get_opt.opt_arg ());
+ remote = 1;
+ break;
+ case 't':
+ threads = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'R':
+ renew = 1;
+ break;
+ case 'r':
+ reads = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'd':
+ debug = 1;
+ break;
+ case 's':
+ write_sleep = 1;
+ break;
+ case 'n':
+ iterations = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'i':
+ ignore_deadlock = 1;
+ break;
+ case 'u':
+ // usage: fallthrough
+ default:
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "%n:\n"
+ "[-h <remote host>]\n"
+ "[-p <remote port>]\n"
+ "[-i ignore deadlock]\n"
+ "[-n <iterations>]\n"
+ "[-R perform renews]\n"
+ "[-r <reads>]\n"
+ "[-d debug]\n"
+ "[-s sleep during writes]\n"
+ "[-t <threads>\n", 1), -1);
+ }
+ }
+
+ return 0;
+}
+
+#if defined (ACE_HAS_PTHREADS)
+#define SUSPEND 0
+#else
+#define SUSPEND THR_SUSPENDED
+#endif
+
+int
+main (int argc, char* argv[])
+{
+ if (parse_args (argc, argv) == -1)
+ return -1;
+
+ if (remote)
+ {
+ ACE_Remote_Mutex::set_server_address (ACE_INET_Addr (server_port, server_host));
+ global_rlock = (ACE_Token_Proxy *) new
+ ACE_Remote_RLock ("THE_TOKEN", ignore_deadlock, debug);
+ global_wlock = (ACE_Token_Proxy *) new
+ ACE_Remote_WLock ("THE_TOKEN", ignore_deadlock, debug);
+ }
+ else
+ {
+ global_rlock = (ACE_Token_Proxy *) new
+ ACE_Local_RLock ("THE_TOKEN", ignore_deadlock, debug);
+ global_wlock = (ACE_Token_Proxy *) new
+ ACE_Local_WLock ("THE_TOKEN", ignore_deadlock, debug);
+ }
+
+ ACE_Thread_Manager mgr;
+
+ if (mgr.spawn_n (threads, ACE_THR_FUNC (run_thread),
+ (void *) 0,
+ THR_BOUND | SUSPEND) == -1)
+ ACE_ERROR_RETURN ((LM_DEBUG, "%p\n", "spawn failed"), -1);
+
+#if ! defined (ACE_HAS_PTHREADS)
+ if (mgr.resume_all () == -1)
+ ACE_ERROR_RETURN ((LM_DEBUG, "%p\n", "resume failed"), -1);
+#endif
+
+ mgr.wait ();
+
+ return 0;
+}
+
+#else
+int
+main (int, char *[])
+{
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "threads not supported on this platform\n"), -1);
+}
+#endif /* ACE_HAS_THREADS */