summaryrefslogtreecommitdiff
path: root/docs/tutorials/007
diff options
context:
space:
mode:
authorschmidt <douglascraigschmidt@users.noreply.github.com>1998-08-30 23:47:15 +0000
committerschmidt <douglascraigschmidt@users.noreply.github.com>1998-08-30 23:47:15 +0000
commit2a2e62e0f2b414fd6e2e154e0d8c60c6bf146487 (patch)
treef0bfddf4d121c1bff2d25b73b35392d69393b5c8 /docs/tutorials/007
parent97b96ada24a87802fb354c374a57ae5654f2b309 (diff)
downloadATCD-2a2e62e0f2b414fd6e2e154e0d8c60c6bf146487.tar.gz
*** empty log message ***
Diffstat (limited to 'docs/tutorials/007')
-rw-r--r--docs/tutorials/007/Makefile99
-rw-r--r--docs/tutorials/007/client_acceptor.cpp67
-rw-r--r--docs/tutorials/007/client_acceptor.h137
-rw-r--r--docs/tutorials/007/client_handler.cpp209
-rw-r--r--docs/tutorials/007/client_handler.h156
-rwxr-xr-xdocs/tutorials/007/fix.Makefile60
-rw-r--r--docs/tutorials/007/page01.html33
-rw-r--r--docs/tutorials/007/page02.html197
-rw-r--r--docs/tutorials/007/page03.html263
-rw-r--r--docs/tutorials/007/page04.html133
-rw-r--r--docs/tutorials/007/page05.html282
-rw-r--r--docs/tutorials/007/page06.html332
-rw-r--r--docs/tutorials/007/page07.html197
-rw-r--r--docs/tutorials/007/page08.html509
-rw-r--r--docs/tutorials/007/page09.html64
-rw-r--r--docs/tutorials/007/server.cpp107
-rw-r--r--docs/tutorials/007/thread_pool.cpp262
-rw-r--r--docs/tutorials/007/thread_pool.h88
18 files changed, 3195 insertions, 0 deletions
diff --git a/docs/tutorials/007/Makefile b/docs/tutorials/007/Makefile
new file mode 100644
index 00000000000..eaf503868ca
--- /dev/null
+++ b/docs/tutorials/007/Makefile
@@ -0,0 +1,99 @@
+#----------------------------------------------------------------------------
+# $Id$
+#----------------------------------------------------------------------------
+
+#----------------------------------------------------------------------------
+# Local macros
+#----------------------------------------------------------------------------
+
+# You can generally find a Makefile in the ACE examples, tests or the library
+# itself that will satisfy our application needs. This one was taken from
+# one of the examples.
+
+ # Define the name of the binary we want to create. There has to be
+ # a CPP file $(BIN).cpp but it doesn't necessarily have to have your
+ # main() in it. Most of the time, though, it will.
+BIN = server
+
+ # Few applications will have a single source file. We use the FILES
+ # macro to build up a list of additional files to compile. Notice
+ # that we leave off the extension just as with BIN
+FILES =
+FILES += client_handler
+FILES += client_acceptor
+FILES += thread_pool
+
+ # The BUILD macro is used by the ACE makefiles. Basically, it tells
+ # the system what to build. I don't really know what VBIN is other
+ # than it is constructed from the value of BIN. Just go with it...
+BUILD = $(VBIN)
+
+ # Here we use some GNU make extensions to build the SRC macro. Basically,
+ # we're just adding .cpp to the value of BIN and for each entry of the
+ # FILES macro.
+SRC = $(addsuffix .cpp,$(BIN)) $(addsuffix .cpp,$(FILES))
+
+ # This is used by my Indent target below. It's not a part of standard
+ # ACE and you don't need it yourself.
+HDR = *.h
+
+#----------------------------------------------------------------------------
+# Include macros and targets
+#----------------------------------------------------------------------------
+
+ # This is where the real power lies! These included makefile components
+ # are similar to the C++ templates in ACE. That is, they do a tremendous
+ # amount of work for you and all you have to do is include them.
+ # As a matter of fact, in our project, I created a single file named
+ # "app.mk" that includes all of these. Our project makefiles then just
+ # need to include app.mk to get everything they need.
+
+include $(ACE_ROOT)/include/makeinclude/wrapper_macros.GNU
+include $(ACE_ROOT)/include/makeinclude/macros.GNU
+include $(ACE_ROOT)/include/makeinclude/rules.common.GNU
+include $(ACE_ROOT)/include/makeinclude/rules.nonested.GNU
+include $(ACE_ROOT)/include/makeinclude/rules.lib.GNU
+include $(ACE_ROOT)/include/makeinclude/rules.bin.GNU
+include $(ACE_ROOT)/include/makeinclude/rules.local.GNU
+
+#----------------------------------------------------------------------------
+# Local targets
+#----------------------------------------------------------------------------
+
+ # Sometimes I like to reformat my code to make it more readable. This is
+ # more useful for the comments than anything else. Unfortunately, the
+ # "indent" program doesn't quite grok C++ so I have to post-process it's
+ # output just a bit.
+Indent : #
+ for i in $(SRC) $(HDR) ; do \
+ indent -npsl -l80 -fca -fc1 -cli0 -cdb < $$i | \
+ sed -e 's/: :/::/g' \
+ -e 's/^.*\(public:\)/\1/' \
+ -e 's/^.*\(protected:\)/\1/' \
+ -e 's/^.*\(private:\)/\1/' \
+ -e 's/:\(public\)/ : \1/' \
+ -e 's/:\(protected\)/ : \1/' \
+ -e 's/:\(private\)/ : \1/' \
+ > $$i~ ;\
+ mv $$i~ $$i ;\
+ done
+
+ # One of the targets in the ACE makefiles is "depend". It will invoke
+ # your compiler in a way that will generate a list of dependencies for
+ # you. This is a great thing! Unfortunately, it puts all of that mess
+ # directly into the Makefile. I prefer my Makefile to stay clean and
+ # uncluttered. The perl script referenced here pulls the dependency
+ # stuff back out of the Makefile and into a file ".depend" which we then
+ # include just like the makefile components above.
+Depend : depend
+ perl fix.Makefile
+
+#----------------------------------------------------------------------------
+# Dependencies
+#----------------------------------------------------------------------------
+
+ # Don't put anything below here. Between the "depend" target and fix.Makefile
+ # it's guaranteed to be lost!
+
+ # This is inserted by the fix.Makefile script
+include .depend
diff --git a/docs/tutorials/007/client_acceptor.cpp b/docs/tutorials/007/client_acceptor.cpp
new file mode 100644
index 00000000000..6cc90612558
--- /dev/null
+++ b/docs/tutorials/007/client_acceptor.cpp
@@ -0,0 +1,67 @@
+
+// $Id$
+
+#include "client_acceptor.h"
+
+/*
+ Construct ourselves with the chosen concurrency strategy. Notice that we also
+ set our Thread_Pool reference to our private instance.
+ */
+Client_Acceptor::Client_Acceptor( int _concurrency )
+ : concurrency_(_concurrency)
+ ,the_thread_pool_(private_thread_pool_)
+{
+}
+
+/*
+ Construct ourselves with a reference to somebody else' Thread_Pool. Obvioulsy
+ our concurrency strategy is "thread_pool_" at this point.
+ */
+Client_Acceptor::Client_Acceptor( Thread_Pool & _thread_pool )
+ : concurrency_(thread_pool_)
+ ,the_thread_pool_(_thread_pool)
+{
+}
+
+/*
+ When we're destructed, we may need to cleanup after ourselves. If we're running
+ with a thread pool that we own, it is up to us to close it down.
+ */
+Client_Acceptor::~Client_Acceptor( void )
+{
+ if( this->concurrency() == thread_pool_ && thread_pool_is_private() )
+ {
+ thread_pool()->close();
+ }
+}
+
+/*
+ Similar to the destructor (and close() below) it is necessary for us to open the
+ thread pool in some circumstances.
+
+ Notice how we delegate most of the open() work to the open() method of our baseclass.
+ */
+int Client_Acceptor::open( const ACE_INET_Addr & _addr, ACE_Reactor * _reactor, int _pool_size )
+{
+ if( this->concurrency() == thread_pool_ && thread_pool_is_private() )
+ {
+ thread_pool()->open(_pool_size);
+ }
+
+ return inherited::open(_addr,_reactor);
+}
+
+/*
+ Here again we find that we have to manage the thread pool. Like open() we also delegate
+ the other work to our baseclass.
+ */
+int Client_Acceptor::close(void)
+{
+ if( this->concurrency() == thread_pool_ && thread_pool_is_private() )
+ {
+ thread_pool()->close();
+ }
+
+ return inherited::close();
+}
+
diff --git a/docs/tutorials/007/client_acceptor.h b/docs/tutorials/007/client_acceptor.h
new file mode 100644
index 00000000000..e1c0eded6fd
--- /dev/null
+++ b/docs/tutorials/007/client_acceptor.h
@@ -0,0 +1,137 @@
+
+// $Id$
+
+#ifndef CLIENT_ACCEPTOR_H
+#define CLIENT_ACCEPTOR_H
+
+/*
+ The ACE_Acceptor<> template lives in the ace/Acceptor.h header file. You'll
+ find a very consitent naming convention between the ACE objects and the
+ headers where they can be found. In general, the ACE object ACE_Foobar will
+ be found in ace/Foobar.h.
+ */
+
+#include "ace/Acceptor.h"
+
+/*
+ Since we want to work with sockets, we'll need a SOCK_Acceptor to allow the
+ clients to connect to us.
+ */
+#include "ace/SOCK_Acceptor.h"
+
+/*
+ The Client_Handler object we develop will be used to handle clients once
+ they're connected. The ACE_Acceptor<> template's first parameter requires
+ such an object. In some cases, you can get by with just a forward
+ declaration on the class, in others you have to have the whole thing.
+ */
+#include "client_handler.h"
+
+/*
+ Parameterize the ACE_Acceptor<> such that it will listen for socket
+ connection attempts and create Client_Handler objects when they happen. In
+ Tutorial 001, we wrote the basic acceptor logic on our own before we
+ realized that ACE_Acceptor<> was available. You'll get spoiled using the
+ ACE templates because they take away a lot of the tedious details!
+ */
+typedef ACE_Acceptor < Client_Handler, ACE_SOCK_ACCEPTOR > Client_Acceptor_Base;
+
+#include "thread_pool.h"
+
+/*
+ This time we've added quite a bit more to our acceptor. In addition to
+ providing a choice of concurrency strategies, we also maintain a Thread_Pool
+ object in case that strategy is chosen. The object still isn't very complex
+ but it's come a long way from the simple typedef we had in Tutorial 5.
+
+ Why keep the thread pool as a member? If we go back to the inetd concept
+ you'll recall that we need several acceptors to make that work. We may have
+ a situation in which our different client types requre different resources.
+ That is, we may need a large thread pool for some client types and a smaller
+ one for others. We could share a pool but then the client types may have
+ undesirable impact on one another.
+
+ Just in case you do want to share a single thread pool, there is a constructor
+ below that will let you do that.
+ */
+class Client_Acceptor : public Client_Acceptor_Base
+{
+public:
+ typedef Client_Acceptor_Base inherited;
+
+ /*
+ Now that we have more than two strategies, we need more than a boolean
+ to tell us what we're using. A set of enums is a good choice because
+ it allows us to use named values. Another option would be a set of
+ static const integers.
+ */
+ enum concurrency_t
+ {
+ single_threaded_,
+ thread_per_connection_,
+ thread_pool_
+ };
+
+ /*
+ The default constructor allows the programmer to choose the concurrency
+ strategy. Since we want to focus on thread-pool, that's what we'll use
+ if nothing is specified.
+ */
+ Client_Acceptor( int _concurrency = thread_pool_ );
+
+ /*
+ Another option is to construct the object with an existing thread pool.
+ The concurrency strategy is pretty obvious at that point.
+ */
+ Client_Acceptor( Thread_Pool & _thread_pool );
+
+ /*
+ Our destructor will take care of shutting down the thread-pool
+ if applicable.
+ */
+ ~Client_Acceptor( void );
+
+ /*
+ Open ourselves and register with the given reactor. The thread pool size
+ can be specified here if you want to use that concurrency strategy.
+ */
+ int open( const ACE_INET_Addr & _addr, ACE_Reactor * _reactor,
+ int _pool_size = Thread_Pool::default_pool_size_ );
+
+ /*
+ Close ourselves and our thread pool if applicable
+ */
+ int close(void);
+
+ /*
+ What is our concurrency strategy?
+ */
+ int concurrency(void)
+ { return this->concurrency_; }
+
+ /*
+ Give back a pointer to our thread pool. Our Client_Handler objects
+ will need this so that their handle_input() methods can put themselves
+ into the pool. Another alternative would be a globally accessible
+ thread pool. ACE_Singleton<> is a way to achieve that.
+ */
+ Thread_Pool * thread_pool(void)
+ { return & this->the_thread_pool_; }
+
+ /*
+ Since we can be constructed with a Thread_Pool reference, there are times
+ when we need to know if the thread pool we're using is ours or if we're
+ just borrowing it from somebody else.
+ */
+ int thread_pool_is_private(void)
+ { return &the_thread_pool_ == &private_thread_pool_; }
+
+protected:
+ int concurrency_;
+
+ Thread_Pool private_thread_pool_;
+
+ Thread_Pool & the_thread_pool_;
+};
+
+#endif // CLIENT_ACCEPTOR_H
diff --git a/docs/tutorials/007/client_handler.cpp b/docs/tutorials/007/client_handler.cpp
new file mode 100644
index 00000000000..d14c8ce3144
--- /dev/null
+++ b/docs/tutorials/007/client_handler.cpp
@@ -0,0 +1,209 @@
+
+// $Id$
+
+/*
+ Since this is the third time we've seen most of this, I'm going to strip out almost
+ all of the comments that you've already seen. That way, you can concentrate on the
+ new items.
+ */
+
+#include "client_acceptor.h"
+#include "client_handler.h"
+
+/*
+ We're going to be registering and unregistering a couple of times. To make sure that
+ we use the same flags every time, I've created these handy macros.
+ */
+#define REGISTER_MASK ACE_Event_Handler::READ_MASK
+#define REMOVE_MASK (ACE_Event_Handler::READ_MASK | ACE_Event_Handler::DONT_CALL)
+
+/*
+ Our constructor still doesn't really do anything. We simply initialize the acceptor
+ pointer to "null" and get our current thread id. The static self() method of ACE_Thread
+ will return you a thread id native to your platform.
+ */
+Client_Handler::Client_Handler (void)
+ : client_acceptor_(0)
+ ,creator_(ACE_Thread::self())
+{
+}
+
+Client_Handler::~Client_Handler (void)
+{
+}
+
+/*
+ Query our acceptor for the concurrency strategy. Notice that we don't bother
+ to check that our acceptor pointer is valid. That is proably a bad idea...
+ */
+int Client_Handler::concurrency(void)
+{
+ return this->client_acceptor()->concurrency();
+}
+
+/*
+ And here we ask the acceptor about the thread pool.
+ */
+Thread_Pool * Client_Handler::thread_pool(void)
+{
+ return this->client_acceptor()->thread_pool();
+}
+
+/*
+ The destroy() method hasn't changed since we wrote it back in Tutorial 5.
+ */
+void Client_Handler::destroy (void)
+{
+ this->peer ().close ();
+
+ this->reactor ()->remove_handler (this, REMOVE_MASK );
+
+ delete this;
+}
+
+/*
+ Back to our open() method. This is straight out of Tutorial 6. There's
+ nothing additional here for the thread-pool implementation.
+ */
+int Client_Handler::open (void *_acceptor)
+{
+ client_acceptor( (Client_Acceptor *) _acceptor );
+
+ if( concurrency() == Client_Acceptor::thread_per_connection_ )
+ {
+ return this->activate();
+ }
+
+ this->reactor (client_acceptor()->reactor ());
+
+ ACE_INET_Addr addr;
+
+ if (this->peer ().get_remote_addr (addr) == -1)
+ {
+ return -1;
+ }
+
+ if (this->reactor ()->register_handler (this, REGISTER_MASK) == -1)
+ {
+ ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) can't register with reactor\n"), -1);
+ }
+
+ ACE_DEBUG ((LM_DEBUG, "(%P|%t) connected with %s\n", addr.get_host_name ()));
+
+ return 0;
+}
+
+/*
+ In the open() method, we registered with the reactor and requested to be
+ notified when there is data to be read. When the reactor sees that activity
+ it will invoke this handle_input() method on us. As I mentioned, the _handle
+ parameter isn't useful to us but it narrows the list of methods the reactor
+ has to worry about and the list of possible virtual functions we would have
+ to override.
+
+ You've read that much before... Now we have to do some extra stuff in case
+ we're using the thread-pool implementation. If we're called by our creator
+ thread then we must be in the reactor. In that case, we arrange to be put
+ into the thread pool. If we're not in the creator thread then we must be
+ in the thread pool and we can do some work.
+ */
+int Client_Handler::handle_input (ACE_HANDLE _handle)
+{
+ ACE_UNUSED_ARG (_handle);
+
+ /*
+ Check our strategy. If we're using the thread pool and we're in the creation
+ thread then we know we were called by the reactor.
+ */
+ if( concurrency() == Client_Acceptor::thread_pool_ )
+ {
+ if( ACE_Thread::self() == creator_ )
+ {
+ /*
+ Remove ourselves from the reactor and ask to be put into the thread pool's
+ queue of work. (You should be able to use suspend_handler() but I've had
+ problems with that.)
+ */
+ this->reactor()->remove_handler( this, REMOVE_MASK );
+ return this->thread_pool()->enqueue(this);
+ }
+ }
+
+ /*
+ Any strategy other than thread-per-connection will eventually get here. If we're in the
+ single-threaded implementation or the thread-pool, we still have to pass this way.
+ */
+
+ char buf[128];
+ memset (buf, 0, sizeof (buf));
+
+ /*
+ Invoke the process() method to do the work but save it's return value instead
+ of returning it immediately.
+ */
+
+ int rval = this->process(buf,sizeof(buf));
+
+ /*
+ Now, we look again to see if we're in the thread-pool implementation. If so then we
+ need to re-register ourselves with the reactor so that we can get more work when it
+ is available. (If suspend_handler() worked then we would use resume_handler() here.)
+ */
+ if( concurrency() == Client_Acceptor::thread_pool_ )
+ {
+ if( rval != -1 )
+ {
+ this->reactor()->register_handler( this, REGISTER_MASK );
+ }
+ }
+
+ /*
+ Return the result of process()
+ */
+ return(rval);
+}
+
+int Client_Handler::handle_close (ACE_HANDLE _handle, ACE_Reactor_Mask _mask)
+{
+ ACE_UNUSED_ARG (_handle);
+ ACE_UNUSED_ARG (_mask);
+
+ this->destroy ();
+ return 0;
+}
+
+int Client_Handler::svc(void)
+{
+ char buf[128];
+ memset (buf, 0, sizeof (buf));
+
+ while( 1 )
+ {
+ if( this->process(buf,sizeof(buf)) == -1 )
+ {
+ return(-1);
+ }
+ }
+
+ return(0);
+}
+
+/*
+ Once again, we see that the application-level logic has not been at all affected
+ by our choice of threading models. Of course, I'm not sharing data between threads
+ or anything. We'll leave locking issues for a later tutorial.
+ */
+int Client_Handler::process (char *_rdbuf, int _rdbuf_len)
+{
+ switch (this->peer ().recv (_rdbuf, _rdbuf_len))
+ {
+ case -1:
+ ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) %p bad read\n", "client"), -1);
+ case 0:
+ ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) closing daemon (fd = %d)\n", this->get_handle ()), -1);
+ default:
+ ACE_DEBUG ((LM_DEBUG, "(%P|%t) from client: %s", _rdbuf));
+ }
+
+ return 0;
+}
diff --git a/docs/tutorials/007/client_handler.h b/docs/tutorials/007/client_handler.h
new file mode 100644
index 00000000000..c86012d4b7b
--- /dev/null
+++ b/docs/tutorials/007/client_handler.h
@@ -0,0 +1,156 @@
+
+// $Id$
+
+#ifndef CLIENT_HANDLER_H
+#define CLIENT_HANDLER_H
+
+/*
+ Our client handler must exist somewhere in the ACE_Event_Handler object
+ hierarchy. This is a requirement of the ACE_Reactor because it maintains
+ ACE_Event_Handler pointers for each registered event handler. You could
+ derive our Client_Handler directly from ACE_Event_Handler but you still have
+ to have an ACE_SOCK_Stream for the actually connection. With a direct
+ derivative of ACE_Event_Handler, you'll have to contain and maintain an
+ ACE_SOCK_Stream instance yourself. With ACE_Svc_Handler (which is a
+ derivative of ACE_Event_Handler) some of those details are handled for you.
+ */
+
+#include "ace/Svc_Handler.h"
+#include "ace/SOCK_Stream.h"
+
+class Client_Acceptor;
+class Thread_Pool;
+
+/*
+ Another feature of ACE_Svc_Handler is it's ability to present the ACE_Task<>
+ interface as well. That's what the ACE_NULL_SYNCH parameter below is all
+ about. That's beyond our scope here but we'll come back to it in the next
+ tutorial when we start looking at concurrency options.
+ */
+class Client_Handler : public ACE_Svc_Handler < ACE_SOCK_STREAM, ACE_NULL_SYNCH >
+{
+public:
+
+ // Constructor...
+ Client_Handler (void);
+
+ /*
+ The destroy() method is our preferred method of destruction. We could
+ have overloaded the delete operator but that is neither easy nor
+ intuitive (at least to me). Instead, we provide a new method of
+ destruction and we make our destructor protected so that only ourselves,
+ our derivatives and our friends can delete us. It's a nice
+ compromise.
+ */
+ void destroy (void);
+
+ /*
+ Most ACE objects have an open() method. That's how you make them ready
+ to do work. ACE_Event_Handler has a virtual open() method which allows us
+ to create this overrride. ACE_Acceptor<> will invoke this method after
+ creating a new Client_Handler when a client connects. Notice that the
+ parameter to open() is a void*. It just so happens that the pointer
+ points to the acceptor which created us. You would like for the parameter
+ to be an ACE_Acceptor<>* but since ACE_Event_Handler is generic, that
+ would tie it too closely to the ACE_Acceptor<> set of objects. In our
+ definition of open() you'll see how we get around that.
+ */
+ int open (void *_acceptor);
+
+ /*
+ When there is activity on a registered handler, the handle_input() method
+ of the handler will be invoked. If that method returns an error code (eg
+ -- -1) then the reactor will invoke handle_close() to allow the object to
+ clean itself up. Since an event handler can be registered for more than
+ one type of callback, the callback mask is provided to inform
+ handle_close() exactly which method failed. That way, you don't have to
+ maintain state information between your handle_* method calls. The _handle
+ parameter is explained below...
+ */
+ int handle_close (ACE_HANDLE _handle, ACE_Reactor_Mask _mask);
+
+ /*
+ When we register with the reactor, we're going to tell it that we want to
+ be notified of READ events. When the reactor sees that there is read
+ activity for us, our handle_input() will be invoked. The _handleg
+ provided is the handle (file descriptor in Unix) of the actual connection
+ causing the activity. Since we're derived from ACE_Svc_Handler<> and it
+ maintains it's own peer (ACE_SOCK_Stream) object, this is redundant for
+ us. However, if we had been derived directly from ACE_Event_Handler, we
+ may have chosen not to contain the peer. In that case, the _handleg
+ would be important to us for reading the client's data.
+ */
+ int handle_input (ACE_HANDLE _handle);
+
+protected:
+
+ /*
+ If the Client_Acceptor which created us has chosen a thread-per-connection
+ strategy then our open() method will activate us into a dedicate thread.
+ The svc() method will then execute in that thread performing some of the
+ functions we used to leave up to the reactor.
+ */
+ int svc(void);
+
+ /*
+ This has nothing at all to do with ACE. I've added this here as a worker
+ function which I will call from handle_input(). That allows me to
+ introduce concurrencly in later tutorials with a no changes to the worker
+ function. You can think of process() as application-level code and
+ everything elase as application-framework code.
+ */
+ int process (char *_rdbuf, int _rdbuf_len);
+
+ /*
+ We don't really do anything in our destructor but we've declared it to be
+ protected to prevent casual deletion of this object. As I said above, I
+ really would prefer that everyone goes through the destroy() method to get
+ rid of us.
+ */
+ ~Client_Handler (void);
+
+ /*
+ When we get to the definition of Client_Handler we'll see that there are
+ several places where we go back to the Client_Acceptor for information.
+ It is generally a good idea to do that through an accesor rather than
+ using the member variable directly.
+ */
+ Client_Acceptor * client_acceptor( void )
+ { return this->client_acceptor_; }
+
+ /*
+ And since you shouldn't access a member variable directly, neither should you
+ set (mutate) it. Although it might seem silly to do it this way, you'll thank
+ yourself for it later.
+ */
+ void client_acceptor( Client_Acceptor * _client_acceptor )
+ { this->client_acceptor_ = _client_acceptor; }
+
+ /*
+ The concurrency() accessor tells us the current concurrency strategy. It actually
+ queries the Client_Acceptor for it but by having the accessor in place, we could
+ change our implementation without affecting everything that needs to know.
+ */
+ int concurrency(void);
+
+ /*
+ Likewise for access to the Thread_Pool that we belong to.
+ */
+ Thread_Pool * thread_pool(void);
+
+
+ Client_Acceptor * client_acceptor_;
+
+ /*
+ For some reason I didn't create accessor/mutator methods for this. So much for
+ consistency....
+
+ This variable is used to remember the thread in which we were created: the "creator"
+ thread in other words. handle_input() needs to know if it is operating in the
+ main reactor thread (which is the one that created us) or if it is operating in
+ one of the thread pool threads. More on this when we get to handle_input().
+ */
+ ACE_thread_t creator_;
+};
+
+#endif // CLIENT_HANDLER_H
diff --git a/docs/tutorials/007/fix.Makefile b/docs/tutorials/007/fix.Makefile
new file mode 100755
index 00000000000..e99c194114a
--- /dev/null
+++ b/docs/tutorials/007/fix.Makefile
@@ -0,0 +1,60 @@
+#!/usr/bin/perl
+
+ # Open the Makefile that has been mangled by 'make depend'
+ # and suck it into a perl array.
+open(IF,"<Makefile") || die;
+@makefile = <IF>;
+close(IF);
+
+ # Now open our .depend file and a temporary Makefile.
+ # We'll split the original Makefile between these two.
+open(DF,">.depend") || die;
+open(MF,">Makefile.tmp") || die;
+
+ # For each line we read out of the original file...
+foreach (@makefile) {
+
+ # If we're into the dependency section, write the line
+ # into the .depend file.
+ #
+ if( $depend ) {
+ print DF $_;
+ }
+ else {
+ # If we haven't gotten to the dependency section yet
+ # then see if the current line is the separator that
+ # "make depend" causes to be inserted.
+ #
+ if( m/^\Q# DO NOT DELETE THIS LINE -- g++dep uses it.\E/ ) {
+
+ # If so, change our "mode" and skip this line.
+ ++$depend;
+ next;
+ }
+
+ # Also skip the "include .depend" that we insert. If we
+ # don't do this, it is possible to have a bunch of these
+ # inserted into the output when we read an unmangled Makefile
+ next if( m/^include .depend/ );
+
+ # Print the non-dependency info to the temporary Makefile
+ print MF $_;
+ }
+}
+
+# Tell our new Makefile to include the dependency file
+print MF "include .depend\n";
+
+# Close the two output files...
+close(DF);
+close(MF);
+
+# Unlink (remove) the original Makefile and rename our
+# temporary file. There's obviously room for error checking
+# here but we've got the Makefile checked into some revision
+# control system anyway. Don't we?
+
+unlink("Makefile");
+rename("Makefile.tmp","Makefile");
+
+exit(0);
diff --git a/docs/tutorials/007/page01.html b/docs/tutorials/007/page01.html
new file mode 100644
index 00000000000..9402426de3f
--- /dev/null
+++ b/docs/tutorials/007/page01.html
@@ -0,0 +1,33 @@
+<HTML>
+<HEAD>
+ <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+ <META NAME="GENERATOR" CONTENT="Mozilla/4.04 [en] (X11; I; Linux 2.0.32 i486) [Netscape]">
+ <META NAME="Author" CONTENT="James CE Johnson">
+ <META NAME="Description" CONTENT="A first step towards using ACE productively">
+ <TITLE>ACE Tutorial 007</TITLE>
+</HEAD>
+<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F">
+
+<CENTER><B><FONT SIZE=+2>ACE Tutorial 007</FONT></B></CENTER>
+
+<CENTER><B><FONT SIZE=+2>Creating a thread-pool server</FONT></B></CENTER>
+
+
+<P>
+<HR WIDTH="100%">
+
+<P>In this tutorial, we're going to extend Tutorial 6 to add a third concurrency
+strategy:&nbsp; thread-pool.&nbsp; Like Tutorail 6 did to Tutorial 5, we're
+going to keep the existing strategies that we've already created and add
+this one in as a "bonus".&nbsp; As you'll see, our basic objects will change
+but not by a whole lot.&nbsp; To accomplish this, we'll introduce one new
+major object that helps to abstract the thread pool concept.
+
+<P>
+<HR WIDTH="100%">
+<CENTER>[<A HREF="..">Tutorial
+Index</A>] [<A HREF="page02.html">Continue
+This Tutorial</A>]</CENTER>
+
+</BODY>
+</HTML>
diff --git a/docs/tutorials/007/page02.html b/docs/tutorials/007/page02.html
new file mode 100644
index 00000000000..c6e7bedec43
--- /dev/null
+++ b/docs/tutorials/007/page02.html
@@ -0,0 +1,197 @@
+<HTML>
+<HEAD>
+ <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+ <META NAME="GENERATOR" CONTENT="Mozilla/4.04 [en] (X11; I; Linux 2.0.32 i486) [Netscape]">
+ <META NAME="Author" CONTENT="James CE Johnson">
+ <META NAME="Description" CONTENT="A first step towards using ACE productively">
+ <TITLE>ACE Tutorial 007</TITLE>
+</HEAD>
+<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F">
+
+<CENTER><B><FONT SIZE=+2>ACE Tutorial 007</FONT></B></CENTER>
+
+<CENTER><B><FONT SIZE=+2>Creating a thread-pool server</FONT></B></CENTER>
+
+
+<P>
+<HR WIDTH="100%">
+
+<P>As usualy, we start with <A HREF="server.cpp">server.cpp</A>
+<BR>
+<HR WIDTH="100%">
+
+<P><FONT FACE="Arial,Helvetica">// $Id: server.cpp,v 1.1 1998/08/30 16:04:12
+jcej Exp $</FONT>
+
+<P><FONT FACE="Arial,Helvetica">/*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; We try to keep main() very
+simple.&nbsp; One of the ways we do that is to push</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; much of the complicated stuff
+into worker objects.&nbsp; In this case, we only</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; need to include the acceptor
+header in our main source file.&nbsp; We let it</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; worry about the "real work".</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;*/</FONT>
+
+<P><FONT FACE="Arial,Helvetica">#include "client_acceptor.h"</FONT>
+
+<P><FONT FACE="Arial,Helvetica">/*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; As before, we create a simple
+signal handler that will set our finished</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; flag.&nbsp; There are, of
+course, more elegant ways to handle program shutdown</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; requests but that isn't really
+our focus right now, so we'll just do the</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; easiest thing.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;*/</FONT>
+
+<P><FONT FACE="Arial,Helvetica">static sig_atomic_t finished = 0;</FONT>
+<BR><FONT FACE="Arial,Helvetica">extern "C" void handler (int)</FONT>
+<BR><FONT FACE="Arial,Helvetica">{</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp; finished = 1;</FONT>
+<BR><FONT FACE="Arial,Helvetica">}</FONT>
+
+<P><FONT FACE="Arial,Helvetica">/*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; A server has to listen for
+clients at a known TCP/IP port.&nbsp; The default ACE</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; port is 10002 (at least on
+my system) and that's good enough for what&nbsp; we</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; want to do here.&nbsp; Obviously,
+a more robust application would take a command</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; line parameter or read from
+a configuration file or do some other&nbsp; clever</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; thing.&nbsp; Just like the
+signal handler above, though, that's what we want to</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; focus on, so we're taking
+the easy way out.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;*/</FONT>
+
+<P><FONT FACE="Arial,Helvetica">static const u_short PORT = ACE_DEFAULT_SERVER_PORT;</FONT>
+
+<P><FONT FACE="Arial,Helvetica">/*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; Finally, we get to main.&nbsp;
+Some C++ compilers will complain loudly if your</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; function signature doesn't
+match the prototype.&nbsp; Even though we're not</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; going to use the parameters,
+we still&nbsp; have to specify them.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;*/</FONT>
+
+<P><FONT FACE="Arial,Helvetica">int main (int argc, char *argv[])</FONT>
+<BR><FONT FACE="Arial,Helvetica">{</FONT>
+<BR><FONT FACE="Arial,Helvetica">/*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; In our earlier servers, we
+used a global pointer to get to the reactor. I've</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; never really liked that idea,
+so I've moved it into main() this time. When</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; we&nbsp; get to the Client_Handler
+object you'll see how we manage to get a</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; pointer back to this reactor.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;*/</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp; ACE_Reactor reactor;</FONT>
+
+<P><FONT FACE="Arial,Helvetica">&nbsp; /*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; The acceptor
+will take care of letting clients connect to us.&nbsp; It will</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; also arrange
+for a&nbsp; Client_Handler to be created for each new client.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; Since we're only
+going to listen at one&nbsp; TCP/IP port, we only need one</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; acceptor.&nbsp;
+If we wanted, though, we could create several of these&nbsp; and</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; listen at several
+ports.&nbsp; (That's what we would do if we wanted to rewrite</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; inetd for&nbsp;
+instance.)</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; */</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp; Client_Acceptor peer_acceptor;</FONT>
+
+<P><FONT FACE="Arial,Helvetica">&nbsp; /*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; Create an ACE_INET_Addr
+that represents our endpoint of a connection. We</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; then open our
+acceptor object with that Addr.&nbsp; Doing so tells the acceptor</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; where to listen
+for connections.&nbsp; Servers generally listen at "well known"</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; addresses.&nbsp;
+If not, there must be some mechanism by which the client is</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; informed of the
+server's address.</FONT>
+
+<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; Note how ACE_ERROR_RETURN
+is used if we fail to open the acceptor.&nbsp; This</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; technique is
+used over and over again in our tutorials.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; */</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp; if (peer_acceptor.open (ACE_INET_Addr
+(PORT), &amp;reactor) == -1)</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp; ACE_ERROR_RETURN ((LM_ERROR,
+"%p\n", "open"), -1);</FONT>
+
+<P><FONT FACE="Arial,Helvetica">&nbsp; /*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; Install our signal
+handler.&nbsp; You can actually register signal handlers</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; with the reactor.&nbsp;
+You might do that when the signal handler is</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; responsible for
+performing "real" work.&nbsp; Our simple flag-setter doesn't</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; justify deriving
+from ACE_Event_Handler and providing a callback function</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; though.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; */</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp; ACE_Sig_Action sa ((ACE_SignalHandler)
+handler, SIGINT);</FONT>
+
+<P><FONT FACE="Arial,Helvetica">&nbsp; /*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; Like ACE_ERROR_RETURN,
+the ACE_DEBUG macro gets used quite a bit.&nbsp; It's a</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; handy way to
+generate uniform debug output from your program.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; */</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp; ACE_DEBUG ((LM_DEBUG, "(%P|%t)
+starting up server daemon\n"));</FONT>
+
+<P><FONT FACE="Arial,Helvetica">&nbsp; /*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; This will loop
+"forever" invoking the handle_events() method of our</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; reactor. handle_events()
+watches for activity on any registered handlers</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; and invokes their
+appropriate callbacks when necessary.&nbsp; Callback-driven</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; programming is
+a big thing in ACE, you should get used to it. If the</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; signal handler
+catches something, the finished flag will be set and we'll</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; exit.&nbsp; Conveniently
+enough, handle_events() is also interrupted by signals</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; and will exit
+back to the while() loop.&nbsp; (If you want your event loop to</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; not be interrupted
+by signals, checkout the &lt;i>restart&lt;/i> flag on the</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; open() method
+of ACE_Reactor if you're interested.)</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; */</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp; while (!finished)</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+reactor.handle_events ();</FONT>
+
+<P><FONT FACE="Arial,Helvetica">&nbsp; ACE_DEBUG ((LM_DEBUG, "(%P|%t) shutting
+down server daemon\n"));</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp; return 0;</FONT>
+<BR><FONT FACE="Arial,Helvetica">}</FONT>
+
+<P>
+<HR WIDTH="100%">
+
+<P>Hmmm... No change there.&nbsp;&nbsp; Maybe I should leave out comments
+on the stuff I don't change.&nbsp; Let's take a lookt at client_acceptor.h.
+
+<P>
+<HR WIDTH="100%">
+<CENTER>[<A HREF="..">Tutorial
+Index</A>] [<A HREF="page03.html">Continue
+This Tutorial</A>]</CENTER>
+
+</BODY>
+</HTML>
diff --git a/docs/tutorials/007/page03.html b/docs/tutorials/007/page03.html
new file mode 100644
index 00000000000..694ed2505cc
--- /dev/null
+++ b/docs/tutorials/007/page03.html
@@ -0,0 +1,263 @@
+<HTML>
+<HEAD>
+ <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+ <META NAME="GENERATOR" CONTENT="Mozilla/4.04 [en] (X11; I; Linux 2.0.32 i486) [Netscape]">
+ <META NAME="Author" CONTENT="James CE Johnson">
+ <META NAME="Description" CONTENT="A first step towards using ACE productively">
+ <TITLE>ACE Tutorial 007</TITLE>
+</HEAD>
+<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F">
+
+<CENTER><B><FONT SIZE=+2>ACE Tutorial 007</FONT></B></CENTER>
+
+<CENTER><B><FONT SIZE=+2>Creating a thread-pool server</FONT></B></CENTER>
+
+
+<P>
+<HR WIDTH="100%">
+
+<P>Let's see what things we've had to add to <A HREF="client_acceptor.h">client_acceptor.h</A>.
+
+<P>
+<HR WIDTH="100%">
+<BR><FONT FACE="Arial,Helvetica">// $Id: client_acceptor.h,v 1.1 1998/08/30
+16:04:11 jcej Exp $</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">#ifndef CLIENT_ACCEPTOR_H</FONT>
+<BR><FONT FACE="Arial,Helvetica">#define CLIENT_ACCEPTOR_H</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">/*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; The ACE_Acceptor&lt;> template
+lives in the ace/Acceptor.h header file. You'll</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; find a very consitent naming
+convention between the ACE objects and the</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; headers where they can be
+found.&nbsp; In general, the ACE object ACE_Foobar will</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; be found in ace/Foobar.h.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;*/</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">#include "ace/Acceptor.h"</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">/*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; Since we want to work with
+sockets, we'll need a SOCK_Acceptor to allow the</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; clients to connect to us.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;*/</FONT>
+<BR><FONT FACE="Arial,Helvetica">#include "ace/SOCK_Acceptor.h"</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">/*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; The Client_Handler object
+we develop will be used to handle clients once</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; they're connected.&nbsp;
+The ACE_Acceptor&lt;> template's first parameter requires</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; such an object.&nbsp; In
+some cases, you can get by with just a forward</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; declaration on the class,
+in others you have to have the whole thing.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;*/</FONT>
+<BR><FONT FACE="Arial,Helvetica">#include "client_handler.h"</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">/*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; Parameterize the ACE_Acceptor&lt;>
+such that it will listen for socket</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; connection attempts and create
+Client_Handler objects when they happen. In</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; Tutorial 001, we wrote the
+basic acceptor logic on our own before we</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; realized that ACE_Acceptor&lt;>
+was available.&nbsp; You'll get spoiled using the</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; ACE templates because they
+take away a lot of the tedious details!</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;*/</FONT>
+<BR><FONT FACE="Arial,Helvetica">typedef ACE_Acceptor &lt; Client_Handler,
+ACE_SOCK_ACCEPTOR > Client_Acceptor_Base;</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">#include "thread_pool.h"</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">/*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; This time we've added quite
+a bit more to our acceptor.&nbsp; In addition to</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; providing a choice of concurrency
+strategies, we also maintain a Thread_Pool</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; object in case that strategy
+is chosen.&nbsp; The object still isn't very complex</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; but it's come a long way
+from the simple typedef we had in Tutorial 5.</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; Why keep the thread pool as
+a member?&nbsp; If we go back to the inetd concept</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; you'll recall that we need
+several acceptors to make that work.&nbsp; We may have</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; a situation in which our
+different client types requre different resources.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; That is, we may need a large
+thread pool for some client types and a smaller</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; one for others.&nbsp; We
+could share a pool but then the client types may have</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; undesirable impact on one
+another.</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; Just in case you do want to
+share a single thread pool, there is a constructor</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; below that will let you do
+that.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;*/</FONT>
+<BR><FONT FACE="Arial,Helvetica">class Client_Acceptor : public Client_Acceptor_Base</FONT>
+<BR><FONT FACE="Arial,Helvetica">{</FONT>
+<BR><FONT FACE="Arial,Helvetica">public:</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+typedef Client_Acceptor_Base inherited;</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+/*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Now that we have more than two strategies, we need more than a boolean</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+to tell us what we're using.&nbsp; A set of enums is a good choice because</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+it allows us to use named values.&nbsp; Another option would be a set of</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+static const integers.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+*/</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+enum concurrency_t</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+{</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+single_threaded_,</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+thread_per_connection_,</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+thread_pool_</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+};</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+/*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+The default constructor allows the programmer to choose the concurrency</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+strategy.&nbsp; Since we want to focus on thread-pool, that's what we'll
+use</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+if nothing is specified.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+*/</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Client_Acceptor( int _concurrency = thread_pool_ );</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+/*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Another option is to construct the object with an existing thread pool.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+The&nbsp; concurrency strategy is pretty obvious at that point.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+*/</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Client_Acceptor( Thread_Pool &amp; _thread_pool );</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+/*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Our destructor will take care of shutting down the thread-pool</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+if applicable.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+*/</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+~Client_Acceptor( void );</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+/*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Open ourselves and register with the given reactor.&nbsp; The thread pool
+size</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+can be specified here if you want to use that concurrency strategy.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+*/</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+int open( const ACE_INET_Addr &amp; _addr, ACE_Reactor * _reactor,</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+int _pool_size = Thread_Pool::default_pool_size_ );</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+/*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Close ourselves and our thread pool if applicable</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+*/</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+int close(void);</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+/*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+What is our concurrency strategy?</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+*/</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+int concurrency(void)</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+{ return this->concurrency_; }</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+/*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Give back a pointer to our thread pool.&nbsp; Our Client_Handler objects</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+will need this so that their handle_input() methods can put themselves</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+into the pool.&nbsp; Another alternative would be a globally accessible</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+thread pool.&nbsp; ACE_Singleton&lt;> is a way to achieve that.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+*/</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Thread_Pool * thread_pool(void)</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+{ return &amp; this->the_thread_pool_; }</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+/*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Since we can be constructed with a Thread_Pool reference, there are times</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+when we need to know if the thread pool we're using is ours or if we're</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+just borrowing it from somebody else.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+*/</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+int thread_pool_is_private(void)</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+{ return &amp;the_thread_pool_ == &amp;private_thread_pool_; }</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">protected:</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+int concurrency_;</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Thread_Pool&nbsp;&nbsp; private_thread_pool_;</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Thread_Pool &amp; the_thread_pool_;</FONT>
+<BR><FONT FACE="Arial,Helvetica">};</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">#endif // CLIENT_ACCEPTOR_H</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P>
+<HR WIDTH="100%">
+
+<P>Well, except for the new Thread_Pool member variable, most of the changes
+are informational.
+
+<P>
+<HR WIDTH="100%">
+<CENTER>[<A HREF="..">Tutorial Index</A>] [<A HREF="page04.html">Continue
+This Tutorial</A>]</CENTER>
+
+</BODY>
+</HTML>
diff --git a/docs/tutorials/007/page04.html b/docs/tutorials/007/page04.html
new file mode 100644
index 00000000000..c74bcdf7dae
--- /dev/null
+++ b/docs/tutorials/007/page04.html
@@ -0,0 +1,133 @@
+<HTML>
+<HEAD>
+ <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+ <META NAME="GENERATOR" CONTENT="Mozilla/4.04 [en] (X11; I; Linux 2.0.32 i486) [Netscape]">
+ <META NAME="Author" CONTENT="James CE Johnson">
+ <META NAME="Description" CONTENT="A first step towards using ACE productively">
+ <TITLE>ACE Tutorial 007</TITLE>
+</HEAD>
+<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F">
+
+<CENTER><B><FONT SIZE=+2>ACE Tutorial 007</FONT></B></CENTER>
+
+<CENTER><B><FONT SIZE=+2>Creating a thread-pool server</FONT></B></CENTER>
+
+
+<P>
+<HR WIDTH="100%">
+
+<P>Something new this time is <A HREF="client_acceptor.cpp">client_acceptor.cpp</A>.&nbsp;
+I finally had enough code to move it out of the header.
+
+<P>
+<HR WIDTH="100%">
+<BR><FONT FACE="Arial,Helvetica">// $Id: client_acceptor.cpp,v 1.1 1998/08/30
+16:04:11 jcej Exp $</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">#include "client_acceptor.h"</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">/*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; Construct ourselves with
+the chosen concurrency strategy.&nbsp; Notice that we also</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; set our Thread_Pool reference
+to our private instance.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;*/</FONT>
+<BR><FONT FACE="Arial,Helvetica">Client_Acceptor::Client_Acceptor( int
+_concurrency )</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;:&nbsp; concurrency_(_concurrency)</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; ,the_thread_pool_(private_thread_pool_)</FONT>
+<BR><FONT FACE="Arial,Helvetica">{</FONT>
+<BR><FONT FACE="Arial,Helvetica">}</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">/*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; Construct ourselves with
+a reference to somebody else' Thread_Pool.&nbsp; Obvioulsy</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; our concurrency strategy
+is "thread_pool_" at this point.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;*/</FONT>
+<BR><FONT FACE="Arial,Helvetica">Client_Acceptor::Client_Acceptor( Thread_Pool
+&amp; _thread_pool )</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;:&nbsp; concurrency_(thread_pool_)</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; ,the_thread_pool_(_thread_pool)</FONT>
+<BR><FONT FACE="Arial,Helvetica">{</FONT>
+<BR><FONT FACE="Arial,Helvetica">}</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">/*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; When we're destructed, we
+may need to cleanup after ourselves.&nbsp; If we're running</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; with a thread pool that we
+own, it is up to us to close it down.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;*/</FONT>
+<BR><FONT FACE="Arial,Helvetica">Client_Acceptor::~Client_Acceptor( void
+)</FONT>
+<BR><FONT FACE="Arial,Helvetica">{</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+if( this->concurrency() == thread_pool_ &amp;&amp; thread_pool_is_private()
+)</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+{</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+thread_pool()->close();</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+}</FONT>
+<BR><FONT FACE="Arial,Helvetica">}</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">/*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; Similar to the destructor
+(and close() below) it is necessary for us to open the</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; thread pool in some circumstances.</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; Notice how we delegate most
+of the open() work to the open() method of our baseclass.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;*/</FONT>
+<BR><FONT FACE="Arial,Helvetica">int Client_Acceptor::open( const ACE_INET_Addr
+&amp; _addr, ACE_Reactor * _reactor, int _pool_size )</FONT>
+<BR><FONT FACE="Arial,Helvetica">{</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+if( this->concurrency() == thread_pool_ &amp;&amp; thread_pool_is_private()
+)</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+{</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+thread_pool()->open(_pool_size);</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+}</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+return inherited::open(_addr,_reactor);</FONT>
+<BR><FONT FACE="Arial,Helvetica">}</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">/*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; Here again we find that we
+have to manage the thread pool.&nbsp; Like open() we also delegate</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; the other work to our baseclass.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;*/</FONT>
+<BR><FONT FACE="Arial,Helvetica">int Client_Acceptor::close(void)</FONT>
+<BR><FONT FACE="Arial,Helvetica">{</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+if( this->concurrency() == thread_pool_ &amp;&amp; thread_pool_is_private()
+)</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+{</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+thread_pool()->close();</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+}</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+return inherited::close();</FONT>
+<BR><FONT FACE="Arial,Helvetica">}</FONT>
+<BR><FONT FACE="Arial,Helvetica"></FONT>&nbsp;<FONT FACE="Arial,Helvetica"></FONT>
+
+<P>
+<HR WIDTH="100%">
+
+<P>Nothing really surprising here.&nbsp; Most of it just manages the Thread_Pool.
+
+<P>
+<HR WIDTH="100%">
+<CENTER>[<A HREF="..">Tutorial Index</A>] [<A HREF="page05.html">Continue
+This Tutorial</A>]</CENTER>
+
+</BODY>
+</HTML>
diff --git a/docs/tutorials/007/page05.html b/docs/tutorials/007/page05.html
new file mode 100644
index 00000000000..7e8df23e750
--- /dev/null
+++ b/docs/tutorials/007/page05.html
@@ -0,0 +1,282 @@
+<HTML>
+<HEAD>
+ <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+ <META NAME="GENERATOR" CONTENT="Mozilla/4.04 [en] (X11; I; Linux 2.0.32 i486) [Netscape]">
+ <META NAME="Author" CONTENT="James CE Johnson">
+ <META NAME="Description" CONTENT="A first step towards using ACE productively">
+ <TITLE>ACE Tutorial 007</TITLE>
+</HEAD>
+<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F">
+
+<CENTER><B><FONT SIZE=+2>ACE Tutorial 007</FONT></B></CENTER>
+
+<CENTER><B><FONT SIZE=+2>Creating a thread-pool server</FONT></B></CENTER>
+
+
+<P>
+<HR WIDTH="100%">
+
+<P>As you might expect, <A HREF="client_handler.h">client_handler.h</A>
+is next.
+
+<P>
+<HR WIDTH="100%">
+<BR><FONT FACE="Arial,Helvetica"></FONT>&nbsp;<FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">// $Id: client_handler.h,v 1.1 1998/08/30
+16:04:12 jcej Exp $</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">#ifndef CLIENT_HANDLER_H</FONT>
+<BR><FONT FACE="Arial,Helvetica">#define CLIENT_HANDLER_H</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">/*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; Our client handler must exist
+somewhere in the ACE_Event_Handler object</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; hierarchy.&nbsp; This is
+a requirement of the ACE_Reactor because it maintains</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; ACE_Event_Handler pointers
+for each registered event handler.&nbsp; You could</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; derive our Client_Handler
+directly from ACE_Event_Handler but you still have</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; to have an ACE_SOCK_Stream
+for the actually connection.&nbsp; With a direct</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; derivative of ACE_Event_Handler,
+you'll have to contain and maintain an</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; ACE_SOCK_Stream instance
+yourself.&nbsp; With ACE_Svc_Handler (which is a</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; derivative of ACE_Event_Handler)
+some of those details are handled for you.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;*/</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">#include "ace/Svc_Handler.h"</FONT>
+<BR><FONT FACE="Arial,Helvetica">#include "ace/SOCK_Stream.h"</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">class Client_Acceptor;</FONT>
+<BR><FONT FACE="Arial,Helvetica">class Thread_Pool;</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">/*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; Another feature of ACE_Svc_Handler
+is it's ability to present the ACE_Task&lt;></FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; interface as well.&nbsp;
+That's what the ACE_NULL_SYNCH parameter below is all</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; about.&nbsp; That's beyond
+our scope here but we'll come back to it in the next</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; tutorial when we start looking
+at concurrency options.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;*/</FONT>
+<BR><FONT FACE="Arial,Helvetica">class Client_Handler : public ACE_Svc_Handler
+&lt; ACE_SOCK_STREAM, ACE_NULL_SYNCH ></FONT>
+<BR><FONT FACE="Arial,Helvetica">{</FONT>
+<BR><FONT FACE="Arial,Helvetica">public:</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">&nbsp; // Constructor...</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp; Client_Handler (void);</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">&nbsp; /*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; The destroy()
+method is our preferred method of destruction.&nbsp; We could</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; have overloaded
+the delete operator but that is neither easy nor</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; intuitive (at
+least to me).&nbsp; Instead, we provide a new method of</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; destruction and
+we make our destructor protected so that only ourselves,</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; our derivatives
+and our friends can delete us. It's a nice</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; compromise.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; */</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp; void destroy (void);</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">&nbsp; /*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; Most ACE objects
+have an open() method.&nbsp; That's how you make them ready</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; to do work.&nbsp;
+ACE_Event_Handler has a virtual open() method which allows us</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; to create this
+overrride.&nbsp; ACE_Acceptor&lt;> will invoke this method after</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; creating a new
+Client_Handler when a client connects. Notice that the</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; parameter to
+open() is a void*.&nbsp; It just so happens that the pointer</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; points to the
+acceptor which created us.&nbsp; You would like for the parameter</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; to be an ACE_Acceptor&lt;>*
+but since ACE_Event_Handler is generic, that</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; would tie it
+too closely to the ACE_Acceptor&lt;> set of objects.&nbsp; In our</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; definition of
+open() you'll see how we get around that.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; */</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp; int open (void *_acceptor);</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">&nbsp; /*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; When there is
+activity on a registered handler, the handle_input() method</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; of the handler
+will be invoked.&nbsp; If that method returns an error code (eg</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; -- -1) then the
+reactor will invoke handle_close() to allow the object to</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; clean itself
+up. Since an event handler can be registered for more than</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; one type of callback,
+the callback mask is provided to inform</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; handle_close()
+exactly which method failed.&nbsp; That way, you don't have to</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; maintain state
+information between your handle_* method calls. The _handle</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; parameter is
+explained below...</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; */</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp; int handle_close (ACE_HANDLE _handle,
+ACE_Reactor_Mask _mask);</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">&nbsp; /*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; When we register
+with the reactor, we're going to tell it that we want to</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; be notified of
+READ events.&nbsp; When the reactor sees that there is read</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; activity for
+us, our handle_input() will be invoked. The _handleg</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; provided is the
+handle (file descriptor in Unix) of the actual connection</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; causing the activity.&nbsp;
+Since we're derived from ACE_Svc_Handler&lt;> and it</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; maintains it's
+own peer (ACE_SOCK_Stream) object, this is redundant for</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; us.&nbsp; However,
+if we had been derived directly from ACE_Event_Handler, we</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; may have chosen
+not to contain the peer.&nbsp; In that case, the _handleg</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; would be important
+to us for reading the client's data.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; */</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp; int handle_input (ACE_HANDLE _handle);</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">protected:</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">&nbsp; /*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; If the Client_Acceptor
+which created us has chosen a thread-per-connection</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; strategy then
+our open() method will activate us into a dedicate thread.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; The svc() method
+will then execute in that thread performing some of the</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; functions we
+used to leave up to the reactor.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; */</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp; int svc(void);</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">&nbsp; /*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; This has nothing
+at all to do with ACE.&nbsp; I've added this here as a worker</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; function which
+I will call from handle_input().&nbsp; That allows me to</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; introduce concurrencly
+in later tutorials with a no changes to the worker</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; function.&nbsp;
+You can think of process() as application-level code and</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; everything elase
+as application-framework code.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; */</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp; int process (char *_rdbuf, int
+_rdbuf_len);</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">&nbsp; /*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; We don't really
+do anything in our destructor but we've declared it to be</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; protected to
+prevent casual deletion of this object.&nbsp; As I said above, I</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; really would
+prefer that everyone goes through the destroy() method to get</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; rid of us.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; */</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; ~Client_Handler (void);</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; /*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; When we
+get to the definition of Client_Handler we'll see that there are</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+several places where we go back to the Client_Acceptor for information.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+It is generally a good idea to do that through an accesor rather than</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+using the member variable directly.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp; */</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; Client_Acceptor * client_acceptor(
+void )</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+{ return this->client_acceptor_; }</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; /*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; And since
+you shouldn't access a member variable directly, neither should you</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+set (mutate) it.&nbsp; Although it might seem silly to do it this way,
+you'll thank</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+yourself for it later.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp; */</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; void client_acceptor( Client_Acceptor
+* _client_acceptor )</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+{ this->client_acceptor_ = _client_acceptor; }</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; /*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; The concurrency()
+accessor tells us the current concurrency strategy.&nbsp; It actually</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+queries the Client_Acceptor for it but by having the accessor in place,
+we could</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+change our implementation without affecting everything that needs to know.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp; */</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; int concurrency(void);</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; /*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Likewise
+for access to the Thread_Pool that we belong to.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp; */</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; Thread_Pool * thread_pool(void);</FONT>
+<BR><FONT FACE="Arial,Helvetica"></FONT>&nbsp;<FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; Client_Acceptor * client_acceptor_;</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; /*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; For some
+reason I didn't create accessor/mutator methods for this.&nbsp; So much
+for</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+consistency....</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+This variable is used to remember the thread in which we were created:&nbsp;
+the "creator"</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+thread in other words.&nbsp; handle_input() needs to know if it is operating
+in the</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+main reactor thread (which is the one that created us) or if it is operating
+in</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+one of the thread pool threads.&nbsp; More on this when we get to handle_input().</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp; */</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; ACE_thread_t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+creator_;</FONT>
+<BR><FONT FACE="Arial,Helvetica">};</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">#endif // CLIENT_HANDLER_H</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P>
+<HR WIDTH="100%">
+
+<P>Still, we're just not seeing a lot of changes due to intruduction of
+the thread pool.&nbsp; That's a good thing! You don't want to go turning
+your application upside down just because you changed thread models.
+
+<P>
+<HR WIDTH="100%">
+<CENTER>[<A HREF="..">Tutorial Index</A>] [<A HREF="page06.html">Continue
+This Tutorial</A>]</CENTER>
+
+</BODY>
+</HTML>
diff --git a/docs/tutorials/007/page06.html b/docs/tutorials/007/page06.html
new file mode 100644
index 00000000000..605cc80a03f
--- /dev/null
+++ b/docs/tutorials/007/page06.html
@@ -0,0 +1,332 @@
+<HTML>
+<HEAD>
+ <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+ <META NAME="GENERATOR" CONTENT="Mozilla/4.04 [en] (X11; I; Linux 2.0.32 i486) [Netscape]">
+ <META NAME="Author" CONTENT="James CE Johnson">
+ <META NAME="Description" CONTENT="A first step towards using ACE productively">
+ <TITLE>ACE Tutorial 007</TITLE>
+</HEAD>
+<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F">
+
+<CENTER><B><FONT SIZE=+2>ACE Tutorial 007</FONT></B></CENTER>
+
+<CENTER><B><FONT SIZE=+2>Creating a thread-pool server</FONT></B></CENTER>
+
+
+<P>
+<HR WIDTH="100%">
+
+<P><A HREF="client_handler.cpp">client_handler.cpp</A> shows some of the
+changes due to the thread-pool.&nbsp;&nbsp; Just a few though.
+
+<P>
+<HR WIDTH="100%">
+<BR><FONT FACE="Arial,Helvetica"></FONT>&nbsp;<FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">// $Id: client_handler.cpp,v 1.1 1998/08/30
+16:04:12 jcej Exp $</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">/*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; Since this is the third time
+we've seen most of this, I'm going to strip out almost</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; all of the comments that
+you've already seen.&nbsp; That way, you can concentrate on the</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; new items.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;*/</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">#include "client_acceptor.h"</FONT>
+<BR><FONT FACE="Arial,Helvetica">#include "client_handler.h"</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">/*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; We're going to be registering
+and unregistering a couple of times.&nbsp; To make sure that</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; we use the same flags every
+time, I've created these handy macros.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;*/</FONT>
+<BR><FONT FACE="Arial,Helvetica">#define REGISTER_MASK&nbsp;&nbsp;&nbsp;
+ACE_Event_Handler::READ_MASK</FONT>
+<BR><FONT FACE="Arial,Helvetica">#define REMOVE_MASK&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+(ACE_Event_Handler::READ_MASK | ACE_Event_Handler::DONT_CALL)</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">/*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; Our constructor still doesn't
+really do anything.&nbsp; We simply initialize the acceptor</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; pointer to "null" and get
+our current thread id.&nbsp; The static self() method of ACE_Thread</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; will return you a thread
+id native to your platform.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;*/</FONT>
+<BR><FONT FACE="Arial,Helvetica">Client_Handler::Client_Handler (void)</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;: client_acceptor_(0)</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp; ,creator_(ACE_Thread::self())</FONT>
+<BR><FONT FACE="Arial,Helvetica">{</FONT>
+<BR><FONT FACE="Arial,Helvetica">}</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">Client_Handler::~Client_Handler (void)</FONT>
+<BR><FONT FACE="Arial,Helvetica">{</FONT>
+<BR><FONT FACE="Arial,Helvetica">}</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">/*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; Query our acceptor for the
+concurrency strategy.&nbsp; Notice that we don't bother</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; to check that our acceptor
+pointer is valid.&nbsp; That is proably a bad idea...</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;*/</FONT>
+<BR><FONT FACE="Arial,Helvetica">int Client_Handler::concurrency(void)</FONT>
+<BR><FONT FACE="Arial,Helvetica">{</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+return this->client_acceptor()->concurrency();</FONT>
+<BR><FONT FACE="Arial,Helvetica">}</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">/*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; And here we ask the acceptor
+about the thread pool.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;*/</FONT>
+<BR><FONT FACE="Arial,Helvetica">Thread_Pool * Client_Handler::thread_pool(void)</FONT>
+<BR><FONT FACE="Arial,Helvetica">{</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+return this->client_acceptor()->thread_pool();</FONT>
+<BR><FONT FACE="Arial,Helvetica">}</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">/*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; The destroy() method hasn't
+changed since we wrote it back in Tutorial 5.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;*/</FONT>
+<BR><FONT FACE="Arial,Helvetica">void Client_Handler::destroy (void)</FONT>
+<BR><FONT FACE="Arial,Helvetica">{</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp; this->peer ().close ();</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">&nbsp; this->reactor ()->remove_handler
+(this, REMOVE_MASK );</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">&nbsp; delete this;</FONT>
+<BR><FONT FACE="Arial,Helvetica">}</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">/*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; Back to our open() method.&nbsp;
+This is straight out of Tutorial 6.&nbsp; There's</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; nothing additional here for
+the thread-pool implementation.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;*/</FONT>
+<BR><FONT FACE="Arial,Helvetica">int Client_Handler::open (void *_acceptor)</FONT>
+<BR><FONT FACE="Arial,Helvetica">{</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp; client_acceptor( (Client_Acceptor
+*) _acceptor );</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">&nbsp; if( concurrency() == Client_Acceptor::thread_per_connection_
+)</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp; {</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+return this->activate();</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp; }</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">&nbsp; this->reactor (client_acceptor()->reactor
+());</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">&nbsp; ACE_INET_Addr addr;</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">&nbsp; if (this->peer ().get_remote_addr
+(addr) == -1)</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp; {</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return
+-1;</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp; }</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">&nbsp; if (this->reactor ()->register_handler
+(this, REGISTER_MASK) == -1)</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp; {</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ACE_ERROR_RETURN
+((LM_ERROR, "(%P|%t) can't register with reactor\n"), -1);</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp; }</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">&nbsp; ACE_DEBUG ((LM_DEBUG, "(%P|%t) connected
+with %s\n", addr.get_host_name ()));</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">&nbsp; return 0;</FONT>
+<BR><FONT FACE="Arial,Helvetica">}</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">/*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; In the open() method, we
+registered with the reactor and requested to be</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; notified when there is data
+to be read.&nbsp; When the reactor sees that activity</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; it will invoke this handle_input()
+method on us.&nbsp; As I mentioned, the _handle</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; parameter isn't useful to
+us but it narrows the list of methods the reactor</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; has to worry about and the
+list of possible virtual functions we would have</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; to override.</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; You've read that much before...&nbsp;
+Now we have to do some extra stuff in case</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; we're using the thread-pool
+implementation.&nbsp; If we're called by our creator</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; thread then we must be in
+the reactor.&nbsp; In that case, we arrange to be put</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; into the thread pool.&nbsp;
+If we're not in the creator thread then we must be</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; in the thread pool and we
+can do some work.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;*/</FONT>
+<BR><FONT FACE="Arial,Helvetica">int Client_Handler::handle_input (ACE_HANDLE
+_handle)</FONT>
+<BR><FONT FACE="Arial,Helvetica">{</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp; ACE_UNUSED_ARG (_handle);</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">&nbsp; /*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; Check our strategy.&nbsp;
+If we're using the thread pool and we're in the creation</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+thread then we know we were called by the reactor.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; */</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp; if( concurrency() == Client_Acceptor::thread_pool_
+)</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp; {</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+if( ACE_Thread::self() == creator_ )</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+{</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+/*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Remove ourselves from the reactor and ask to be put into the thread pool's</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+queue of work.&nbsp; (You should be able to use suspend_handler() but I've
+had</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+problems with that.)</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+*/</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+this->reactor()->remove_handler( this, REMOVE_MASK );</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+return this->thread_pool()->enqueue(this);</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+}</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp; }</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">&nbsp; /*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; Any strategy
+other than thread-per-connection will eventually get here.&nbsp; If we're
+in the</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+single-threaded implementation or the thread-pool, we still have to pass
+this way.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; */</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">&nbsp; char buf[128];</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp; memset (buf, 0, sizeof (buf));</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">&nbsp; /*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; Invoke the process()
+method to do the work but save it's return value instead</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+of returning it immediately.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; */</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">&nbsp; int rval = this->process(buf,sizeof(buf));</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">&nbsp; /*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; Now, we look
+again to see if we're in the thread-pool implementation.&nbsp; If so then
+we</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+need to re-register ourselves with the reactor so that we can get more
+work when it</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+is available.&nbsp; (If suspend_handler() worked then we would use resume_handler()
+here.)</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; */</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp; if( concurrency() == Client_Acceptor::thread_pool_
+)</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp; {</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+if( rval != -1 )</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+{</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+this->reactor()->register_handler( this, REGISTER_MASK );</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+}</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp; }</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">&nbsp; /*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; Return the result
+of process()</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; */</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp; return(rval);</FONT>
+<BR><FONT FACE="Arial,Helvetica">}</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">int Client_Handler::handle_close (ACE_HANDLE
+_handle, ACE_Reactor_Mask _mask)</FONT>
+<BR><FONT FACE="Arial,Helvetica">{</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp; ACE_UNUSED_ARG (_handle);</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp; ACE_UNUSED_ARG (_mask);</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">&nbsp; this->destroy ();</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp; return 0;</FONT>
+<BR><FONT FACE="Arial,Helvetica">}</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">int Client_Handler::svc(void)</FONT>
+<BR><FONT FACE="Arial,Helvetica">{</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp; char buf[128];</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp; memset (buf, 0, sizeof (buf));</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">&nbsp; while( 1 )</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp; {</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; if( this->process(buf,sizeof(buf))
+== -1 )</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+{</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+return(-1);</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; }</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp; }</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">&nbsp; return(0);</FONT>
+<BR><FONT FACE="Arial,Helvetica">}</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">/*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; Once again, we see that the
+application-level logic has not been at all affected</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; by our choice of threading
+models.&nbsp; Of course, I'm not sharing data between threads</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; or anything.&nbsp; We'll
+leave locking issues for a later tutorial.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;*/</FONT>
+<BR><FONT FACE="Arial,Helvetica">int Client_Handler::process (char *_rdbuf,
+int _rdbuf_len)</FONT>
+<BR><FONT FACE="Arial,Helvetica">{</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp; switch (this->peer ().recv (_rdbuf,
+_rdbuf_len))</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp; {</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp; case -1:</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ACE_ERROR_RETURN
+((LM_ERROR, "(%P|%t) %p bad read\n", "client"), -1);</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp; case 0:</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ACE_ERROR_RETURN
+((LM_ERROR, "(%P|%t) closing daemon (fd = %d)\n", this->get_handle ()),
+-1);</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp; default:</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ACE_DEBUG
+((LM_DEBUG, "(%P|%t) from client: %s", _rdbuf));</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp; }</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">&nbsp; return 0;</FONT>
+<BR><FONT FACE="Arial,Helvetica">}</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P>
+<HR WIDTH="100%">
+
+<P>Ok, now we've gone and changed handle_input()&nbsp;so that it knows
+when to do work and when to enqueue itself.&nbsp; Beyond that, we're still
+about the same.
+
+<P>
+<HR WIDTH="100%">
+<CENTER>[<A HREF="..">Tutorial Index</A>] [<A HREF="page07.html">Continue
+This Tutorial</A>]</CENTER>
+
+</BODY>
+</HTML>
diff --git a/docs/tutorials/007/page07.html b/docs/tutorials/007/page07.html
new file mode 100644
index 00000000000..4c6905ebf33
--- /dev/null
+++ b/docs/tutorials/007/page07.html
@@ -0,0 +1,197 @@
+<HTML>
+<HEAD>
+ <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+ <META NAME="GENERATOR" CONTENT="Mozilla/4.04 [en] (X11; I; Linux 2.0.32 i486) [Netscape]">
+ <META NAME="Author" CONTENT="James CE Johnson">
+ <META NAME="Description" CONTENT="A first step towards using ACE productively">
+ <TITLE>ACE Tutorial 007</TITLE>
+</HEAD>
+<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F">
+
+<CENTER><B><FONT SIZE=+2>ACE Tutorial 007</FONT></B></CENTER>
+
+<CENTER><B><FONT SIZE=+2>Creating a thread-pool server</FONT></B></CENTER>
+
+
+<P>
+<HR WIDTH="100%">
+
+<P>Two new files this time.&nbsp; The first is <A HREF="thread_pool.h">thread_pool.h</A>
+where we declare our Thread_Pool object.&nbsp; This is responsible for
+abstracting away the thread pool implementation details and allowing us
+to make so few changes to the rest of the code.
+
+<P>
+<HR WIDTH="100%"><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">// $Id: thread_pool.h,v 1.1 1998/08/30
+16:04:12 jcej Exp $</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">#ifndef THREAD_POOL_H</FONT>
+<BR><FONT FACE="Arial,Helvetica">#define THREAD_POOL_H</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">/*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; In order to implement a thread
+pool, we have to have an object that can create</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; a thread.&nbsp; The ACE_Task&lt;>
+is the basis for doing just such a thing.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;*/</FONT>
+<BR><FONT FACE="Arial,Helvetica">#include "ace/Task.h"</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">/*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; We need a forward reference
+for ACE_Event_Handler so that our enqueue() method</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; can accept a pointer to one.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;*/</FONT>
+<BR><FONT FACE="Arial,Helvetica">class ACE_Event_Handler;</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">/*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; Although we modified the
+rest of our program to make use of the thread pool</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; implementation, if you look
+closely you'll see that the changes were rather</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; minor.&nbsp; The "ACE way"
+is generally to create a helper object that abstracts</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; away the details not relevant
+to your application.&nbsp; That's what I'm trying</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; to do here by creating the
+Thread_Pool object.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;*/</FONT>
+<BR><FONT FACE="Arial,Helvetica">class Thread_Pool : public ACE_Task&lt;ACE_MT_SYNCH></FONT>
+<BR><FONT FACE="Arial,Helvetica">{</FONT>
+<BR><FONT FACE="Arial,Helvetica">public:</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+/*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Provide an enumeration for the default pool size.&nbsp; By doing this,
+other objects</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+can use the value when they want a default.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+*/</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+enum size_t</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+{</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+default_pool_size_ = 5</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+};</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+// Basic constructor</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Thread_Pool(void);</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+/*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Opening the thread pool causes one or more threads to be activated.&nbsp;
+When activated,</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+they all execute the svc() method declared below.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+*/</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+int open( int _pool_size = default_pool_size_ );</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+/*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+When you're done wit the thread pool, you have to have some way to shut
+it down.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+This is what close() is for.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+*/</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+int close(void);</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+/*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+To use the thread pool, you have to put some unit of work into it.&nbsp;
+Since we're</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+dealing with event handlers (or at least their derivatives), I've chosen
+to provide</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+an enqueue() method that takes a pointer to an ACE_Event_Handler.&nbsp;
+The handler's</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+handle_input() method will be called, so your object has to know when it
+is being</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+called by the thread pool.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+*/</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+int enqueue( ACE_Event_Handler * _handler );</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">protected:</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+/*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Our svc() method will dequeue the enqueued event handler objects and invoke
+the</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+handle_input() method on each.&nbsp; Since we're likely running in more
+than one thread,</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+idle threads can take work from the queue while other threads are busy
+executing</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+handle_input() on some object.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+*/</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+int svc(void);</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+/*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Another handy ACE template is ACE_Atomic_Op&lt;>.&nbsp; When parameterized,
+this allows</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+is to have a thread-safe counting object.&nbsp; The typical arithmetic
+operators are</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+all internally thread-safe so that you can share it across threads without
+worrying</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+about any contention issues.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+*/</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+typedef ACE_Atomic_Op&lt;ACE_Mutex,int> counter_t;</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+/*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+We use the atomic op to keep a count of the number of threads in which
+our svc()</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+method is running.&nbsp; This is particularly important when we want to
+close() it down!</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+*/</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+counter_t active_threads_;</FONT>
+<BR><FONT FACE="Arial,Helvetica">};</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">#endif // THREAD_POOL_H</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P>
+<HR WIDTH="100%">
+
+<P>Well, that doesn't look too complex.&nbsp; What about the implementation?
+
+<P>
+<HR WIDTH="100%">
+<CENTER>[<A HREF="..">Tutorial Index</A>] [<A HREF="page08.html">Continue
+This Tutorial</A>]</CENTER>
+
+</BODY>
+</HTML>
diff --git a/docs/tutorials/007/page08.html b/docs/tutorials/007/page08.html
new file mode 100644
index 00000000000..5c3ede6e8ab
--- /dev/null
+++ b/docs/tutorials/007/page08.html
@@ -0,0 +1,509 @@
+<HTML>
+<HEAD>
+ <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+ <META NAME="GENERATOR" CONTENT="Mozilla/4.04 [en] (X11; I; Linux 2.0.32 i486) [Netscape]">
+ <META NAME="Author" CONTENT="James CE Johnson">
+ <META NAME="Description" CONTENT="A first step towards using ACE productively">
+ <TITLE>ACE Tutorial 007</TITLE>
+</HEAD>
+<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F">
+
+<CENTER><B><FONT SIZE=+2>ACE Tutorial 007</FONT></B></CENTER>
+
+<CENTER><B><FONT SIZE=+2>Creating a thread-pool server</FONT></B></CENTER>
+
+
+<P>
+<HR WIDTH="100%">
+
+<P>Finally, <A HREF="thread_pool.cpp">thread_pool.cpp</A> where we have
+the Thread_Pool object implementation.
+
+<P>
+<HR WIDTH="100%"><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">// $Id: thread_pool.cpp,v 1.1 1998/08/30
+16:04:12 jcej Exp $</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">#include "thread_pool.h"</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">/*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; We need this header so that
+we can invoke handle_input() on the objects we dequeue.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;*/</FONT>
+<BR><FONT FACE="Arial,Helvetica">#include "ace/Event_Handler.h"</FONT>
+<BR><FONT FACE="Arial,Helvetica"></FONT>&nbsp;<FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">/*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; All we do here is initialize
+our active thread counter.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;*/</FONT>
+<BR><FONT FACE="Arial,Helvetica">Thread_Pool::Thread_Pool(void)</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;: active_threads_(0)</FONT>
+<BR><FONT FACE="Arial,Helvetica">{</FONT>
+<BR><FONT FACE="Arial,Helvetica">}</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">/*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; Our open() method is a thin
+disguise around the ACE_Task&lt;> activate() method.&nbsp; By</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; hiding activate() in this
+way, the users of Thread_Pool don't have to worry about</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; the thread configuration
+flags.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;*/</FONT>
+<BR><FONT FACE="Arial,Helvetica">int Thread_Pool::open( int _pool_size
+)</FONT>
+<BR><FONT FACE="Arial,Helvetica">{</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp; return this->activate(THR_NEW_LWP|THR_DETACHED,_pool_size);</FONT>
+<BR><FONT FACE="Arial,Helvetica">}</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">/*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; Closing the thread pool can
+be a tricky exercise.&nbsp; I've decided to take an easy approach</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; and simply enqueue a secret
+message for each thread we have active.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;*/</FONT>
+<BR><FONT FACE="Arial,Helvetica">int Thread_Pool::close(void)</FONT>
+<BR><FONT FACE="Arial,Helvetica">{</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+/*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Find out how many threads are currently active</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+*/</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+int counter = active_threads_.value();</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+/*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+For each one of the active threads, enqueue a "null" event handler.&nbsp;
+Below, we'll</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+teach our svc() method that "null" means "shutdown".</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+*/</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+while( counter-- )</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+{</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+this->enqueue( 0 );</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+}</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+/*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+As each svc() method exits, it will decrement the active thread counter.&nbsp;
+We just wait</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+here for it to reach zero.&nbsp; Since we don't know how long it will take,
+we sleep for</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+a quarter-second or so between tries.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+*/</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+while( active_threads_.value() )</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+{</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ACE_OS::sleep( ACE_Time_Value(0.25) );</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+}</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+return(0);</FONT>
+<BR><FONT FACE="Arial,Helvetica">}</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">/*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; When an object wants to do
+work in the pool, it should call the enqueue() method.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; We introduce the ACE_Message_Block
+here but, unfortunately, we seriously missuse it.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;*/</FONT>
+<BR><FONT FACE="Arial,Helvetica">int Thread_Pool::enqueue( ACE_Event_Handler
+* _handler )</FONT>
+<BR><FONT FACE="Arial,Helvetica">{</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+/*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+An ACE_Message_Block is a chunk of data.&nbsp; You put them into an ACE_Message_Queue.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ACE_Task&lt;> has an ACE_Message_Queue built in.&nbsp; In fact, the parameter
+to ACE_Task&lt;></FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+is passed directly to ACE_Message_Queue.&nbsp; If you look back at our
+header file you'll</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+see that we used ACE_MT_SYNCH as the parameter indicating that we want
+MultiThread</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Synch safety.&nbsp; This allows us to safely put ACE_Message_Block objects
+into the</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+message queue in one thread and take them out in another.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+*/</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+/*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+An ACE_Message_Block wants to have char* data.&nbsp; We don't have that.&nbsp;
+We could</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+cast our ACE_Event_Handler* directly to a char* but I wanted to be more
+explicit.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Since casting pointers around is a dangerous thing, I've gone out of my
+way here</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+to be very clear about what we're doing.</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+First:&nbsp; Cast the handler pointer to a void pointer.&nbsp; You can't
+do any useful work</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+on a void pointer, so this is a clear message that we're making the</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+pointer unusable.</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Next:&nbsp;&nbsp; Cast the void pointer to a char pointer that the ACE_Message_Block
+will accept.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+*/</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+void * v_data = (void*)_handler;</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+char * c_data = (char*)v_data;</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+/*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Construct a new ACE_Message_Block.&nbsp; For efficiency, you might want
+to preallocate a</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+stack of these and reuse them.&nbsp; For simplicity, I'll just create what
+I need as I need it.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+*/</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ACE_Message_Block * mb = new ACE_Message_Block( c_data );</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+/*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Our putq() method is a wrapper around one of the enqueue methods of the
+ACE_Message_Queue</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+that we own.&nbsp; Like all good methods, it returns -1 if it fails for
+some reason.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+*/</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+if( this->putq(mb) == -1 )</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+{</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+/*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Another trait of the ACE_Message_Block objects is that they are reference
+counted.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Since they're designed to be passed around between various objects in several
+threads</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+we can't just delete them whenever we feel like it.&nbsp; The release()
+method is similar</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+to the destroy() method we've used elsewhere.&nbsp; It watches the reference
+count and will</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+delete the object when possible.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+*/</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+mb->release();</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+return(-1);</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+}</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+return(0);</FONT>
+<BR><FONT FACE="Arial,Helvetica">}</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">/*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; The "guard" concept is very
+powerful and used throughout multi-threaded applications.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; A guard normally does some
+operation on an object at construction and the "opposite"</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; operation at destruction.&nbsp;
+For instance, when you guard a mutex (lock) object, the guard</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; will acquire the lock on
+construction and release it on destruction.&nbsp; In this way, your</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; method can simply let the
+guard go out of scope and know that the lock is released.</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; Guards aren't only useful
+for locks however.&nbsp; In this application I've created two guard</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; objects for quite a different
+purpose.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;*/</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">/*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; The Counter_Guard is constructed
+with a reference to the thread pool's active thread</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; counter.&nbsp; The guard
+increments the counter when it is created and decrements it at</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; destruction.&nbsp; By creating
+one of these in svc(), I know that the counter will be decremented</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; no matter how or where svc()
+returns.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;*/</FONT>
+<BR><FONT FACE="Arial,Helvetica">class Counter_Guard</FONT>
+<BR><FONT FACE="Arial,Helvetica">{</FONT>
+<BR><FONT FACE="Arial,Helvetica">public:</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Counter_Guard( Thread_Pool::counter_t &amp; _counter )</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+: counter_(_counter)</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+{</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+++counter_;</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+}</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+~Counter_Guard(void)</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+{</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+--counter_;</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+}</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">protected:</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Thread_Pool::counter_t &amp; counter_;</FONT>
+<BR><FONT FACE="Arial,Helvetica">};</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">/*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; My Message_Block_Guard is
+also a little non-traditional.&nbsp; It doesn't do anything in the</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; constructor but it's destructor
+ensures that the message block's release() method is called.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; This is a cheap way to prevent
+a memory leak if I need an additional exit point in svc().</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;*/</FONT>
+<BR><FONT FACE="Arial,Helvetica">class Message_Block_Guard</FONT>
+<BR><FONT FACE="Arial,Helvetica">{</FONT>
+<BR><FONT FACE="Arial,Helvetica">public:</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Message_Block_Guard( ACE_Message_Block * &amp; _mb )</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+: mb_(_mb)</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+{</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+}</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+~Message_Block_Guard( void )</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+{</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+mb_->release();</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+}</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">protected:</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ACE_Message_Block * &amp; mb_;</FONT>
+<BR><FONT FACE="Arial,Helvetica">};</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">/*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; Now we come to the svc()
+method.&nbsp; As I said, this is being executed in each thread of the</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; Thread_Pool.&nbsp; Here,
+we pull messages off of our built-in ACE_Message_Queue and cause them</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; to do work.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;*/</FONT>
+<BR><FONT FACE="Arial,Helvetica">int Thread_Pool::svc(void)</FONT>
+<BR><FONT FACE="Arial,Helvetica">{</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+/*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+The getq() method takes a reference to a pointer.&nbsp; So... we need a
+pointer to give it</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+a reference to.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+*/</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ACE_Message_Block * mb;</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+/*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Create the guard for our active thread counter object.&nbsp; No matter
+where we choose to</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+return() from svc(), we no know that the counter will be decremented.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+*/</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Counter_Guard counter_guard(active_threads_);</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+/*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Get messages from the queue until we have a failure.&nbsp; There's no real
+good reason</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+for failure so if it happens, we leave immediately.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+*/</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+while( this->getq(mb) != -1 )</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+{</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+/*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+A successful getq() will cause "mb" to point to a valid refernce-counted</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ACE_Message_Block.&nbsp; We use our guard object here so that we're sure
+to call</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+the release() method of that message block and reduce it's reference count.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Once the count reaches zero, it will be deleted.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+*/</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Message_Block_Guard message_block_guard(mb);</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+/*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+As noted before, the ACE_Message_Block stores it's data as a char*.&nbsp;
+We pull that</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+out here and later turn it into an ACE_Event_Handler*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+*/</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+char * c_data = mb->base();</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+/*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+We've chosen to use a "null" value as an indication to leave.&nbsp; If
+the data we got</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+from the queue is not null then we have some work to do.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+*/</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+if( c_data )</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+{</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+/*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Once again, we go to great lengths to emphasize the fact that we're casting
+pointers</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+around in rather impolite ways.&nbsp; We could have cast the char* directly
+to an</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ACE_Event_Handler* but then folks might think that's an OK thing to do.</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+(Note:&nbsp; The correct way to use an ACE_Message_Block is to write data
+into it.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+What I should have done was create a message block big enough to hold an</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+event handler pointer and then written the pointer value into the block.&nbsp;
+When</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+we got here, I would have to read that data back into a pointer.&nbsp;
+While politically</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+correct, it is also a lot of work.&nbsp; If you're careful you can get
+away with casting</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+pointers around.)</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+*/</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+void * v_data = (void*)c_data;</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ACE_Event_Handler * handler = (ACE_Event_Handler*)v_data;</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+/*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Now that we finally have an event handler pointer, invoke it's handle_input()
+method.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Since we don't know it's handle, we just give it a default.&nbsp; That's
+OK because we</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+know that we're not using the handle in the method anyway.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+*/</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+if( handler->handle_input(ACE_INVALID_HANDLE) == -1 )</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+{</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+return(-1);&nbsp;&nbsp; // Error, return now</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+}</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+}</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+else</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+{</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+/*</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+If we get here, we were given a message block with "null" data.&nbsp; That
+is our</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+signal to leave, so we return(0) to leave gracefully.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+*/</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+return(0);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+// Ok, shutdown request</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+}</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+// message_block_guard goes out of scope here</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+// and releases the message_block instance.</FONT>
+<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+}</FONT><FONT FACE="Arial,Helvetica"></FONT>
+
+<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+return(0);</FONT>
+<BR><FONT FACE="Arial,Helvetica">}</FONT>
+<BR><FONT FACE="Arial,Helvetica"></FONT>&nbsp;<FONT FACE="Arial,Helvetica"></FONT>
+
+<P>
+<HR WIDTH="100%">
+<CENTER>[<A HREF="..">Tutorial Index</A>] [<A HREF="page09.html">Continue
+This Tutorial</A>]</CENTER>
+
+</BODY>
+</HTML>
diff --git a/docs/tutorials/007/page09.html b/docs/tutorials/007/page09.html
new file mode 100644
index 00000000000..5023e761eec
--- /dev/null
+++ b/docs/tutorials/007/page09.html
@@ -0,0 +1,64 @@
+<HTML>
+<HEAD>
+ <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+ <META NAME="GENERATOR" CONTENT="Mozilla/4.04 [en] (X11; I; Linux 2.0.32 i486) [Netscape]">
+ <META NAME="Author" CONTENT="James CE Johnson">
+ <META NAME="Description" CONTENT="A first step towards using ACE productively">
+ <TITLE>ACE Tutorial 006</TITLE>
+</HEAD>
+<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F">
+
+<CENTER><B><FONT SIZE=+2>ACE Tutorial 007</FONT></B></CENTER>
+
+<CENTER><B><FONT SIZE=+2>Creating a thread-pool server</FONT></B></CENTER>
+
+<HR WIDTH="100%">
+
+<P>That's it for Tutorial 7.&nbsp; As with Tutorial 6, we really didn't
+have to change much to introduce a new threading strategy.&nbsp; Most of
+the work was in creating the Thread_Pool object itself.&nbsp; Everything
+else was just minor housekeeping.
+
+<P>There is a fourth common thread strategy:&nbsp; thread-per-request.&nbsp;
+It's not one of my favorites, so I wasn't planning to go into it.&nbsp;
+If you want to contribute a tutorial on that topic though, I'll be glad
+to include it here.
+
+<P>For reference, here's the file list again:
+<UL>
+<LI>
+<A HREF="Makefile">Makefile</A></LI>
+
+<LI>
+<A HREF="client_acceptor.h">client_acceptor.h</A></LI>
+
+<LI>
+<A HREF="client_acceptor.cpp">client_acceptor.cpp</A></LI>
+
+<LI>
+<A HREF="client_handler.cpp">client_handler.cpp</A></LI>
+
+<LI>
+<A HREF="client_handler.h">client_handler.h</A></LI>
+
+<LI>
+<A HREF="server.cpp">server.cpp</A></LI>
+
+<LI>
+<A HREF="thread_pool.h">thread_pool.h</A></LI>
+
+<LI>
+<A HREF="thread_pool.cpp">thread_poo.cpp</A></LI>
+
+<LI>
+<A HREF="fix.Makefile">fix.Makefile</A></LI>
+</UL>
+&nbsp;
+
+<P>
+<HR WIDTH="100%">
+<CENTER>[<A HREF="..">Tutorial
+Index</A>]</CENTER>
+
+</BODY>
+</HTML>
diff --git a/docs/tutorials/007/server.cpp b/docs/tutorials/007/server.cpp
new file mode 100644
index 00000000000..14ef85c44d1
--- /dev/null
+++ b/docs/tutorials/007/server.cpp
@@ -0,0 +1,107 @@
+// $Id$
+
+/*
+ We try to keep main() very simple. One of the ways we do that is to push
+ much of the complicated stuff into worker objects. In this case, we only
+ need to include the acceptor header in our main source file. We let it
+ worry about the "real work".
+ */
+
+#include "client_acceptor.h"
+
+/*
+ As before, we create a simple signal handler that will set our finished
+ flag. There are, of course, more elegant ways to handle program shutdown
+ requests but that isn't really our focus right now, so we'll just do the
+ easiest thing.
+ */
+
+static sig_atomic_t finished = 0;
+extern "C" void handler (int)
+{
+ finished = 1;
+}
+
+/*
+ A server has to listen for clients at a known TCP/IP port. The default ACE
+ port is 10002 (at least on my system) and that's good enough for what we
+ want to do here. Obviously, a more robust application would take a command
+ line parameter or read from a configuration file or do some other clever
+ thing. Just like the signal handler above, though, that's what we want to
+ focus on, so we're taking the easy way out.
+ */
+
+static const u_short PORT = ACE_DEFAULT_SERVER_PORT;
+
+/*
+ Finally, we get to main. Some C++ compilers will complain loudly if your
+ function signature doesn't match the prototype. Even though we're not
+ going to use the parameters, we still have to specify them.
+ */
+
+int main (int argc, char *argv[])
+{
+/*
+ In our earlier servers, we used a global pointer to get to the reactor. I've
+ never really liked that idea, so I've moved it into main() this time. When
+ we get to the Client_Handler object you'll see how we manage to get a
+ pointer back to this reactor.
+ */
+ ACE_Reactor reactor;
+
+ /*
+ The acceptor will take care of letting clients connect to us. It will
+ also arrange for a Client_Handler to be created for each new client.
+ Since we're only going to listen at one TCP/IP port, we only need one
+ acceptor. If we wanted, though, we could create several of these and
+ listen at several ports. (That's what we would do if we wanted to rewrite
+ inetd for instance.)
+ */
+ Client_Acceptor peer_acceptor;
+
+ /*
+ Create an ACE_INET_Addr that represents our endpoint of a connection. We
+ then open our acceptor object with that Addr. Doing so tells the acceptor
+ where to listen for connections. Servers generally listen at "well known"
+ addresses. If not, there must be some mechanism by which the client is
+ informed of the server's address.
+
+ Note how ACE_ERROR_RETURN is used if we fail to open the acceptor. This
+ technique is used over and over again in our tutorials.
+ */
+ if (peer_acceptor.open (ACE_INET_Addr (PORT), &reactor) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "open"), -1);
+
+ /*
+ Install our signal handler. You can actually register signal handlers
+ with the reactor. You might do that when the signal handler is
+ responsible for performing "real" work. Our simple flag-setter doesn't
+ justify deriving from ACE_Event_Handler and providing a callback function
+ though.
+ */
+ ACE_Sig_Action sa ((ACE_SignalHandler) handler, SIGINT);
+
+ /*
+ Like ACE_ERROR_RETURN, the ACE_DEBUG macro gets used quite a bit. It's a
+ handy way to generate uniform debug output from your program.
+ */
+ ACE_DEBUG ((LM_DEBUG, "(%P|%t) starting up server daemon\n"));
+
+ /*
+ This will loop "forever" invoking the handle_events() method of our
+ reactor. handle_events() watches for activity on any registered handlers
+ and invokes their appropriate callbacks when necessary. Callback-driven
+ programming is a big thing in ACE, you should get used to it. If the
+ signal handler catches something, the finished flag will be set and we'll
+ exit. Conveniently enough, handle_events() is also interrupted by signals
+ and will exit back to the while() loop. (If you want your event loop to
+ not be interrupted by signals, checkout the <i>restart</i> flag on the
+ open() method of ACE_Reactor if you're interested.)
+ */
+ while (!finished)
+ reactor.handle_events ();
+
+ ACE_DEBUG ((LM_DEBUG, "(%P|%t) shutting down server daemon\n"));
+
+ return 0;
+}
diff --git a/docs/tutorials/007/thread_pool.cpp b/docs/tutorials/007/thread_pool.cpp
new file mode 100644
index 00000000000..dc2ff7f2a39
--- /dev/null
+++ b/docs/tutorials/007/thread_pool.cpp
@@ -0,0 +1,262 @@
+
+// $Id$
+
+#include "thread_pool.h"
+
+/*
+ We need this header so that we can invoke handle_input() on the objects we dequeue.
+ */
+#include "ace/Event_Handler.h"
+
+
+/*
+ All we do here is initialize our active thread counter.
+ */
+Thread_Pool::Thread_Pool(void)
+ : active_threads_(0)
+{
+}
+
+/*
+ Our open() method is a thin disguise around the ACE_Task<> activate() method. By
+ hiding activate() in this way, the users of Thread_Pool don't have to worry about
+ the thread configuration flags.
+ */
+int Thread_Pool::open( int _pool_size )
+{
+ return this->activate(THR_NEW_LWP|THR_DETACHED,_pool_size);
+}
+
+/*
+ Closing the thread pool can be a tricky exercise. I've decided to take an easy approach
+ and simply enqueue a secret message for each thread we have active.
+ */
+int Thread_Pool::close(void)
+{
+ /*
+ Find out how many threads are currently active
+ */
+ int counter = active_threads_.value();
+
+ /*
+ For each one of the active threads, enqueue a "null" event handler. Below, we'll
+ teach our svc() method that "null" means "shutdown".
+ */
+ while( counter-- )
+ {
+ this->enqueue( 0 );
+ }
+
+ /*
+ As each svc() method exits, it will decrement the active thread counter. We just wait
+ here for it to reach zero. Since we don't know how long it will take, we sleep for
+ a quarter-second or so between tries.
+ */
+ while( active_threads_.value() )
+ {
+ ACE_OS::sleep( ACE_Time_Value(0.25) );
+ }
+
+ return(0);
+}
+
+/*
+ When an object wants to do work in the pool, it should call the enqueue() method.
+ We introduce the ACE_Message_Block here but, unfortunately, we seriously missuse it.
+ */
+int Thread_Pool::enqueue( ACE_Event_Handler * _handler )
+{
+ /*
+ An ACE_Message_Block is a chunk of data. You put them into an ACE_Message_Queue.
+ ACE_Task<> has an ACE_Message_Queue built in. In fact, the parameter to ACE_Task<>
+ is passed directly to ACE_Message_Queue. If you look back at our header file you'll
+ see that we used ACE_MT_SYNCH as the parameter indicating that we want MultiThread
+ Synch safety. This allows us to safely put ACE_Message_Block objects into the
+ message queue in one thread and take them out in another.
+ */
+
+ /*
+ An ACE_Message_Block wants to have char* data. We don't have that. We could
+ cast our ACE_Event_Handler* directly to a char* but I wanted to be more explicit.
+ Since casting pointers around is a dangerous thing, I've gone out of my way here
+ to be very clear about what we're doing.
+
+ First: Cast the handler pointer to a void pointer. You can't do any useful work
+ on a void pointer, so this is a clear message that we're making the
+ pointer unusable.
+
+ Next: Cast the void pointer to a char pointer that the ACE_Message_Block will accept.
+ */
+ void * v_data = (void*)_handler;
+ char * c_data = (char*)v_data;
+
+ /*
+ Construct a new ACE_Message_Block. For efficiency, you might want to preallocate a
+ stack of these and reuse them. For simplicity, I'll just create what I need as I need it.
+ */
+ ACE_Message_Block * mb = new ACE_Message_Block( c_data );
+
+ /*
+ Our putq() method is a wrapper around one of the enqueue methods of the ACE_Message_Queue
+ that we own. Like all good methods, it returns -1 if it fails for some reason.
+ */
+ if( this->putq(mb) == -1 )
+ {
+ /*
+ Another trait of the ACE_Message_Block objects is that they are reference counted.
+ Since they're designed to be passed around between various objects in several threads
+ we can't just delete them whenever we feel like it. The release() method is similar
+ to the destroy() method we've used elsewhere. It watches the reference count and will
+ delete the object when possible.
+ */
+ mb->release();
+ return(-1);
+ }
+
+ return(0);
+}
+
+/*
+ The "guard" concept is very powerful and used throughout multi-threaded applications.
+ A guard normally does some operation on an object at construction and the "opposite"
+ operation at destruction. For instance, when you guard a mutex (lock) object, the guard
+ will acquire the lock on construction and release it on destruction. In this way, your
+ method can simply let the guard go out of scope and know that the lock is released.
+
+ Guards aren't only useful for locks however. In this application I've created two guard
+ objects for quite a different purpose.
+ */
+
+/*
+ The Counter_Guard is constructed with a reference to the thread pool's active thread
+ counter. The guard increments the counter when it is created and decrements it at
+ destruction. By creating one of these in svc(), I know that the counter will be decremented
+ no matter how or where svc() returns.
+ */
+class Counter_Guard
+{
+public:
+ Counter_Guard( Thread_Pool::counter_t & _counter )
+ : counter_(_counter)
+ {
+ ++counter_;
+ }
+
+ ~Counter_Guard(void)
+ {
+ --counter_;
+ }
+
+protected:
+ Thread_Pool::counter_t & counter_;
+};
+
+/*
+ My Message_Block_Guard is also a little non-traditional. It doesn't do anything in the
+ constructor but it's destructor ensures that the message block's release() method is called.
+ This is a cheap way to prevent a memory leak if I need an additional exit point in svc().
+ */
+class Message_Block_Guard
+{
+public:
+ Message_Block_Guard( ACE_Message_Block * & _mb )
+ : mb_(_mb)
+ {
+ }
+
+ ~Message_Block_Guard( void )
+ {
+ mb_->release();
+ }
+
+protected:
+ ACE_Message_Block * & mb_;
+};
+
+/*
+ Now we come to the svc() method. As I said, this is being executed in each thread of the
+ Thread_Pool. Here, we pull messages off of our built-in ACE_Message_Queue and cause them
+ to do work.
+ */
+int Thread_Pool::svc(void)
+{
+ /*
+ The getq() method takes a reference to a pointer. So... we need a pointer to give it
+ a reference to.
+ */
+ ACE_Message_Block * mb;
+
+ /*
+ Create the guard for our active thread counter object. No matter where we choose to
+ return() from svc(), we no know that the counter will be decremented.
+ */
+ Counter_Guard counter_guard(active_threads_);
+
+ /*
+ Get messages from the queue until we have a failure. There's no real good reason
+ for failure so if it happens, we leave immediately.
+ */
+ while( this->getq(mb) != -1 )
+ {
+ /*
+ A successful getq() will cause "mb" to point to a valid refernce-counted
+ ACE_Message_Block. We use our guard object here so that we're sure to call
+ the release() method of that message block and reduce it's reference count.
+ Once the count reaches zero, it will be deleted.
+ */
+ Message_Block_Guard message_block_guard(mb);
+
+ /*
+ As noted before, the ACE_Message_Block stores it's data as a char*. We pull that
+ out here and later turn it into an ACE_Event_Handler*
+ */
+ char * c_data = mb->base();
+
+ /*
+ We've chosen to use a "null" value as an indication to leave. If the data we got
+ from the queue is not null then we have some work to do.
+ */
+ if( c_data )
+ {
+ /*
+ Once again, we go to great lengths to emphasize the fact that we're casting pointers
+ around in rather impolite ways. We could have cast the char* directly to an
+ ACE_Event_Handler* but then folks might think that's an OK thing to do.
+
+ (Note: The correct way to use an ACE_Message_Block is to write data into it.
+ What I should have done was create a message block big enough to hold an
+ event handler pointer and then written the pointer value into the block. When
+ we got here, I would have to read that data back into a pointer. While politically
+ correct, it is also a lot of work. If you're careful you can get away with casting
+ pointers around.)
+ */
+ void * v_data = (void*)c_data;
+
+ ACE_Event_Handler * handler = (ACE_Event_Handler*)v_data;
+
+ /*
+ Now that we finally have an event handler pointer, invoke it's handle_input() method.
+ Since we don't know it's handle, we just give it a default. That's OK because we
+ know that we're not using the handle in the method anyway.
+ */
+ if( handler->handle_input(ACE_INVALID_HANDLE) == -1 )
+ {
+ return(-1); // Error, return now
+ }
+ }
+ else
+ {
+ /*
+ If we get here, we were given a message block with "null" data. That is our
+ signal to leave, so we return(0) to leave gracefully.
+ */
+ return(0); // Ok, shutdown request
+ }
+
+ // message_block_guard goes out of scope here
+ // and releases the message_block instance.
+ }
+
+ return(0);
+}
+
diff --git a/docs/tutorials/007/thread_pool.h b/docs/tutorials/007/thread_pool.h
new file mode 100644
index 00000000000..5fae81fae72
--- /dev/null
+++ b/docs/tutorials/007/thread_pool.h
@@ -0,0 +1,88 @@
+
+// $Id$
+
+#ifndef THREAD_POOL_H
+#define THREAD_POOL_H
+
+/*
+ In order to implement a thread pool, we have to have an object that can create
+ a thread. The ACE_Task<> is the basis for doing just such a thing.
+ */
+#include "ace/Task.h"
+
+/*
+ We need a forward reference for ACE_Event_Handler so that our enqueue() method
+ can accept a pointer to one.
+ */
+class ACE_Event_Handler;
+
+/*
+ Although we modified the rest of our program to make use of the thread pool
+ implementation, if you look closely you'll see that the changes were rather
+ minor. The "ACE way" is generally to create a helper object that abstracts
+ away the details not relevant to your application. That's what I'm trying
+ to do here by creating the Thread_Pool object.
+ */
+class Thread_Pool : public ACE_Task<ACE_MT_SYNCH>
+{
+public:
+
+ /*
+ Provide an enumeration for the default pool size. By doing this, other objects
+ can use the value when they want a default.
+ */
+ enum size_t
+ {
+ default_pool_size_ = 5
+ };
+
+ // Basic constructor
+ Thread_Pool(void);
+
+ /*
+ Opening the thread pool causes one or more threads to be activated. When activated,
+ they all execute the svc() method declared below.
+ */
+ int open( int _pool_size = default_pool_size_ );
+
+ /*
+ When you're done wit the thread pool, you have to have some way to shut it down.
+ This is what close() is for.
+ */
+ int close(void);
+
+ /*
+ To use the thread pool, you have to put some unit of work into it. Since we're
+ dealing with event handlers (or at least their derivatives), I've chosen to provide
+ an enqueue() method that takes a pointer to an ACE_Event_Handler. The handler's
+ handle_input() method will be called, so your object has to know when it is being
+ called by the thread pool.
+ */
+ int enqueue( ACE_Event_Handler * _handler );
+
+protected:
+
+ /*
+ Our svc() method will dequeue the enqueued event handler objects and invoke the
+ handle_input() method on each. Since we're likely running in more than one thread,
+ idle threads can take work from the queue while other threads are busy executing
+ handle_input() on some object.
+ */
+ int svc(void);
+
+ /*
+ Another handy ACE template is ACE_Atomic_Op<>. When parameterized, this allows
+ is to have a thread-safe counting object. The typical arithmetic operators are
+ all internally thread-safe so that you can share it across threads without worrying
+ about any contention issues.
+ */
+ typedef ACE_Atomic_Op<ACE_Mutex,int> counter_t;
+
+ /*
+ We use the atomic op to keep a count of the number of threads in which our svc()
+ method is running. This is particularly important when we want to close() it down!
+ */
+ counter_t active_threads_;
+};
+
+#endif // THREAD_POOL_H