summaryrefslogtreecommitdiff
path: root/ACE/netsvcs/clients/Tokens
diff options
context:
space:
mode:
Diffstat (limited to 'ACE/netsvcs/clients/Tokens')
-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.cpp209
-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.cpp341
-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.cpp366
-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.cpp255
21 files changed, 2135 insertions, 0 deletions
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..d2aa7bf8c1b
--- /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/$(ACE_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..84724d1a6ea
--- /dev/null
+++ b/ACE/netsvcs/clients/Tokens/collection/collection.cpp
@@ -0,0 +1,209 @@
+// $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
+ACE_TMAIN(int argc, ACE_TCHAR *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
+ACE_TMAIN(int, ACE_TCHAR *[])
+{
+ 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..33ca18b9dba
--- /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
+ACE_TMAIN(int argc, ACE_TCHAR *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
+ACE_TMAIN(int, ACE_TCHAR *[])
+{
+ 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..5e25ccd0fb3
--- /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/$(ACE_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..3a1a13195d4
--- /dev/null
+++ b/ACE/netsvcs/clients/Tokens/deadlock/deadlock_detection_test.cpp
@@ -0,0 +1,341 @@
+// $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
+ACE_TMAIN(int argc, ACE_TCHAR *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
+ACE_TMAIN(int, ACE_TCHAR *[])
+{
+ 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..83b621b5a42
--- /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/$(ACE_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..d9821bbc27d
--- /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
+ACE_TMAIN(int, ACE_TCHAR *[])
+{
+ 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
+ACE_TMAIN(int, ACE_TCHAR *[])
+{
+ 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..4a2cbf60788
--- /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/$(ACE_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..1e0154a12c7
--- /dev/null
+++ b/ACE/netsvcs/clients/Tokens/manual/manual.cpp
@@ -0,0 +1,366 @@
+// $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.
+
+ //FUZZ: disable check_for_lack_ACE_OS
+ int open (int argc, char *argv[]);
+ // Register with whatever event dispatcher is needed and run.
+ //FUZZ: enable check_for_lack_ACE_OS
+
+ // = 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
+ACE_TMAIN(int argc, ACE_TCHAR *argv[])
+{
+ STDIN_Token st;
+ return st.open (argc, argv);
+}
+
+#else
+int
+ACE_TMAIN(int, ACE_TCHAR *[])
+{
+ 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..56dd1efccf2
--- /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/$(ACE_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..26432f292d6
--- /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
+ACE_TMAIN(int argc, ACE_TCHAR *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..972d8a64faa
--- /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/$(ACE_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..23d6a5e7f20
--- /dev/null
+++ b/ACE/netsvcs/clients/Tokens/rw_lock/rw_locks.cpp
@@ -0,0 +1,255 @@
+// $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
+ACE_TMAIN(int argc, ACE_TCHAR *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
+ACE_TMAIN(int, ACE_TCHAR *[])
+{
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "threads not supported on this platform\n"), -1);
+}
+#endif /* ACE_HAS_THREADS */