diff options
Diffstat (limited to 'docs/tutorials')
164 files changed, 0 insertions, 18632 deletions
diff --git a/docs/tutorials/001/00SetEnv b/docs/tutorials/001/00SetEnv deleted file mode 100644 index eca78e10c85..00000000000 --- a/docs/tutorials/001/00SetEnv +++ /dev/null @@ -1,2 +0,0 @@ -export ACE_ROOT=/local/src/ACE/ACE_wrappers -export LD_LIBRARY_PATH=$ACE_ROOT/ace:$LD_LIBRARY_PATH diff --git a/docs/tutorials/001/Makefile b/docs/tutorials/001/Makefile deleted file mode 100644 index 8a1d6069d48..00000000000 --- a/docs/tutorials/001/Makefile +++ /dev/null @@ -1,46 +0,0 @@ -#---------------------------------------------------------------------------- -# $Id$ -# -# Makefile for the Reactor Server Logging Daemon -#---------------------------------------------------------------------------- - -#---------------------------------------------------------------------------- -# Local macros -#---------------------------------------------------------------------------- - -BIN = server - -FILES = - -LSRC = $(addsuffix .cpp,$(FILES)) -LOBJ = $(addsuffix .o,$(FILES)) -SHOBJ = $(addsuffix .so,$(FILES)) - -LDLIBS = $(addprefix .shobj/,$(SHOBJ)) - -VLDLIBS = $(LDLIBS:%=%$(VAR)) - -BUILD = $(VBIN) - -#---------------------------------------------------------------------------- -# Include macros and targets -#---------------------------------------------------------------------------- - -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 -#---------------------------------------------------------------------------- - -#---------------------------------------------------------------------------- -# Dependencies -#---------------------------------------------------------------------------- - -.obj/server.o .shobj/server.so: server.cpp acceptor.h logger.h - diff --git a/docs/tutorials/001/Source.tgz b/docs/tutorials/001/Source.tgz Binary files differdeleted file mode 100644 index 5f7392a7fc8..00000000000 --- a/docs/tutorials/001/Source.tgz +++ /dev/null diff --git a/docs/tutorials/001/acceptor.h b/docs/tutorials/001/acceptor.h deleted file mode 100644 index 988b1948231..00000000000 --- a/docs/tutorials/001/acceptor.h +++ /dev/null @@ -1,138 +0,0 @@ - -// $Id$ - - -#if !defined (_CLIENT_ACCEPTOR_H) -#define _CLIENT_ACCEPTOR_H - -/* - A SOCK_Acceptor knows how to accept socket connections. We'll use - one of those at the heart of our Logging_Acceptor. - */ -#include "ace/SOCK_Acceptor.h" - -/* - An Event_Handler is what you register with ACE_Reactor. When events occur, - the reactor will callback on the Event_Handler. More on that in a few lines. - */ -#include "ace/Event_Handler.h" - -/* - When a client connects, we'll create a Logging_Handler to deal with the - connection. Here, we bring in that declaration. - */ -#include "logger.h" - -/* - Our Logging_Acceptor is derived from ACE_Event_Handler. That lets the - reactor treat our acceptor just like every other handler. - */ -class Logging_Acceptor : public ACE_Event_Handler -{ - -friend class Logging_Handler; - -public: - - /* - For this simple case we won't bother with either constructor or - destructor. In a real application you would certainly have them. - */ - - /* - Here's the open() method we called from main(). We have two things - to accomplish here: (1) Open the acceptor so that we can hear - client requests and (2) register ourselves with the reactor so that - we can respond to those requests. - */ - int open (const ACE_INET_Addr &_addr, ACE_Reactor * _reactor ) - { - /* - Perform the open() on the acceptor. We pass through the address - at which main() wants us to listen. The second parameter tells - the acceptor it is OK to reuse the address. This is necessary - sometimes to get around closed connections that haven't timed out. - */ - if (this->peer_acceptor_.open (_addr, 1) == -1) - return -1; - - /* - Remember the reactor we're using. We'll need it later when we - create a client connection handler. - */ - reactor_ = _reactor; - - /* - Now we can register with the reactor we were given. Since the reactor - pointer is global, we could have just used that but it's gross enough - already. - Notice that we can pass 'this' right into the registration since we're - derived from ACE_Event_Handler. We also provide ACCEPT_MASK to tell - the reactor that we want to know about accept requests from clients. - */ - return _reactor->register_handler( this, ACE_Event_Handler::ACCEPT_MASK ); - } - -private: - - /* - To provide multi-OS abstraction, ACE uses the concept of "handles" for - connection endpoints. In Unix, this is a traditional file descriptor - (or integer). On other OS's, it may be something else. - The reactor will need to get the handle (file descriptor) to satisfy - it's own internal needs. Our relevant handle is the handle of the - acceptor object, so that's what we provide. - */ - ACE_HANDLE get_handle (void) const - { - return this->peer_acceptor_.get_handle (); - } - - /* - When an accept request arrives, the reactor will invoke the handle_input() - callback. This is where we deal with the connection request. - */ - int handle_input (ACE_HANDLE) - { - /* - In response to the connection request, we create a new Logging_Handler. - This new object will be used to interact with the client until it - disconnects. - */ - Logging_Handler *svc_handler = new Logging_Handler; - - /* - To complete the connection, we invoke the accept() method call on - the acceptor object and provide it with the connection handler instance. - This transfers "ownership" of the connection from the acceptor to the - connection handler. - */ - if (this->peer_acceptor_.accept (*svc_handler) == -1) - ACE_ERROR_RETURN ((LM_ERROR, "%p", "accept failed"), -1); - - /* - Again, most objects need to be open()ed before they are useful. We'll - give the handler our reactor pointer so that it can register for - events as well. If the open fails, we'll force a close(). - */ - if (svc_handler->open (reactor_) == -1) - svc_handler->close (); - - return 0; - } - -protected: - - /* - Our acceptor object instance - */ - ACE_SOCK_Acceptor peer_acceptor_; - - /* - A place to remember our reactor pointer - */ - ACE_Reactor * reactor_; -}; - -#endif /* _CLIENT_ACCEPTOR_H */ - diff --git a/docs/tutorials/001/logger.h b/docs/tutorials/001/logger.h deleted file mode 100644 index 8063f83f48a..00000000000 --- a/docs/tutorials/001/logger.h +++ /dev/null @@ -1,161 +0,0 @@ - -// $Id$ - - -#if !defined (_CLIENT_HANDLER_H) -#define _CLIENT_HANDLER_H - -/* - A connection handler will also be derived from ACE_Event_Handler so that we - can register with a reactor. - */ -#include "ace/Event_Handler.h" - -#include "ace/INET_Addr.h" - -/* - Since we're doing TCP/IP, we'll need a SOCK_Stream for the connection. - */ -#include "ace/SOCK_Stream.h" - -class Logging_Handler : public ACE_Event_Handler -{ -public: - - /* - Like the acceptor, we're simple enough to avoid constructor and destructor. - */ - - /* - To open the client handler, we have to register ourselves with the reactor. - Notice that we don't have to "open" our ACE_SOCK_Stream member variable. - Why? Because the call to the acceptor's accept() method took care of those - details for us. - */ - int open ( ACE_Reactor * _reactor ) - { - /* - Remember our reactor... - */ - reactor_ = _reactor; - - /* - In this case we're using the READ_MASK. Like the acceptor, handle_input() - will be called due to this mask but it's a nice piece of bookkeeping to - have separate masks for the separate types of activity. - */ - if (_reactor-> register_handler (this, ACE_Event_Handler::READ_MASK) == -1) - ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) can't register with reactor\n"), -1); - return 0; - } - - /* - If we're explicitly closed we'll close our "file handle". The net result - is to close the connection to the client and remove ourselves from the - reactor if we're registered - */ - int close (void) - { - return this->handle_close (ACE_INVALID_HANDLE, ACE_Event_Handler::RWE_MASK); - } - - /* - This is a bit of magic... When we call the accept() method of the acceptor - object, it wants to do work on an ACE_SOCK_Stream. We have one of those as - our connection to the client but it would be gross to provide a method to - access that object. It's much cooler if the acceptor can just treat the - Logging_Handler as an ACE_SOCK_Stream. Providing this cast operator lets - that happen cleanly. - */ - operator ACE_SOCK_Stream &() - { - return this->cli_stream_; - } - -protected: - - /* - Again, like the acceptor, we need to provide the connection handle to the reactor. - */ - ACE_HANDLE get_handle (void) const - { - return this->cli_stream_.get_handle (); - } - - /* - And here's the handle_input(). This is really the workhorse of the application. - */ - int handle_input (ACE_HANDLE) - { - /* - Create and initialize a small receive buffer. - */ - char buf[128]; - memset(buf,0,sizeof(buf)); - - /* - Invoke the recv() method of the ACE_SOCK_Stream to get some data. It will - return -1 if there is an error. Otherwise, it will return the number of bytes - read. Of course, if it read zero bytes then the connection must be gone. - How do I know that? Because handle_input() would not be called by the reactor - if there wasn't *some* kind of activity and a closed connection looks like a - read request to the reactor. But when you read from a closed connection you'll - read zero bytes. - Notice that in the error case or closed case we return -1. That tells the reactor - to call our handle_close() where we'll take care of shutting down cleanly. - */ - switch( this->cli_stream_.recv(buf,sizeof buf) ) - { - case -1: - ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) %p bad read\n", "client logger"), -1); - case 0: - ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) closing log daemon (fd = %d)\n", - this->get_handle ()), -1); - default: - ACE_DEBUG ((LM_DEBUG, "(%P|%t) from client: %s",buf)); - } - - return 0; - } - - /* - When handle_input() returns -1, we'll end up here. There are a few housekeeping - chores to handle. - */ - int handle_close (ACE_HANDLE, ACE_Reactor_Mask _mask) - { - /* - Remove ourselves from the reactor. We have to include the DONT_CALL in the - mask so that it won't call handle_close() on us again! - */ - reactor_->remove_handler(this,_mask|ACE_Event_Handler::DONT_CALL); - - /* - Close the socket that we're connected to the client with. - */ - cli_stream_.close(); - - /* - Since we know we were dynamically allocated by the acceptor, now is a good - time to get rid of ourselves. - */ - delete this; - - return 0; - } - -protected: - - /* - Our peer connection. - */ - ACE_SOCK_Stream cli_stream_; - - /* - Our reactor (and our acceptor's reactor). - */ - ACE_Reactor * reactor_; -}; - -#endif /* _CLIENT_HANDLER_H */ - diff --git a/docs/tutorials/001/page01.html b/docs/tutorials/001/page01.html deleted file mode 100644 index f8a921ee48b..00000000000 --- a/docs/tutorials/001/page01.html +++ /dev/null @@ -1,109 +0,0 @@ -<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN"> -<HTML> -<HEAD> - <TITLE>ACE Tutorial 001</TITLE> - <META NAME="GENERATOR" CONTENT="Mozilla/3.01Gold (Win95; I) [Netscape]"> - <META NAME="Author" CONTENT="James CE Johnson"> - <META NAME="Description" CONTENT="A first step towards using ACE productively"> -</HEAD> -<BODY text = "#000000" link="#000fff" vlink="#ff0f0f" bgcolor="#ffffff"> - - -<CENTER><P><B><FONT SIZE=+2>ACE Tutorial 001<BR> -A Beginners Guide to Using the ACE Toolkit</FONT></B></P></CENTER> - -<P> -<HR WIDTH="100%"></P> - -<P>The purpose of this tutorial is to show you how to create a very simple -server capable of handling multiple client connections. Unlike a "traditional" -server application, this one handles all requests in one process. Issues -of multi-processing and multi-threading will be handled in later tutorial.</P> - -<P> -<HR WIDTH="100%"></P> - -<P>What do you need to create a server?</P> - -<OL> -<LI>Something which accepts connections from clients</LI> - -<LI>Something which handles established connections</LI> - -<LI>A main program loop that handles it all</LI> -</OL> - -<P>The ACE Acceptor provides a solution for our first requirement. -This class is given a TCP/IP port number on which it will listen for -incoming connections. When a connection is attempted, the acceptor will -create a new object (the handler) to deal with the client connection while -the acceptor goes back to listening for other connections.</P> - -<P>The ACE EventHandler solves our second requirement. This doesn't -seem obvious now but as we progress through this tutorial it will become -more clear.</P> - -<P>Finally, a simple <I>main()</I> function will provide our program loop. -After any program initiallization, it will enter an infinite loop which -waits for connection attempts to the Acceptor or data "events" -on the EventHandler.</P> - -<P> -<HR WIDTH="100%"></P> - -<P>Before we continue, I need to introduce one more ACE concept: the Reactor. -</P> - -<P>I don't want to go into great detail at this time on what the Reactor -is, what it does and how it does it but it is necessary for you to understand -the basic function of a reactor because it is going to be in the first -piece of code you see. The figure below depicts the interrelationships -between the Reactor, the Acceptor and the application handler.</P> -<P> <center> <img src="simple.gif" align=center> </center> - -<P>Briefly:<BR> -The reactor is an object which reacts when things happen to other objects. -These things are called <I>events</I>. The <I>other objects</I> are communications -objects which you have <I>registered</I> with the reactor. At the time -of registration, you also specify which events you are interested in. The -reactor is notified by the operating system when the events of interest -occur within the registered objects. The reactor then uses member functions -of the registered object to process the event. Notice that the reactor -doesn't care what happens because of the event. It is the object's responsibility -to process the event correctly. The reactor simply notifies the object -of the event.</P> - -<P>Why use the reactor?</P> - -<P>That will become clear as the tutorial progresses. For now, however, -a brief answer would be this: it allows multiple simultaneous client connections -to be processed efficiently by a single-threaded server. </P> - -<P>Servers have traditionally created a separate thread or process for -each client served. For large-volume services (such as telnet and ftp) -this is appropriate. However, for small-volume services the overhead of -process creation far outweighs the actual work being done. So... folks -begin using threads instead of processes to handle the clients. This is -good also but still, in some cases, the overhead is too much to bear. Instead, -why not have a single thread handle several clients and use a more intelligent -load-balancing methodology than one-thread-or-process-per-client? -<i>Caveat: Handling all requests in one thread of one process is really -only good when the requests can be handled almost instantaneously.</i> -</P> - -<P>This is where the reactor's power and flexibility come into play. The -developer can begin as a simple, single-threaded application that is later -modified to thread-per-client, process-per-client or thread-pool solution. -<P> -If all of this is gibberish & makes you think that ACE is way to hard to -learn, don't worry. We'll go into all the details & explain as we go. -I only went into all of this so that it can kick around in the back of your -mind until you need it later. -<P> -<HR WIDTH="100%"></P> - -<CENTER><P>[<A HREF="..">Tutorial Index</A>] [<A HREF="page02.html">Continue -This Tutorial</A>] </P></CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/001/page02.html b/docs/tutorials/001/page02.html deleted file mode 100644 index f5979936078..00000000000 --- a/docs/tutorials/001/page02.html +++ /dev/null @@ -1,137 +0,0 @@ -<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 001</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 001</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>A Beginners Guide to Using the ACE Toolkit</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> - -<P>From here, I want to move on to the main program loop. In a way, we're -starting at the final product when we do this, but it is a very simple -piece of code and a good place to start. - -<P>The <A HREF="server.cpp">main</A> -program is really quite simple. The real work is done in the ACE derived -classes. - -<P> -<HR WIDTH="100%"> -<PRE>/* - Include the header file where our client acceptor is defined. - */ -#include "ace/Reactor.h" - -/* - For simplicity, we create our reactor in the global address space. - In later tutorials we will do something more clever and appropriate. However, - the purpose of this tutorial is to introduce a connection acceptance and - handling, not the full capabilities of a reactor. -*/ -ACE_Reactor * g_reactor; - -/* - Include the header where we define our acceptor object. An acceptor is - an abstraction that allows a server to "accept" connections from clients. -*/ -#include "acceptor.h" - -/* - A TCP/IP server can listen to only one port for connection requests. - Well-known services can always be found at the same address. Lesser-known - services are generally told where to listen by a configuration file or - command-line parameter. For this example, we're satisfied with simply hard-coding - a random but known value. -*/ -static const u_short PORT = ACE_DEFAULT_SERVER_PORT; - -int main (int, char **) -{ - /* - Create a Reactor instance. Again, a global pointer isn't exactly the - best way to handle this but for the simple example here, it will be OK. - We'll get cute with it later. - */ - g_reactor = new ACE_Reactor; - - /* - Like the Reactor, I'm skimming over the details of the ADDR - object. What it provides is an abstraction for addressing services in the - network. All we need to know at this point is that we are creating an address - object which specifies the TCP/IP port on which the server - will listen for new connection requests. - */ - ACE_INET_Addr addr (PORT); - - /* - We now create an acceptor object. No connections will - yet be established because the object isn't "open for business" - at this time. Which brings us to the next line... - */ - Logging_Acceptor * peer_acceptor = new Logging_Acceptor(); - - /* - where the acceptor object is opened. You'll find that most ACE - objects have to be open()ed before they're of any use to you. - On this open() call, we're telling the acceptor where to listen - for connections via the 'addr' object. We're also telling it - that we want it to be registered with our 'g_reactor' instance. - */ - if (peer_acceptor->open(addr,g_reactor) == -1 ) - ACE_ERROR_RETURN ((LM_ERROR, "Opening Acceptor\n"), -1); - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) starting up server logging daemon\n")); - - /* - The reactor's handle_events member function is responsible for looking at - all registered objects and invoking an appropriate member function when - anything of interest occurs. When an event is processed, the handle_events - function returns. In order to get all events, we embed this in an infinite - loop. - - Since we put ourselves into an infinite loop, you'll need to CTRL-C - to exit the program. - */ - while (1) - g_reactor-> handle_events (); - - return 0; -}</PRE> - -<HR WIDTH="100%"> - -<P>As I said, the main program is really quite simple: -<UL> -<LI> -Create an address for the <I>port</I> we want to listen to</LI> - -<LI> -Create an acceptor which listens on that address</LI> - -<LI> -Register the acceptor with a reactor to respond to the connection requests</LI> - -<LI> -Enter an infinite loop to let the reactor handle the events</LI> -</UL> -On the next page, we will take a look at the acceptor and how it responds -to new connection requests. - -<P> -<HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial -Index</A>] [<A HREF="page01.html">Previous -Page</A>] [<A HREF="page03.html">Continue -This Tutorial</A>]</CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/001/page03.html b/docs/tutorials/001/page03.html deleted file mode 100644 index e6d0b708c16..00000000000 --- a/docs/tutorials/001/page03.html +++ /dev/null @@ -1,193 +0,0 @@ -<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 001</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 001</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>A Beginners Guide to Using the ACE Toolkit</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> - -<P>Now we begin to look at the <A HREF="acceptor.h">acceptor</A> object. - -<P> -<HR WIDTH="100%"> -<PRE> -#if !defined (_CLIENT_ACCEPTOR_H) -#define _CLIENT_ACCEPTOR_H - -/* - A SOCK_Acceptor knows how to accept socket connections. We'll use - one of those at the heart of our Logging_Acceptor. - */ -#include "ace/SOCK_Acceptor.h" - -/* - An Event_Handler is what you register with ACE_Reactor. When events occur, - the reactor will callback on the Event_Handler. More on that in a few lines. - */ -#include "ace/Event_Handler.h" - -/* - When a client connects, we'll create a Logging_Handler to deal with the - connection. Here, we bring in that declaration. - */ -#include "logger.h" - -/* - Our Logging_Acceptor is derived from ACE_Event_Handler. That lets the - reactor treat our acceptor just like every other handler. - */ -class Logging_Acceptor : public ACE_Event_Handler -{ - -friend class Logging_Handler; - -public: - - /* - For this simple case we won't bother with either constructor or - destructor. In a real application you would certainly have them. - */ - - /* - Here's the open() method we called from main(). We have two things - to accomplish here: (1) Open the acceptor so that we can hear - client requests and (2) register ourselves with the reactor so that - we can respond to those requests. - */ - int open (const ACE_INET_Addr &_addr, ACE_Reactor * _reactor ) - { - /* - Perform the open() on the acceptor. We pass through the address - at which main() wants us to listen. The second parameter tells - the acceptor it is OK to reuse the address. This is necessary - sometimes to get around closed connections that haven't timed out. - */ - if (this->peer_acceptor_.open (_addr, 1) == -1) - return -1; - - /* - Remember the reactor we're using. We'll need it later when we - create a client connection handler. - */ - reactor_ = _reactor; - - /* - Now we can register with the reactor we were given. Since the reactor - pointer is global, we could have just used that but it's gross enough - already. - Notice that we can pass 'this' right into the registration since we're - derived from ACE_Event_Handler. We also provide ACCEPT_MASK to tell - the reactor that we want to know about accept requests from clients. - */ - return _reactor->register_handler( this, ACE_Event_Handler::ACCEPT_MASK ); - } - -private: - - /* - To provide multi-OS abstraction, ACE uses the concept of "handles" for - connection endpoints. In Unix, this is a traditional file descriptor - (or integer). On other OS's, it may be something else. - The reactor will need to get the handle (file descriptor) to satisfy - it's own internal needs. Our relevant handle is the handle of the - acceptor object, so that's what we provide. - */ - ACE_HANDLE get_handle (void) const - { - return this->peer_acceptor_.get_handle (); - } - - /* - When an accept request arrives, the reactor will invoke the handle_input() - callback. This is where we deal with the connection request. - */ - int handle_input (ACE_HANDLE) - { - /* - In response to the connection request, we create a new Logging_Handler. - This new object will be used to interact with the client until it - disconnects. - */ - Logging_Handler *svc_handler = new Logging_Handler; - - /* - To complete the connection, we invoke the accept() method call on - the acceptor object and provide it with the connection handler instance. - This transfers "ownership" of the connection from the acceptor to the - connection handler. - */ - if (this->peer_acceptor_.accept (*svc_handler) == -1) - ACE_ERROR_RETURN ((LM_ERROR, "%p", "accept failed"), -1); - - /* - Again, most objects need to be open()ed before they are useful. We'll - give the handler our reactor pointer so that it can register for - events as well. If the open fails, we'll force a close(). - */ - if (svc_handler->open (reactor_) == -1) - svc_handler->close (); - - return 0; - } - -protected: - - /* - Our acceptor object instance - */ - ACE_SOCK_Acceptor peer_acceptor_; - - /* - A place to remember our reactor pointer - */ - ACE_Reactor * reactor_; -}; - -#endif /* _CLIENT_ACCEPTOR_H */ - - -<HR WIDTH="100%"></PRE> -It is important to notice here that we have done very little application-specifc -code in developing this object. In fact, if we take out the progress information, -the only app-specific code is when we create the new <I>Logging_Handler</I> -object to give to the <I>accept</I> function. You may begin to wonder why -there isn't a C++ template that does all of this coding for you. Actually, -the ACE toolkit happens to have one handy: -<UL>typedef ACE_Acceptor <<I>YourHandlerClass</I>, ACE_SOCK_ACCEPTOR> -<I>YourAcceptorClass</I>;</UL> -We would have used it like this: -<UL>typedef ACE_Acceptor <Logging_Handler, ACE_SOCK_ACCEPTOR> Client_Acceptor;</UL> -This will create a piece of code similar to what I've shown above. The -primary difference is that the <I>handle_input </I>function created by -the template does NOT register the handler with the reactor. In the long-run, -that is good for us because we can then move that logic into the <I>open</I> -function of the <I>Logging_Handler</I> and use a completely-generic acceptor. - -<P>Now that we know how to accept a connection request, let's move on to -the next page where we learn how to handle the actual connection. Even -though we just learned about this cool template thing, we will continue -to use the "hand-written" acceptor developed above. As I mentioned, the -only difference will be in the <I>open</I> function of the connection handler -anyway. - -<P> -<HR WIDTH="100%"> -<CENTER></CENTER> - -<CENTER>[<A HREF="..">Tutorial -Index</A>] [<A HREF="page02.html">Previous -Page</A>] [<A HREF="page04.html">Continue -This Tutorial</A>]</CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/001/page04.html b/docs/tutorials/001/page04.html deleted file mode 100644 index 5223bb34282..00000000000 --- a/docs/tutorials/001/page04.html +++ /dev/null @@ -1,204 +0,0 @@ -<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 001</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 001</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>A Beginners Guide to Using the ACE Toolkit</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> - -<P>Now we begin to look at the <A HREF="logger.h">logger</A> -object. - -<P> -<HR WIDTH="100%"> -<PRE> -#if !defined (_CLIENT_HANDLER_H) -#define _CLIENT_HANDLER_H - -/* - A connection handler will also be derived from ACE_Event_Handler so that we - can register with a reactor. - */ -#include "ace/Event_Handler.h" - -#include "ace/INET_Addr.h" - -/* - Since we're doing TCP/IP, we'll need a SOCK_Stream for the connection. - */ -#include "ace/SOCK_Stream.h" - -class Logging_Handler : public ACE_Event_Handler -{ -public: - - /* - Like the acceptor, we're simple enough to avoid constructor and destructor. - */ - - /* - To open the client handler, we have to register ourselves with the reactor. - Notice that we don't have to "open" our ACE_SOCK_Stream member variable. - Why? Because the call to the acceptor's accept() method took care of those - details for us. - */ - int open ( ACE_Reactor * _reactor ) - { - /* - Remember our reactor... - */ - reactor_ = _reactor; - - /* - In this case we're using the READ_MASK. Like the acceptor, handle_input() - will be called due to this mask but it's a nice piece of bookkeeping to - have separate masks for the separate types of activity. - */ - if (_reactor-> register_handler (this, ACE_Event_Handler::READ_MASK) == -1) - ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) can't register with reactor\n"), -1); - - return 0; - } - - /* - If we're explicitly closed we'll close our "file handle". The net result - is to close the connection to the client and remove ourselves from the - reactor if we're registered - */ - int close (void) - { - return this->handle_close (ACE_INVALID_HANDLE, ACE_Event_Handler::RWE_MASK); - } - - /* - This is a bit of magic... When we call the accept() method of the acceptor - object, it wants to do work on an ACE_SOCK_Stream. We have one of those as - our connection to the client but it would be gross to provide a method to - access that object. It's much cooler if the acceptor can just treat the - Logging_Handler as an ACE_SOCK_Stream. Providing this cast operator lets - that happen cleanly. - */ - operator ACE_SOCK_Stream &() - { - return this->cli_stream_; - } - -protected: - - /* - Again, like the acceptor, we need to provide the connection handle to the reactor. - */ - ACE_HANDLE get_handle (void) const - { - return this->cli_stream_.get_handle (); - } - - /* - And here's the handle_input(). This is really the workhorse of the application. - */ - int handle_input (ACE_HANDLE) - { - /* - Create and initialize a small receive buffer. - */ - char buf[128]; - memset(buf,0,sizeof(buf)); - - /* - Invoke the recv() method of the ACE_SOCK_Stream to get some data. It will - return -1 if there is an error. Otherwise, it will return the number of bytes - read. Of course, if it read zero bytes then the connection must be gone. - How do I know that? Because handle_input() would not be called by the reactor - if there wasn't *some* kind of activity and a closed connection looks like a - read request to the reactor. But when you read from a closed connection you'll - read zero bytes. - Notice that in the error case or closed case we return -1. That tells the reactor - to call our handle_close() where we'll take care of shutting down cleanly. - */ - switch( this->cli_stream_.recv(buf,sizeof buf) ) - { - case -1: - ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) %p bad read\n", "client logger"), -1); - case 0: - ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) closing log daemon (fd = %d)\n", - this->get_handle ()), -1); - default: - ACE_DEBUG ((LM_DEBUG, "(%P|%t) from client: %s",buf)); - } - - return 0; - } - - /* - When handle_input() returns -1, we'll end up here. There are a few housekeeping - chores to handle. - */ - int handle_close (ACE_HANDLE, ACE_Reactor_Mask _mask) - { - /* - Remove ourselves from the reactor. We have to include the DONT_CALL in the - mask so that it won't call handle_close() on us again! - */ - reactor_->remove_handler(this,_mask|ACE_Event_Handler::DONT_CALL); - - /* - Close the socket that we're connected to the client with. - */ - cli_stream_.close(); - - /* - Since we know we were dynamically allocated by the acceptor, now is a good - time to get rid of ourselves. - */ - delete this; - - return 0; - } - -protected: - - /* - Our peer connection. - */ - ACE_SOCK_Stream cli_stream_; - - /* - Our reactor (and our acceptor's reactor). - */ - ACE_Reactor * reactor_; -}; - -#endif /* _CLIENT_HANDLER_H */</PRE> - - -<P> -<HR WIDTH="100%"> - -<P>Now that we know how to accept a connection request, let's move on to -the next page where we learn how to handle the actual connection. Even -though we just learned about this cool template thing, we will continue -to use the "hand-written" acceptor developed above. As I mentioned, the -only difference will be in the <I>open</I> function of the connection handler -anyway. - -<P> -<HR WIDTH="100%"> -<CENTER></CENTER> - -<CENTER>[<A HREF="..">Tutorial -Index</A>] [<A HREF="page03.html">Previous -Page</A>] [<A HREF="page05.html">Continue -This Tutorial</A>]</CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/001/page05.html b/docs/tutorials/001/page05.html deleted file mode 100644 index 5e441d04b11..00000000000 --- a/docs/tutorials/001/page05.html +++ /dev/null @@ -1,62 +0,0 @@ -<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 001</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 001</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>A Beginners Guide to Using the ACE Toolkit</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> - -<P>This concludes the first tutorial on using ACE. We've learned how to -create a simple server without knowing very much about network programming. - -<P>The code used in this tutorial is for illustration purposes. That means -it may or may not work. Actually, it <I>does</I> work but the -astute reader will notice a number of places for potential memory leaks. -We'll work on cleaning those up in future tutorials but if you find one -feel free to send me a fix & I'll integrate it into the tutorial. - -<P>You can download all of the <A HREF="Source.tgz">source</A> -or individual files: -<UL> -<LI> -<A HREF="00SetEnv">Environment -Settings</A></LI> - -<LI> -<A HREF="Makefile">Makefile</A></LI> - -<LI> -<A HREF="server.cpp">main -program</A></LI> - -<LI> -<A HREF="acceptor.h">acceptor -object</A></LI> - -<LI> -<A HREF="logger.h">connection -handler</A></LI> -</UL> -(The source is a gzip'ed tar file which can be unpacked using <I>winzip</I> -or the Unix command <I>tar -xvzf filename</I>.) - -<P> -<HR WIDTH="100%"> -<CENTER></CENTER> - -<CENTER>[<A HREF="..">Tutorial -Index</A>] [<A HREF="page04.html">Previous -Page</A>]</CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/001/server.cpp b/docs/tutorials/001/server.cpp deleted file mode 100644 index 391b1c18825..00000000000 --- a/docs/tutorials/001/server.cpp +++ /dev/null @@ -1,85 +0,0 @@ - -// $Id$ - - -/* - Include the header file where our client acceptor is defined. - */ -#include "ace/Reactor.h" - -/* - For simplicity, we create our reactor in the global address space. - In later tutorials we will do something more clever and appropriate. However, - the purpose of this tutorial is to introduce a connection acceptance and - handling, not the full capabilities of a reactor. -*/ -ACE_Reactor * g_reactor; - -/* - Include the header where we define our acceptor object. An acceptor is - an abstraction that allows a server to "accept" connections from clients. -*/ -#include "acceptor.h" - -/* - A TCP/IP server can listen to only one port for connection requests. - Well-known services can always be found at the same address. Lesser-known - services are generally told where to listen by a configuration file or - command-line parameter. For this example, we're satisfied with simply hard-coding - a random but known value. -*/ -static const u_short PORT = ACE_DEFAULT_SERVER_PORT; - -int main (int, char **) -{ - /* - Create a Reactor instance. Again, a global pointer isn't exactly the - best way to handle this but for the simple example here, it will be OK. - We'll get cute with it later. - */ - g_reactor = new ACE_Reactor; - - /* - Like the Reactor, I'm skimming over the details of the ADDR - object. What it provides is an abstraction for addressing services in the - network. All we need to know at this point is that we are creating an address - object which specifies the TCP/IP port on which the server - will listen for new connection requests. - */ - ACE_INET_Addr addr (PORT); - - /* - We now create an acceptor object. No connections will - yet be established because the object isn't "open for business" - at this time. Which brings us to the next line... - */ - Logging_Acceptor * peer_acceptor = new Logging_Acceptor(); - - /* - where the acceptor object is opened. You'll find that most ACE - objects have to be open()ed before they're of any use to you. - On this open() call, we're telling the acceptor where to listen - for connections via the 'addr' object. We're also telling it - that we want it to be registered with our 'g_reactor' instance. - */ - if (peer_acceptor->open(addr,g_reactor) == -1 ) - ACE_ERROR_RETURN ((LM_ERROR, "Opening Acceptor\n"), -1); - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) starting up server logging daemon\n")); - - /* - The reactor's handle_events member function is responsible for looking at - all registered objects and invoking an appropriate member function when - anything of interest occurs. When an event is processed, the handle_events - function returns. In order to get all events, we embed this in an infinite - loop. - - Since we put ourselves into an infinite loop, you'll need to CTRL-C - to exit the program. - */ - while (1) - g_reactor-> handle_events (); - - return 0; -} - diff --git a/docs/tutorials/001/simple.fig b/docs/tutorials/001/simple.fig deleted file mode 100644 index afea1bddabe..00000000000 --- a/docs/tutorials/001/simple.fig +++ /dev/null @@ -1,57 +0,0 @@ -#FIG 3.2 -Landscape -Center -Inches -Letter -100.00 -Single --2 -1200 2 -6 7800 5925 11850 6900 -2 4 0 1 0 7 0 0 -1 0.000 0 0 7 0 0 5 - 11850 6900 11850 5925 7800 5925 7800 6900 11850 6900 -4 0 0 0 0 0 12 0.0000 4 180 3360 7800 6150 Application_Handler (ACE_Event_Handler)\001 -4 0 0 0 0 0 12 0.0000 4 180 3825 7950 6450 handle_input() {read connection, process data ... }\001 -4 0 0 0 0 0 12 0.0000 4 180 1335 7950 6675 get_handle() {...}\001 --6 -2 4 0 1 0 7 0 0 -1 0.000 0 0 7 0 0 5 - 5100 7200 5100 5925 1725 5925 1725 7200 5100 7200 -2 1 1 1 1 7 0 0 -1 4.000 0 0 -1 1 0 2 - 2 1 1.00 60.00 120.00 - 4950 6600 7725 6600 -2 1 0 1 4 7 0 0 -1 0.000 0 0 -1 0 1 2 - 2 1 1.00 60.00 120.00 - 3900 5925 5400 2250 -2 1 0 1 4 7 0 0 -1 0.000 0 0 -1 0 1 2 - 2 1 1.00 60.00 120.00 - 8400 5925 6600 2250 -2 1 0 1 12 7 0 0 -1 0.000 0 0 -1 1 0 2 - 2 1 1.00 60.00 120.00 - 4500 5925 6000 2250 -2 1 0 1 12 7 0 0 -1 0.000 0 0 -1 1 0 2 - 2 1 1.00 60.00 120.00 - 9000 5925 7200 2250 -2 1 2 2 24 7 0 0 -1 3.000 0 0 -1 0 1 2 - 0 0 1.00 60.00 120.00 - 3300 7200 3300 8325 -2 1 0 2 15 7 0 0 -1 0.000 0 0 -1 1 1 2 - 0 0 1.00 60.00 120.00 - 0 0 1.00 60.00 120.00 - 9600 6900 9600 8025 -2 4 0 1 0 7 0 0 -1 0.000 0 0 7 0 0 5 - 7500 2250 7500 1425 5100 1425 5100 2250 7500 2250 -4 0 0 0 0 0 12 0.0000 4 180 3045 1800 6150 Client_Acceptor (ACE_Event_Handler)\001 -4 0 0 0 0 0 12 0.0000 4 180 2565 1950 6450 handle_input() {open data conn ...\001 -4 0 0 0 0 0 12 0.0000 4 180 1755 3150 6675 create Handler Obj ... }\001 -4 0 0 0 0 0 12 0.0000 4 180 1335 1950 6900 get_handle() {...}\001 -4 0 1 0 0 0 12 0.0000 4 180 1800 5550 6450 create new Handler Obj\001 -4 0 24 0 0 0 12 0.0000 4 180 1530 2550 7800 Connection Request\001 -4 0 15 0 0 0 12 0.0000 4 135 1275 9000 7500 Data Connection\001 -4 0 0 0 0 0 12 0.0000 4 135 600 5925 1725 Reactor\001 -4 0 0 0 0 0 12 0.0000 4 180 1935 5325 2025 event handler dispatching\001 -4 0 0 0 0 0 12 0.0000 4 180 585 8175 4875 register\001 -4 0 0 0 0 0 12 0.0000 4 180 585 4650 5025 register\001 -4 0 0 0 0 0 12 0.0000 4 180 1110 4200 3675 handle_input()\001 -4 0 0 0 0 0 12 0.0000 4 180 975 4200 3900 get_handle()\001 -4 0 0 0 0 0 12 0.0000 4 180 1110 6675 3675 handle_input()\001 -4 0 0 0 0 0 12 0.0000 4 180 975 6675 3900 get_handle()\001 diff --git a/docs/tutorials/001/simple.gif b/docs/tutorials/001/simple.gif Binary files differdeleted file mode 100644 index ef29d88a120..00000000000 --- a/docs/tutorials/001/simple.gif +++ /dev/null diff --git a/docs/tutorials/002/00SetEnv b/docs/tutorials/002/00SetEnv deleted file mode 100644 index eca78e10c85..00000000000 --- a/docs/tutorials/002/00SetEnv +++ /dev/null @@ -1,2 +0,0 @@ -export ACE_ROOT=/local/src/ACE/ACE_wrappers -export LD_LIBRARY_PATH=$ACE_ROOT/ace:$LD_LIBRARY_PATH diff --git a/docs/tutorials/002/Makefile b/docs/tutorials/002/Makefile deleted file mode 100644 index bf06d77195d..00000000000 --- a/docs/tutorials/002/Makefile +++ /dev/null @@ -1,42 +0,0 @@ -#---------------------------------------------------------------------------- -# $Id$ -# -# Makefile for the Reactor version of the Server Logging Daemon -#---------------------------------------------------------------------------- - -#---------------------------------------------------------------------------- -# Local macros -#---------------------------------------------------------------------------- - -BIN = server - -VLDLIBS = $(LDLIBS:%=%$(VAR)) - -BUILD = $(VBIN) - -#---------------------------------------------------------------------------- -# Include macros and targets -#---------------------------------------------------------------------------- - -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 -#---------------------------------------------------------------------------- - -#---------------------------------------------------------------------------- -# Dependencies -#---------------------------------------------------------------------------- - -# DO NOT DELETE THIS LINE -- g++dep uses it. -# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY. - - - -# IF YOU PUT ANYTHING HERE IT WILL GO AWAY diff --git a/docs/tutorials/002/handler.h b/docs/tutorials/002/handler.h deleted file mode 100644 index e7796cbb47b..00000000000 --- a/docs/tutorials/002/handler.h +++ /dev/null @@ -1,154 +0,0 @@ - -// $Id$ - -#ifndef LOGGING_HANDLER_H -#define LOGGING_HANDLER_H - -#include "ace/INET_Addr.h" -#include "ace/SOCK_Stream.h" -#include "ace/Reactor.h" - -/* - Since we used the template to create the acceptor, we don't know if there is a - way to get to the reactor it uses. We'll take the easy way out and grab the - global pointer. (There is a way to get back to the acceptor's reactor that - we'll see later on.) - */ -extern ACE_Reactor * g_reactor; - -/* - This time we're deriving from ACE_Svc_Handler instead of ACE_Event_Handler. - The big reason for this is because it already knows how to contain a SOCK_Stream - and provides all of the method calls needed by the reactor. The second template - parameter is for some advanced stuff we'll do with later servers. For now, just - use it as is... - */ -class Logging_Handler : public ACE_Svc_Handler < ACE_SOCK_STREAM, ACE_NULL_SYNCH > -{ - -public: - - /* - The Acceptor<> template will open() us when there is a new client connection. - */ - int open (void *) - { - ACE_INET_Addr addr; - - /* - Ask the peer() (held in our baseclass) to tell us the address of the cient - which has connected. There may be valid reasons for this to fail where we - wouldn't want to drop the connection but I can't think of one. - */ - if (this->peer ().get_remote_addr (addr) == -1) - return -1; - - /* - The Acceptor<> won't register us with it's reactor, so we have to do so - ourselves. This is where we have to grab that global pointer. Notice - that we again use the READ_MASK so that handle_input() will be called - when the client does something. - */ - if (g_reactor->register_handler (this, ACE_Event_Handler::READ_MASK) == -1) - ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) can't register with reactor\n"), -1); - - /* - Here's another new treat. We schedule a timer event. This particular one - will fire in two seconds and then every three seconds after that. It doesn't - serve any useful purpose in our application other than to show you how it - is done. - */ - else if (g_reactor->schedule_timer (this, 0, ACE_Time_Value (2), ACE_Time_Value (3)) == -1) - ACE_ERROR_RETURN ((LM_ERROR, "can'(%P|%t) t register with reactor\n"), -1); - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) connected with %s\n", addr.get_host_name() )); - - return 0; - } - - /* - This is a matter of style & maybe taste. Instead of putting all of this stuff - into a destructor, we put it here and request that everyone call destroy() - instead of 'delete'. - */ - void destroy (void) - { - /* - Remove ourselves from the reactor - */ - g_reactor->remove_handler(this,ACE_Event_Handler::READ_MASK|ACE_Event_Handler::DONT_CALL); - - /* - Cancel that timer we scheduled in open() - */ - g_reactor->cancel_timer (this); - - /* - Shut down the connection to the client. - */ - this->peer ().close (); - - /* - Free our memory. - */ - delete this; - } - - /* - If somebody doesn't like us, the will close() us. Actually, if our open() method - returns -1, the Acceptor<> will invoke close() on us for cleanup. - */ - int close (u_long) - { - /* - Clean up and go away. - */ - this->destroy (); - return 0; - } - -protected: - - /* - Respond to input just like Tutorial 1. - */ - int handle_input (ACE_HANDLE) - { - char buf[128]; - memset (buf, 0, sizeof (buf)); - - switch (this->peer ().recv (buf, sizeof buf)) - { - case -1: - ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) %p bad read\n", "client logger"), -1); - case 0: - ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) closing log daemon (fd = %d)\n", this->get_handle ()), -1); - default: - ACE_DEBUG ((LM_DEBUG, "(%P|%t) from client: %s", buf)); - } - - return 0; - } - - /* - When the timer expires, handle_timeout() will be called. The 'arg' is the value passed - after 'this' in the schedule_timer() call. You can pass in anything there that you can - cast to a void*. - */ - int handle_timeout (const ACE_Time_Value & tv, const void *arg) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) handling timeout from this = %u\n", this)); - return 0; - } - - /* - Clean ourselves up when handle_input() (or handle_timer()) returns -1 - */ - int handle_close(ACE_HANDLE, ACE_Reactor_Mask _mask) - { - this->destroy(); - return 0; - } -}; - -#endif // LOGGING_HANDLER_H diff --git a/docs/tutorials/002/page01.html b/docs/tutorials/002/page01.html deleted file mode 100644 index 5bc3fc534a7..00000000000 --- a/docs/tutorials/002/page01.html +++ /dev/null @@ -1,57 +0,0 @@ -<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN"> -<HTML> -<HEAD> - <TITLE>ACE Tutorial 002</TITLE> - <META NAME="GENERATOR" CONTENT="Mozilla/3.01Gold (Win95; I) [Netscape]"> - <META NAME="Author" CONTENT="James CE Johnson"> - <META NAME="Description" CONTENT="A first step towards using ACE productively"> -</HEAD> -<BODY text = "#000000" link="#000fff" vlink="#ff0f0f" bgcolor="#ffffff"> - - -<CENTER><P><B><FONT SIZE=+2>ACE Tutorial 002<BR> -Creating a Better Server </FONT></B></P></CENTER> - -<P> -<HR WIDTH="100%"></P> - -<P>In this tutorial, we will build a little on what we learned in the first -tutorial and add a few extras. In the end, we will have a better server -object that is actually simpler and more maintainable than the one we created -before.</P> - -<P> -<HR WIDTH="100%"></P> - -<P>To begin, let's ask ourselves the same thing we did at the beginning -of tutorial 001:</P> - -<UL> -<P>What do you need to create a server?</P> -</UL> - -<OL> -<OL> -<LI>Something which accepts connections from clients</LI> - -<LI>Something which handles established connections</LI> - -<LI>A main program loop that handles it all</LI> -</OL> -</OL> - -<P>Previously, we created a solution which addressed each one of these -questions specifically. At the end of it all, we realized that our only -application-specific coding was confined to the <I>handler</I> portion -of the program. We hinted that there may be a way to eliminate hand-coding -an <I>acceptor</I> each time we want to create a server. Here, we will -explore that approach.</P> - -<P> -<HR WIDTH="100%"></P> - -<CENTER><P>[<A HREF="..">Tutorial Index</A>] [<A HREF="page02.html">Continue -This Tutorial</A>] </P></CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/002/page02.html b/docs/tutorials/002/page02.html deleted file mode 100644 index 46504375fd5..00000000000 --- a/docs/tutorials/002/page02.html +++ /dev/null @@ -1,115 +0,0 @@ -<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 002</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 002</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Creating a Better Server</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> - -<P>Like Tutorial 1, this is also a rather small program. I'm going -to add a couple of new ideas along the way but to make up for it I'm also -going to simplify the acceptor a great deal. - -<P>We begin by looking at the <A HREF="server.cpp">main</A> portion program: - -<P> -<HR WIDTH="100%"> -<PRE> -/* - As before, we need a few ACE objects as well as our Logging_Handler declaration. - */ -#include "ace/Acceptor.h" -#include "ace/SOCK_Acceptor.h" -#include "ace/Reactor.h" -#include "handler.h" - -/* - We'll still use the global reactor pointer. There's a snappy way around this - that shows up in later server tutorials. - */ -ACE_Reactor * g_reactor; - -/* - This was hinted at in Tutorial 1. Remember the hand-coded acceptor that we - created there? This template does all of that and more and better. If you - find yourself creating code that doesn't feel like a part of your application, - there's a good chance that ACE has a template or framework component to do - it for you. - */ -typedef ACE_Acceptor < Logging_Handler, ACE_SOCK_ACCEPTOR > Logging_Acceptor; - -/* - One of the new things will be a signal handler so that we can exit the application - somewhat cleanly. The 'finished' flag is used instead of the previous infninite - loop and the 'handler' will set that flag in respose to SIGINT (CTRL-C). - */ -static sig_atomic_t finished = 0; -extern "C" void handler (int) -{ - finished = 1; -} - -static const u_short PORT = ACE_DEFAULT_SERVER_PORT; - -int main (int, char **) -{ - // Create the reactor we'll register our event handler derivatives with. - g_reactor = new ACE_Reactor; - - // Create the acceptor that will listen for client connetions - Logging_Acceptor peer_acceptor; - - /* - Notice how similar this is to the open() call in Tutorial 1. I read - ahead when I created that one so that it would come out this way... - */ - if (peer_acceptor.open (ACE_INET_Addr (PORT), g_reactor) == -1) - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "open"), -1); - - /* - Here's the easiest way to respond to signals in your application. Simply - construct an ACE_Sig_Action object with a "C" function and the signal you - want to capture. As you might expect, there is also a way to register - signal handlers with a reactor but we take the easy-out here. - */ - ACE_Sig_Action sa ((ACE_SignalHandler) handler, SIGINT); - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) starting up server logging daemon\n")); - - // Perform logging service until the signal handler receives SIGINT. - while (!finished) - g_reactor->handle_events (); - - // Close the acceptor so that no more clients will be taken in. - peer_acceptor.close(); - - // Free up the memory allocated for the reactor. - delete g_reactor; - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) shutting down server logging daemon\n")); - - return 0; -}</PRE> - - -<P> -<HR WIDTH="100%"> -<CENTER></CENTER> - -<CENTER>[<A HREF="..">Tutorial -Index</A>] [<A HREF="page01.html">Previous -Page</A>] [<A HREF="page03.html">Continue -This Tutorial</A>]</CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/002/page03.html b/docs/tutorials/002/page03.html deleted file mode 100644 index 7fe8c8ab611..00000000000 --- a/docs/tutorials/002/page03.html +++ /dev/null @@ -1,183 +0,0 @@ -<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 002</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 002</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Creating a Better Server</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> - -<P>Now lets take a look at the new <A HREF="handler.h">Logging_Handler</A>: - -<P> -<HR WIDTH="100%"> -<BR> -<PRE>#ifndef LOGGING_HANDLER_H -#define LOGGING_HANDLER_H - -/* - Since we used the template to create the acceptor, we don't know if there is a - way to get to the reactor it uses. We'll take the easy way out and grab the - global pointer. (There is a way to get back to the acceptor's reactor that - we'll see later on.) - */ -extern ACE_Reactor * g_reactor; - -/* - This time we're deriving from ACE_Svc_Handler instead of ACE_Event_Handler. - The big reason for this is because it already knows how to contain a SOCK_Stream - and provides all of the method calls needed by the reactor. The second template - parameter is for some advanced stuff we'll do with later servers. For now, just - use it as is... - */ -class Logging_Handler : public ACE_Svc_Handler < ACE_SOCK_STREAM, ACE_NULL_SYNCH > -{ - -public: - - /* - The Acceptor<> template will open() us when there is a new client connection. - */ - int open (void *) - { - ACE_INET_Addr addr; - - /* - Ask the peer() (held in our baseclass) to tell us the address of the cient - which has connected. There may be valid reasons for this to fail where we - wouldn't want to drop the connection but I can't think of one. - */ - if (this->peer ().get_remote_addr (addr) == -1) - return -1; - - /* - The Acceptor<> won't register us with it's reactor, so we have to do so - ourselves. This is where we have to grab that global pointer. Notice - that we again use the READ_MASK so that handle_input() will be called - when the client does something. - */ - if (g_reactor->register_handler (this, ACE_Event_Handler::READ_MASK) == -1) - ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) can't register with reactor\n"), -1); - - /* - Here's another new treat. We schedule a timer event. This particular one - will fire in two seconds and then every three seconds after that. It doesn't - serve any useful purpose in our application other than to show you how it - is done. - */ - else if (g_reactor->schedule_timer (this, 0, ACE_Time_Value (2), ACE_Time_Value (3)) == -1) - ACE_ERROR_RETURN ((LM_ERROR, "can'(%P|%t) t register with reactor\n"), -1); - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) connected with %s\n", addr.get_host_name() )); - - return 0; - } - - /* - This is a matter of style & maybe taste. Instead of putting all of this stuff - into a destructor, we put it here and request that everyone call destroy() - instead of 'delete'. - */ - void destroy (void) - { - /* - Remove ourselves from the reactor - */ - g_reactor->remove_handler(this,ACE_Event_Handler::READ_MASK|ACE_Event_Handler::DONT_CALL); - - /* - Cancel that timer we scheduled in open() - */ - g_reactor->cancel_timer (this); - - /* - Shut down the connection to the client. - */ - this->peer ().close (); - - /* - Free our memory. - */ - delete this; - } - - /* - If somebody doesn't like us, the will close() us. Actually, if our open() method - returns -1, the Acceptor<> will invoke close() on us for cleanup. - */ - int close (u_long) - { - /* - Clean up and go away. - */ - this->destroy (); - return 0; - } - -protected: - - /* - Respond to input just like Tutorial 1. - */ - int handle_input (ACE_HANDLE) - { - char buf[128]; - memset (buf, 0, sizeof (buf)); - - switch (this->peer ().recv (buf, sizeof buf)) - { - case -1: - ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) %p bad read\n", "client logger"), -1); - case 0: - ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) closing log daemon (fd = %d)\n", this->get_handle ()), -1); - default: - ACE_DEBUG ((LM_DEBUG, "(%P|%t) from client: %s", buf)); - } - - return 0; - } - - /* - When the timer expires, handle_timeout() will be called. The 'arg' is the value passed - after 'this' in the schedule_timer() call. You can pass in anything there that you can - cast to a void*. - */ - int handle_timeout (const ACE_Time_Value & tv, const void *arg) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) handling timeout from this = %u\n", this)); - return 0; - } - - /* - Clean ourselves up when handle_input() (or handle_timer()) returns -1 - */ - int handle_close(ACE_HANDLE, ACE_Reactor_Mask _mask) - { - this->destroy(); - return 0; - } -}; - -#endif // LOGGING_HANDLER_H</PRE> - - -<P> -<HR WIDTH="100%"> -<CENTER></CENTER> - -<CENTER>[<A HREF="..">Tutorial -Index</A>] [<A HREF="page02.html">Previous -Page</A>] [<A HREF="page04.html">Continue -This Tutorial</A>]</CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/002/page04.html b/docs/tutorials/002/page04.html deleted file mode 100644 index 14837122aca..00000000000 --- a/docs/tutorials/002/page04.html +++ /dev/null @@ -1,41 +0,0 @@ -<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 002</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 002</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Creating a Better Server</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> - -<P>Well, that's it for the second tutorial. We've found a much easier way -to create a server, especially the acceptor part. At the same time, we -introduced more functionality and robustness. Not bad for a day's work. -<BR> -<UL> -<LI> -<A HREF="00SetEnv">Environment -Settings</A></LI> - -<LI> -<A HREF="Makefile">Makefile</A></LI> - -<LI> -<A HREF="server.cpp">server.cpp</A></LI> -</UL> - -<HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial -Index</A>] [<A HREF="page03.html">Previous -Page</A>]</CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/002/server.cpp b/docs/tutorials/002/server.cpp deleted file mode 100644 index bca90aa01bc..00000000000 --- a/docs/tutorials/002/server.cpp +++ /dev/null @@ -1,89 +0,0 @@ - -// $Id$ - - -/* - As before, we need a few ACE objects as well as our Logging_Handler declaration. - */ -#include "ace/Acceptor.h" -#include "ace/SOCK_Acceptor.h" -#include "ace/Reactor.h" -#include "handler.h" - -/* - We'll still use the global reactor pointer. There's a snappy way around this - that shows up in later server tutorials. - */ -ACE_Reactor * g_reactor; - -/* - This was hinted at in Tutorial 1. Remember the hand-coded acceptor that we - created there? This template does all of that and more and better. If you - find yourself creating code that doesn't feel like a part of your application, - there's a good chance that ACE has a template or framework component to do - it for you. - */ -typedef ACE_Acceptor < Logging_Handler, ACE_SOCK_ACCEPTOR > Logging_Acceptor; - -/* - One of the new things will be a signal handler so that we can exit the application - somewhat cleanly. The 'finished' flag is used instead of the previous infninite - loop and the 'handler' will set that flag in respose to SIGINT (CTRL-C). - */ -static sig_atomic_t finished = 0; -extern "C" void handler (int) -{ - finished = 1; -} - -static const u_short PORT = ACE_DEFAULT_SERVER_PORT; - -int main (int, char **) -{ - // Create the reactor we'll register our event handler derivatives with. - g_reactor = new ACE_Reactor; - - // Create the acceptor that will listen for client connetions - Logging_Acceptor peer_acceptor; - - /* - Notice how similar this is to the open() call in Tutorial 1. I read - ahead when I created that one so that it would come out this way... - */ - if (peer_acceptor.open (ACE_INET_Addr (PORT), g_reactor) == -1) - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "open"), -1); - - /* - Here's the easiest way to respond to signals in your application. Simply - construct an ACE_Sig_Action object with a "C" function and the signal you - want to capture. As you might expect, there is also a way to register - signal handlers with a reactor but we take the easy-out here. - */ - ACE_Sig_Action sa ((ACE_SignalHandler) handler, SIGINT); - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) starting up server logging daemon\n")); - - // Perform logging service until the signal handler receives SIGINT. - while (!finished) - g_reactor->handle_events (); - - // Close the acceptor so that no more clients will be taken in. - peer_acceptor.close(); - - // Free up the memory allocated for the reactor. - delete g_reactor; - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) shutting down server logging daemon\n")); - - return 0; -} - - -#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION) -template class ACE_Acceptor <Logging_Handler, ACE_SOCK_ACCEPTOR>; -template class ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH>; -#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA) -#pragma instantiate ACE_Acceptor <Logging_Handler, ACE_SOCK_ACCEPTOR> -#pragma instantiate ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH> -#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */ - diff --git a/docs/tutorials/003/00SetEnv b/docs/tutorials/003/00SetEnv deleted file mode 100644 index eca78e10c85..00000000000 --- a/docs/tutorials/003/00SetEnv +++ /dev/null @@ -1,2 +0,0 @@ -export ACE_ROOT=/local/src/ACE/ACE_wrappers -export LD_LIBRARY_PATH=$ACE_ROOT/ace:$LD_LIBRARY_PATH diff --git a/docs/tutorials/003/Makefile b/docs/tutorials/003/Makefile deleted file mode 100644 index c5da941f1b7..00000000000 --- a/docs/tutorials/003/Makefile +++ /dev/null @@ -1,37 +0,0 @@ -#---------------------------------------------------------------------------- -# $Id$ -# -# Makefile for client logging applications -#---------------------------------------------------------------------------- - -#---------------------------------------------------------------------------- -# Local macros -#---------------------------------------------------------------------------- - -BIN = client - -LSRC = $(addsuffix .cpp,$(BIN)) - -VLDLIBS = $(LDLIBS:%=%$(VAR)) - -BUILD = $(VBIN) - -#---------------------------------------------------------------------------- -# Include macros and targets -#---------------------------------------------------------------------------- - -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.bin.GNU -include $(ACE_ROOT)/include/makeinclude/rules.local.GNU - -#---------------------------------------------------------------------------- -# Local targets -#---------------------------------------------------------------------------- - -#---------------------------------------------------------------------------- -# Dependencies -#---------------------------------------------------------------------------- - diff --git a/docs/tutorials/003/client.cpp b/docs/tutorials/003/client.cpp deleted file mode 100644 index 0886729b4e7..00000000000 --- a/docs/tutorials/003/client.cpp +++ /dev/null @@ -1,105 +0,0 @@ - -// $Id$ - -/* - To establish a socket connection to a server, we'll need an ACE_SOCK_Connector. - */ -#include "ace/SOCK_Connector.h" - -/* - Unlike the previous two Tutorials, we're going to allow the user to provide - command line options this time. Still, we need defaults in case that isn't - done. - */ -static u_short SERVER_PORT = ACE_DEFAULT_SERVER_PORT; -static const char *const SERVER_HOST = ACE_DEFAULT_SERVER_HOST; -static const int MAX_ITERATIONS = 4; - -int main (int argc, char *argv[]) -{ - /* - Accept the users's choice of hosts or use the default. Then do the same - for the TCP/IP port at which the server is listening as well as the - number of iterations to perform. - */ - const char *server_host = argc > 1 ? argv[1] : SERVER_HOST; - u_short server_port = argc > 2 ? ACE_OS::atoi (argv[2]) : SERVER_PORT; - int max_iterations = argc > 3 ? ACE_OS::atoi (argv[3]) : MAX_ITERATIONS; - - /* - Build ourselves a Stream socket. This is a connected socket that provides - reliable end-to-end communications. We will use the server object to send - data to the server we connect to. - */ - ACE_SOCK_Stream server; - - /* - And we need a connector object to establish that connection. The ACE_SOCK_Connector - object provides all of the tools we need to establish a connection once we know the - server's network address... - */ - ACE_SOCK_Connector connector; - - /* - Which we create with an ACE_INET_Addr object. This object is given the TCP/IP port - and hostname of the server we want to connect to. - */ - ACE_INET_Addr addr (server_port, server_host); - - /* - So, we feed the Addr object and the Stream object to the connector's connect() member - function. Given this information, it will establish the network connection to the - server and attacht that connection to the server object. - */ - if (connector.connect (server, addr) == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "open"), -1); - } - - /* - Just for grins, we'll send the server several messages. - */ - for (int i = 0; i < max_iterations; i++) - { - char buf[BUFSIZ]; - - /* - Create our message with the message number - */ - ACE_OS::sprintf (buf, "message = %d\n", i + 1); - - /* - Send the message to the server. We use the server object's send_n() function to - send all of the data at once. There is also a send() function but it may not send - all of the data. That is due to network buffer availability and such. If the send() - doesn't send all of the data, it is up to you to program things such that it will - keep trying until all of the data is sent or simply give up. The send_n() function - already does the "keep tyring" option for us, so we use it. - */ - if (server.send_n ( buf, strlen(buf) ) == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "send"), -1); - } - else - { - /* - Pause for a second. - */ - ACE_OS::sleep (1); - } - } - - /* - Close the connection to the server. The servers we've created so far all are based - on the ACE_Reactor. When we close(), the server's reactor will see activity for - the registered event handler and invoke handle_input(). That, in turn, will try - to read from the socket but get back zero bytes. At that point, the server will know - that we've closed from our side. - */ - if (server.close () == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "close"), -1); - } - - return 0; -} diff --git a/docs/tutorials/003/page01.html b/docs/tutorials/003/page01.html deleted file mode 100644 index cbb0a47c8bc..00000000000 --- a/docs/tutorials/003/page01.html +++ /dev/null @@ -1,146 +0,0 @@ -<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 003</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 003</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Creating a Simple Client</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> - -<P>Now that we've seen how to create servers, let's spend just a moment -making a client. Since this is so easy, I'm going to do all of it in this -one page. - -<P> -<HR WIDTH="100%"> -<PRE>/* - To establish a socket connection to a server, we'll need an ACE_SOCK_Connector. - */ -#include "ace/SOCK_Connector.h" - -/* - Unlike the previous two Tutorials, we're going to allow the user to provide - command line options this time. Still, we need defaults in case that isn't - done. - */ -static u_short SERVER_PORT = ACE_DEFAULT_SERVER_PORT; -static const char *const SERVER_HOST = ACE_DEFAULT_SERVER_HOST; -static const int MAX_ITERATIONS = 4; - -int main (int argc, char *argv[]) -{ - /* - Accept the users's choice of hosts or use the default. Then do the same - for the TCP/IP port at which the server is listening as well as the - number of iterations to perform. - */ - const char *server_host = argc > 1 ? argv[1] : SERVER_HOST; - u_short server_port = argc > 2 ? ACE_OS::atoi (argv[2]) : SERVER_PORT; - int max_iterations = argc > 3 ? ACE_OS::atoi (argv[3]) : MAX_ITERATIONS; - - /* - Build ourselves a Stream socket. This is a connected socket that provides - reliable end-to-end communications. We will use the server object to send - data to the server we connect to. - */ - ACE_SOCK_Stream server; - - /* - And we need a connector object to establish that connection. The ACE_SOCK_Connector - object provides all of the tools we need to establish a connection once we know the - server's network address... - */ - ACE_SOCK_Connector connector; - - /* - Which we create with an ACE_INET_Addr object. This object is given the TCP/IP port - and hostname of the server we want to connect to. - */ - ACE_INET_Addr addr (server_port, server_host); - - /* - So, we feed the Addr object and the Stream object to the connector's connect() member - function. Given this information, it will establish the network connection to the - server and attacht that connection to the server object. - */ - if (connector.connect (server, addr) == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "open"), -1); - } - - /* - Just for grins, we'll send the server several messages. - */ - for (int i = 0; i < max_iterations; i++) - { - char buf[BUFSIZ]; - - /* - Create our message with the message number - */ - ACE_OS::sprintf (buf, "message = %d\n", i + 1); - - /* - Send the message to the server. We use the server object's send_n() function to - send all of the data at once. There is also a send() function but it may not send - all of the data. That is due to network buffer availability and such. If the send() - doesn't send all of the data, it is up to you to program things such that it will - keep trying until all of the data is sent or simply give up. The send_n() function - already does the "keep tyring" option for us, so we use it. - */ - if (server.send_n ( buf, strlen(buf) ) == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "send"), -1); - } - else - { - /* - Pause for a second. - */ - ACE_OS::sleep (1); - } - } - - /* - Close the connection to the server. The servers we've created so far all are based - on the ACE_Reactor. When we close(), the server's reactor will see activity for - the registered event handler and invoke handle_input(). That, in turn, will try - to read from the socket but get back zero bytes. At that point, the server will know - that we've closed from our side. - */ - if (server.close () == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "close"), -1); - } - - return 0; -}</PRE> - -<HR WIDTH="100%"> - -<P>Ok, so that was pretty easy. What would be even easier would be to wrap -all of the connection mess up in an object and overload a couple of basic -operators to make things less network-centric. Perhaps we'll see that in -another tutorial. - -<P>If you want to compile it yourself, here's the <A HREF="client.cpp">source</A>, -the <A HREF="Makefile">Makefile</A>, -and <A HREF="00SetEnv">Environment -settings</A>. - -<P> -<HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial -Index</A>]</CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/004/00SetEnv b/docs/tutorials/004/00SetEnv deleted file mode 100644 index eca78e10c85..00000000000 --- a/docs/tutorials/004/00SetEnv +++ /dev/null @@ -1,2 +0,0 @@ -export ACE_ROOT=/local/src/ACE/ACE_wrappers -export LD_LIBRARY_PATH=$ACE_ROOT/ace:$LD_LIBRARY_PATH diff --git a/docs/tutorials/004/Makefile b/docs/tutorials/004/Makefile deleted file mode 100644 index 06940b7f6c4..00000000000 --- a/docs/tutorials/004/Makefile +++ /dev/null @@ -1,33 +0,0 @@ -#---------------------------------------------------------------------------- -# $Id$ -# -# Makefile for client logging applications -#---------------------------------------------------------------------------- - -#---------------------------------------------------------------------------- -# Local macros -#---------------------------------------------------------------------------- - -BIN = client - -LSRC = $(addsuffix .cpp,$(BIN)) - -VLDLIBS = $(LDLIBS:%=%$(VAR)) - -BUILD = $(VBIN) - -#---------------------------------------------------------------------------- -# Include macros and targets -#---------------------------------------------------------------------------- - -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.bin.GNU -include $(ACE_ROOT)/include/makeinclude/rules.local.GNU - -#---------------------------------------------------------------------------- -# Local targets -#---------------------------------------------------------------------------- - diff --git a/docs/tutorials/004/client.cpp b/docs/tutorials/004/client.cpp deleted file mode 100644 index b32a5f8acb5..00000000000 --- a/docs/tutorials/004/client.cpp +++ /dev/null @@ -1,264 +0,0 @@ - -// $Id$ - -/* - We need the connector object & we also bring in a simple string class. - */ -#include "ace/SOCK_Connector.h" -#include "ace/SString.h" - -/* - In this tutorial, we extend SOCK_Stream by adding a few wrappers - around the send_n() method. - */ -class Client : public ACE_SOCK_Stream -{ - -public: - // Basic constructor - Client(void); - - /* - Construct and open() in one call. This isn't generally a good - idea because you don't have a clean way to inform the caller - when open() fails. (Unless you use C++ exceptions.) - */ - Client( const char * server, u_short port ); - - /* - Open the connection to the server. Notice that this mirrors - the use of ACE_SOCK_Connector. By providing our own open(), - we can hide the connector from our caller & make it's interaction - easier. - */ - int open( const char * server, u_short port ); - - /* - These are necessary if you're going to use the constructor that - invokes open(). - */ - inline int initialized(void) { return initialized_; } - inline int error(void) { return error_; } - - /* - This is where the coolness lies. Most C++ folks are familiar - with "cout << some-data". It's a very handy and easy way to - toss data around. By adding these method calls, we're able - to do the same thing with a socket connection. - */ - Client & operator<<( ACE_SString & str ); - Client & operator<<( char * str ); - Client & operator<<( int n ); - -protected: - unsigned char initialized_; - unsigned char error_; - -}; - -/* - The basic constructor just sets our flags to reasonable values. - */ -Client::Client(void) -{ - initialized_ = 0; - error_ = 0; -} - -/* - This constructor also sets the flags but then calls open(). If the - open() fails, the flags will be set appropriately. Use the two inline - method calls initialized() and error() to check the object state after - using this constructor. - */ -Client::Client( const char * server, u_short port ) -{ - initialized_ = 0; - error_ = 0; - (void)open(server,port); -} - -/* - Open a connection to the server. This hides the use of ACE_SOCK_Connector - from our caller. Since our caller probably doesn't care *how* we connect, - this is a good thing. - */ -int Client::open( const char * server, u_short port ) -{ - /* - This is right out of Tutorial 3. The only thing we've added is to set - the initialized_ member variable on success. - */ - - ACE_SOCK_Connector connector; - ACE_INET_Addr addr (port, server); - - if (connector.connect (*this, addr) == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "open"), -1); - } - - initialized_ = 1; - - return(0); -} - -/* - The first of our put operators sends a simple string object to the peer. -*/ -Client & Client::operator<<( ACE_SString & str ) -{ - /* - We have to be able to allow: - server << foo << bar << stuff; - - To accomplish that, every << operator must check that the object is - in a valid state before doing work. - */ - - if( initialized() && ! error() ) - { - /* - Get the actual data held in the string object - */ - char * cp = str.rep(); - - /* - Send that data to the peer using send_n() as before. If we have - a problem, we'll set error_ so that subsequent << operations won't - try to use a broken stream. - */ - if( this->send_n(cp,strlen(cp)) == -1 ) - { - error_ = 1; - } - } - else - { - /* - Be sure that error_ is set if somebody tries to use us when - we're not initialized. - */ - error_ = 1; - } - - /* - We have to return a reference to ourselves to allow chaining of - put operations (eg -- "server << foo << bar"). Without the reference, - you would have to do each put operation as a statement. That's OK - but doesn't have the same feel as standard C++ iostreams. - */ - return *this ; -} - -/* -How do you put a char*? We'll take an easy way out and construct an ACE_SString -from the char* and then put that. It would have been more efficient to implement -this with the body of the operator<<(ACE_SString&) method and then express that -method in terms of this one. There's always more than one way to do things! - */ -Client & Client::operator<< ( char * str ) -{ - ACE_SString newStr(str); - - *this << newStr; - - return *this ; - - /* - Notice that we could have been really clever and done: - - return *this << ACE_SString(str); - - That kind of thing just makes debugging a pain though! - */ -} - -/* - ACE_SString and char* are both about the same thing. What do you do about - different datatypes though? - - Do the same thing we did with char* and convert it to ACE_SString where we - already have a << operator defined. - */ -Client & Client::operator<< ( int n ) -{ - /* - Create a character buffer large enough for the largest number. That's - a tough call but 1024 should be quite enough. - */ - char buf[1024]; - - /* - Put the number into our buffer... - */ - ACE_OS::sprintf(buf,"(%d)\n",n); - - /* - And create the ACE_SString that we know how to put. - */ - ACE_SString newStr(buf); - - /* - Send it and... - */ - *this << newStr; - - /* - return ourselves as usual. - */ - return *this; -} - - -/* - Now we pull it all together. Like Tutorial 3, we'll allow command line options. - */ -int main (int argc, char *argv[]) -{ - const char *server_host = argc > 1 ? argv[1] : ACE_DEFAULT_SERVER_HOST; - u_short server_port = argc > 2 ? ACE_OS::atoi (argv[2]) : ACE_DEFAULT_SERVER_PORT; - int max_iterations = argc > 3 ? ACE_OS::atoi (argv[3]) : 4; - - /* - Use the basic constructor since the other isn't really very safe. - */ - Client server; - - /* - Open the server connection. Notice how this is simpler than Tutorial 3 - since we only have to provide a host name and port value. - */ - if( server.open(server_host,server_port) == -1 ) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "open"), -1); - } - - for (int i = 0; i < max_iterations; i++) - { - /* - Tell the server which iteration we're on. No more mucking aroudn with - sprintf at this level! It's all hidden from us. - */ - server << "message = " << i+1; - - /* - Everything OK? - */ - if ( server.error() ) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "send"), -1); - } - else - { - ACE_OS::sleep (1); - } - } - - if (server.close () == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "close"), -1); - } - - return 0; -} diff --git a/docs/tutorials/004/page01.html b/docs/tutorials/004/page01.html deleted file mode 100644 index a6e69c5eb98..00000000000 --- a/docs/tutorials/004/page01.html +++ /dev/null @@ -1,316 +0,0 @@ -<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 004</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 004</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>A much more clever Client</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> - -<P>Ok, so the last time around, we learned how to create a simple client -that can send a chunk of data. A cooler thing to do is to overload -the C++ put operator (<<) to put some data for us. That's what -we're going to do this time. (This tutorial is actually where ACE_IOStream -was born.) - -<P> -<HR WIDTH="100%"> -<PRE>/* - We need the connector object & we also bring in a simple string class. - */ -#include "ace/SOCK_Connector.h" -#include "ace/SString.h" - -/* - In this tutorial, we extend SOCK_Stream by adding a few wrappers - around the send_n() method. - */ -class Client : public ACE_SOCK_Stream -{ - -public: - // Basic constructor - Client(void); - - /* - Construct and open() in one call. This isn't generally a good - idea because you don't have a clean way to inform the caller - when open() fails. (Unless you use C++ exceptions.) - */ - Client( const char * server, u_short port ); - - /* - Open the connection to the server. Notice that this mirrors - the use of ACE_SOCK_Connector. By providing our own open(), - we can hide the connector from our caller & make it's interaction - easier. - */ - int open( const char * server, u_short port ); - - /* - These are necessary if you're going to use the constructor that - invokes open(). - */ - inline int initialized(void) { return initialized_; } - inline int error(void) { return error_; } - - /* - This is where the coolness lies. Most C++ folks are familiar - with "cout << some-data". It's a very handy and easy way to - toss data around. By adding these method calls, we're able - to do the same thing with a socket connection. - */ - Client & operator<<( ACE_SString & str ); - Client & operator<<( char * str ); - Client & operator<<( int n ); - -protected: - unsigned char initialized_; - unsigned char error_; - -}; - -/* - The basic constructor just sets our flags to reasonable values. - */ -Client::Client(void) -{ - initialized_ = 0; - error_ = 0; -} - -/* - This constructor also sets the flags but then calls open(). If the - open() fails, the flags will be set appropriately. Use the two inline - method calls initialized() and error() to check the object state after - using this constructor. - */ -Client::Client( const char * server, u_short port ) -{ - initialized_ = 0; - error_ = 0; - (void)open(server,port); -} - -/* - Open a connection to the server. This hides the use of ACE_SOCK_Connector - from our caller. Since our caller probably doesn't care *how* we connect, - this is a good thing. - */ -int Client::open( const char * server, u_short port ) -{ - /* - This is right out of Tutorial 3. The only thing we've added is to set - the initialized_ member variable on success. - */ - - ACE_SOCK_Connector connector; - ACE_INET_Addr addr (port, server); - - if (connector.connect (*this, addr) == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "open"), -1); - } - - initialized_ = 1; - - return(0); -} - -/* - The first of our put operators sends a simple string object to the peer. -*/ -Client & Client::operator<<( ACE_SString & str ) -{ - /* - We have to be able to allow: - server << foo << bar << stuff; - - To accomplish that, every << operator must check that the object is - in a valid state before doing work. - */ - - if( initialized() && ! error() ) - { - /* - Get the actual data held in the string object - */ - char * cp = str.rep(); - - /* - Send that data to the peer using send_n() as before. If we have - a problem, we'll set error_ so that subsequent << operations won't - try to use a broken stream. - */ - if( this->send_n(cp,strlen(cp)) == -1 ) - { - error_ = 1; - } - } - else - { - /* - Be sure that error_ is set if somebody tries to use us when - we're not initialized. - */ - error_ = 1; - } - - /* - We have to return a reference to ourselves to allow chaining of - put operations (eg -- "server << foo << bar"). Without the reference, - you would have to do each put operation as a statement. That's OK - but doesn't have the same feel as standard C++ iostreams. - */ - return *this ; -} - -/* -How do you put a char*? We'll take an easy way out and construct an ACE_SString -from the char* and then put that. It would have been more efficient to implement -this with the body of the operator<<(ACE_SString&) method and then express that -method in terms of this one. There's always more than one way to do things! - */ -Client & Client::operator<< ( char * str ) -{ - ACE_SString newStr(str); - - *this << newStr; - - return *this ; - - /* - Notice that we could have been really clever and done: - - return *this << ACE_SString(str); - - That kind of thing just makes debugging a pain though! - */ -} - -/* - ACE_SString and char* are both about the same thing. What do you do about - different datatypes though? - - Do the same thing we did with char* and convert it to ACE_SString where we - already have a << operator defined. - */ -Client & Client::operator<< ( int n ) -{ - /* - Create a character buffer large enough for the largest number. That's - a tough call but 1024 should be quite enough. - */ - char buf[1024]; - - /* - Put the number into our buffer... - */ - ACE_OS::sprintf(buf,"(%d)\n",n); - - /* - And create the ACE_SString that we know how to put. - */ - ACE_SString newStr(buf); - - /* - Send it and... - */ - *this << newStr; - - /* - return ourselves as usual. - */ - return *this; -} - - -/* - Now we pull it all together. Like Tutorial 3, we'll allow command line options. - */ -int main (int argc, char *argv[]) -{ - const char *server_host = argc > 1 ? argv[1] : ACE_DEFAULT_SERVER_HOST; - u_short server_port = argc > 2 ? ACE_OS::atoi (argv[2]) : ACE_DEFAULT_SERVER_PORT; - int max_iterations = argc > 3 ? ACE_OS::atoi (argv[3]) : 4; - - /* - Use the basic constructor since the other isn't really very safe. - */ - Client server; - - /* - Open the server connection. Notice how this is simpler than Tutorial 3 - since we only have to provide a host name and port value. - */ - if( server.open(server_host,server_port) == -1 ) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "open"), -1); - } - - for (int i = 0; i < max_iterations; i++) - { - /* - Tell the server which iteration we're on. No more mucking aroudn with - sprintf at this level! It's all hidden from us. - */ - server << "message = " << i+1; - - /* - Everything OK? - */ - if ( server.error() ) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "send"), -1); - } - else - { - ACE_OS::sleep (1); - } - } - - if (server.close () == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "close"), -1); - } - - return 0; -}</PRE> - -<HR WIDTH="100%"> - -<P>Ok, now we're done with that. As you can see, it really isn't -so hard to create an object that makes sending data much more "natural" -than the typical send() or send_n() invocation. You can even build -up arbitrary objects & do some neat tricks with C++ templates to stream -their data out as well. (We may go into that a little later.) -Of course, writting the full implementation such that these streams are -interchangable with the standard C++ ostreams is quite a bit more difficult. -In addition, there are a lot of optimizations that this client would benefit -from! - -<P>As an exercise to the reader (don't you hate those!) I challenge you -to write the server side of this. You can take a look at IOStream_Test -in the ACE distribution if you get stuck... - -<P>If you want to compile it yourself, here's the <A HREF="client.cpp">source</A>, -the <A HREF="Makefile">Makefile</A>, -and <A HREF="00SetEnv">Environment -settings</A>. - -<P> -<HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial -Index</A>]</CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/005/00SetEnv b/docs/tutorials/005/00SetEnv deleted file mode 100644 index eca78e10c85..00000000000 --- a/docs/tutorials/005/00SetEnv +++ /dev/null @@ -1,2 +0,0 @@ -export ACE_ROOT=/local/src/ACE/ACE_wrappers -export LD_LIBRARY_PATH=$ACE_ROOT/ace:$LD_LIBRARY_PATH diff --git a/docs/tutorials/005/Makefile b/docs/tutorials/005/Makefile deleted file mode 100644 index c7635ba0fb3..00000000000 --- a/docs/tutorials/005/Makefile +++ /dev/null @@ -1,100 +0,0 @@ -#---------------------------------------------------------------------------- -# $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 - - # 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 - -.depend : # - touch .depend - -#---------------------------------------------------------------------------- -# 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/005/acceptor b/docs/tutorials/005/acceptor deleted file mode 100644 index 45409e4ec3e..00000000000 --- a/docs/tutorials/005/acceptor +++ /dev/null @@ -1,6 +0,0 @@ - -1. #include "ace/Acceptor.h" -2. #include "ace/SOCK_Acceptor.h" - -3. typedef ACE_Acceptor <Logging_Handler, ACE_SOCK_ACCEPTOR> Logging_Acceptor; - diff --git a/docs/tutorials/005/client_acceptor.h b/docs/tutorials/005/client_acceptor.h deleted file mode 100644 index 82416fa999c..00000000000 --- a/docs/tutorials/005/client_acceptor.h +++ /dev/null @@ -1,41 +0,0 @@ - -// $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; - -#endif // CLIENT_ACCEPTOR_H diff --git a/docs/tutorials/005/client_handler.cpp b/docs/tutorials/005/client_handler.cpp deleted file mode 100644 index 42c1b29d66f..00000000000 --- a/docs/tutorials/005/client_handler.cpp +++ /dev/null @@ -1,233 +0,0 @@ - -// $Id$ - -/* - In client_handler.h I alluded to the fact that we'll mess around with a - Client_Acceptor pointer. To do so, we need the Client_Acceptor object - declaration. - - We know that including client_handler.h is redundant because - client_acceptor.h includes it. Still, the sentry prevents double-inclusion - from causing problems and it's sometimes good to be explicit about what - we're using. - - On the other hand, we don't directly include any ACE header files here. - */ -#include "client_acceptor.h" -#include "client_handler.h" - -/* - Our constructor doesn't do anything. That's generally a good idea. Unless - you want to start throwing exceptions, there isn't a really good way to - indicate that a constructor has failed. If I had my way, I'd have a boolean - return code from it that would cause new to return 0 if I failed. Oh - well... - */ -Client_Handler::Client_Handler (void) -{ -} - -/* - Our destructor doesn't do anything either. That is also by design. - Remember, we really want folks to use destroy() to get rid of us. If that's - so, then there's nothing left to do when the destructor gets invoked. - */ -Client_Handler::~Client_Handler (void) -{ -} - -/* - The much talked about destroy() method! The reason I keep going on about - this is because it's just a Bad Idea (TM) to do real work inside of a - destructor. Although this method is void, it really should return - int so that it can tell the caller there was a problem. Even as - void you could at least throw an exception which you would never want - to do in a destructor. - */ -void Client_Handler::destroy (void) -{ - /* - We probably got here because of an error on the stream, so the peer - connection is probably already closed. Still... there are other ways to - get here and closing a closed peer doesn't hurt. - */ - this->peer ().close (); - - /* - Tell the reactor to forget all about us. Notice that we use the same args - here that we use in the open() method to register ourselves. In addition, - we use the DONT_CALL flag to prevent handle_close() being called. Since we - likely got here due to handle_close(), that could cause a bit of nasty - recursion! - */ - this->reactor ()->remove_handler (this, - ACE_Event_Handler:: READ_MASK | ACE_Event_Handler::DONT_CALL); - - /* - This is how we're able to tell folks not to use delete. By - deleting our own instance, we take care of memory leaks after ensuring - that the object is shut down correctly. - */ - delete this; -} - -/* - As mentioned before, the open() method is called by the Client_Acceptor when - a new client connection has been accepted. The Client_Acceptor instance - pointer is cast to a void* and given to us here. We'll use that to avoid - some global data... - */ -int Client_Handler::open (void *_acceptor) -{ - /* - Convert the void* to a Client_Acceptor*. You should probably use those - fancy new C++ cast operators but I can never remember how/when to do so. - Since you can cast just about anything around a void* without compiler - warnings be very sure of what you're doing when you do this kind of thing. - That's where the new-style cast operators can save you. - */ - Client_Acceptor *acceptor = (Client_Acceptor *) _acceptor; - - /* - Our reactor reference will be set when we register ourselves but I decided - to go ahead and set it here. No good reason really... - */ - this->reactor (acceptor->reactor ()); - - /* - We need this to store the address of the client that we are now connected - to. We'll use it later to display a debug message. - */ - ACE_INET_Addr addr; - - /* - Our ACE_Svc_Handler baseclass gives us the peer() method as a way to - access our underlying ACE_SOCK_Stream. On that object, we can invoke the - get_remote_addr() method to get get an ACE_INET_Addr having our client's - address information. As with most ACE methods, we'll get back (and return) - a -1 if there was any kind of error. Once we have the ACE_INET_Addr, we - can query it to find out the clien's host name, TCP/IP address, TCP/IP - port value and so forth. One word of warning: the get_host_name() - method of ACE_INET_Addr may return you an empty string if your name server - can't resolve it. On the other hand, get_host_addr() will always give you - the dotted-decimal string representing the TCP/IP address. - */ - if (this->peer ().get_remote_addr (addr) == -1) - { - return -1; - } - - /* - If we managed to get the client's address then we're connected to a real - and valid client. I suppose that in some cases, the client may connect - and disconnect so quickly that it is invalid by the time we get here. In - any case, the test above should always be done to ensure that the - connection is worth keeping. - - Now, regiser ourselves with a reactor and tell that reactor that we want - to be notified when there is something to read. Remember, we took our - reactor value from the acceptor which created us in the first place. - Since we're exploring a single-threaded implementation, this is the - correct thing to do. - */ - if (this->reactor ()->register_handler (this, ACE_Event_Handler::READ_MASK) == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) can't register with reactor\n"), -1); - } - - /* - Here, we use the ACE_INET_Addr object to print a message with the name of - the client we're connected to. Again, it is possible that you'll get an - empty string for the host name if your DNS isn't configured correctly or - if there is some other reason that a TCP/IP addreess cannot be converted - into a host name. - */ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) connected with %s\n", addr.get_host_name ())); - - /* - Always return zero on success. - */ - 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. - */ -int Client_Handler::handle_input (ACE_HANDLE _handle) -{ - /* - Some compilers don't like it when you fail to use a parameter. This macro - will keep 'em quiet for you. - */ - ACE_UNUSED_ARG (_handle); - - /* - Now, we create and initialize a buffer for receiving the data. Since this - is just a simple test app, we'll use a small buffer size. - */ - char buf[128]; - ACE_OS::memset (buf, 0, sizeof (buf)); - - /* - Invoke the process() method with a pointer to our data area. We'll let - that method worry about interfacing with the data. You might choose to go - ahead and read the data and then pass the result to process(). However, - application logic may require that you read a few bytes to determine what - else to read... It's best if we push that all into the application-logic - level. - */ - return this->process (buf, sizeof (buf)); -} - -/* - If we return -1 out of handle_input() or if the reactor sees other problems - with us then handle_close() will be called. It uses our destroy() method to - shut us down cleanly and get rid of our instance. - */ -int Client_Handler::handle_close (ACE_HANDLE _handle, ACE_Reactor_Mask _mask) -{ - ACE_UNUSED_ARG (_handle); - ACE_UNUSED_ARG (_mask); - - this->destroy (); - return 0; -} - -/* - And, at last, we get to the application-logic level. Out of everything - we've done so far, this is the only thing that really has anything to do - with what your application will do. In this method we will read and process - the client's data. In a real appliation, you will probably have a bit more - in main() to deal with command line options but after that point, all of the - action takes place here. - */ -int Client_Handler::process (char *_rdbuf, int _rdbuf_len) -{ - /* - Using the buffer provided for us, we read the data from the client. If - there is a read error (eg -- recv() returns -1) then it's a pretty good - bet that the connection is gone. Likewise, if we read zero bytes then - something wrong has happened. The reactor wouldn't have called us if - there wasn't some kind of read activity but there wouldn't be activity if - there were no bytes to read... - - On the other hand, if we got some data then we can display it in a debug - message for everyone to see. - */ - 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/005/client_handler.h b/docs/tutorials/005/client_handler.h deleted file mode 100644 index bdd8d903f6f..00000000000 --- a/docs/tutorials/005/client_handler.h +++ /dev/null @@ -1,103 +0,0 @@ - -// $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" - -/* - 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); - -protected: - - /* - 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); - - /* - 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); -}; - -#endif // CLIENT_HANDLER_H diff --git a/docs/tutorials/005/fix.Makefile b/docs/tutorials/005/fix.Makefile deleted file mode 100644 index e99c194114a..00000000000 --- a/docs/tutorials/005/fix.Makefile +++ /dev/null @@ -1,60 +0,0 @@ -#!/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/005/handler b/docs/tutorials/005/handler deleted file mode 100644 index d987f4c34ff..00000000000 --- a/docs/tutorials/005/handler +++ /dev/null @@ -1,81 +0,0 @@ - -1. #include "ace/SOCK_Acceptor.h" -2. #include "ace/Reactor.h" - - -3. class Logging_Handler : public ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH> - { - - public: - -4. Logging_Handler (void) - { - } - -5. virtual void destroy (void) - { -6. g_reactor->cancel_timer (this); -7. this->peer ().close (); - } - -8. virtual int open (void *) - { -9. ACE_INET_Addr addr; - -10. if (this->peer ().get_remote_addr (addr) == -1) -11. return -1; -12. else - { -13. ACE_OS::strncpy (this->peer_name_, addr.get_host_name (), MAXHOSTNAMELEN + 1); - -14. if (g_reactor->register_handler(this, ACE_Event_Handler::READ_MASK) == -1) -15. ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) can't register with reactor\n"), -1); - -16. else if (g_reactor->schedule_timer (this, (const void *) this, ACE_Time_Value (2), ACE_Time_Value (2)) == -1) -17. ACE_ERROR_RETURN ((LM_ERROR, "can'(%P|%t) t register with reactor\n"), -1); - -18. else -19. ACE_DEBUG ((LM_DEBUG, "(%P|%t) connected with %s\n", this->peer_name_)); - -20. return 0; - } - } - -21. virtual int close (u_long) - { -22. this->destroy (); -23. return 0; - } - - protected: - -24. virtual int handle_input (ACE_HANDLE) - { -25. char buf[128]; -26. memset(buf,0,sizeof(buf)); - -27. switch( this->peer().recv(buf,sizeof buf) ) - { -28. case -1: -29. ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) %p bad read\n", "client logger"), -1); -30. case 0: -31. ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) closing log daemon (fd = %d)\n", this->get_handle ()), -1); -32. default: -33. ACE_DEBUG ((LM_DEBUG, "(%P|%t) from client: %s",buf)); - } - -34. return 0; - } - -35. virtual int handle_timeout (const ACE_Time_Value &tv, const void *arg) - { -36. ACE_ASSERT (arg == this); -37. ACE_DEBUG ((LM_DEBUG, "(%P|%t) handling timeout from this = %u\n", this)); -38. return 0; - } - - private: - -39. char peer_name_[MAXHOSTNAMELEN + 1]; - - }; diff --git a/docs/tutorials/005/main b/docs/tutorials/005/main deleted file mode 100644 index 36c67561463..00000000000 --- a/docs/tutorials/005/main +++ /dev/null @@ -1,36 +0,0 @@ -1. #include "ace/Reactor.h" - -2. ACE_Reactor * g_reactor; - -3. static sig_atomic_t finished = 0; -4. extern "C" void handler (int) { finished = 1; } - -5. static const u_short PORT = ACE_DEFAULT_SERVER_PORT; - -6. int main (int argc, char *argv[]) - { -7. g_reactor = new ACE_Reactor; - - // Acceptor factory. -8. Logging_Acceptor peer_acceptor; - -9. if (peer_acceptor.open (ACE_INET_Addr (PORT)) == -1) -10. ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "open"), -1); - -11. else if (g_reactor->register_handler (&peer_acceptor, ACE_Event_Handler::READ_MASK) == -1) -12. ACE_ERROR_RETURN ((LM_ERROR, "registering service with ACE_Reactor\n"), -1); - -13. ACE_Sig_Action sa ((ACE_SignalHandler) handler, SIGINT); - - // Run forever, performing logging service. - -14. ACE_DEBUG ((LM_DEBUG, "(%P|%t) starting up server logging daemon\n")); - - // Perform logging service until QUIT_HANDLER receives SIGINT. -15. while ( !finished ) -16. g_reactor->handle_events (); - -17. ACE_DEBUG ((LM_DEBUG, "(%P|%t) shutting down server logging daemon\n")); - -18. return 0; - } diff --git a/docs/tutorials/005/page01.html b/docs/tutorials/005/page01.html deleted file mode 100644 index 60ae178abf3..00000000000 --- a/docs/tutorials/005/page01.html +++ /dev/null @@ -1,38 +0,0 @@ -<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="Billy Quinn"> - <META NAME="Description" CONTENT="A first step towards using ACE productively"> - <TITLE>ACE Tutorial 005</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 005</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>On the road to a multithreaded server</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> - -<P>In this tutorial, we're going to flash-back to the simple server we -created a while back. We'll create a very simple server where everything -takes place in one thread. Once we have a solid understanding there, -we'll move on to the next tutorial where we begin to introduce concurrency -concepts. - -<P>There are four C++ source files in this tutorial: server.cpp, -client_acceptor.h, client_handler.h and client_handler.cpp. I'll -talk about each of these in turn with the usual color commentary as we -go. In addition, I'll briefly discuss the Makefile and a short perl -script I've added. - -<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/005/page02.html b/docs/tutorials/005/page02.html deleted file mode 100644 index 7d268e8bd00..00000000000 --- a/docs/tutorials/005/page02.html +++ /dev/null @@ -1,201 +0,0 @@ -<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="Billy Quinn"> - <META NAME="Description" CONTENT="A first step towards using ACE productively"> - <TITLE>ACE Tutorial 005</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 005</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>On the road to a multithreaded server</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> - -<P>We begin with <I><A HREF="server.cpp">server.cpp</A></I>. - -<P> -<HR WIDTH="100%"> - -<P><FONT FACE="Arial,Helvetica">// $Id: server.cpp,v 1.5 1998/08/29 21:57:32 -jcej Exp $</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> We try to keep main() very -simple. One of the ways we do that is to push</FONT> -<BR><FONT FACE="Arial,Helvetica"> much of the complicated stuff -into worker objects. In this case, we only</FONT> -<BR><FONT FACE="Arial,Helvetica"> need to include the acceptor -header in our main source file. We let it</FONT> -<BR><FONT FACE="Arial,Helvetica"> worry about the "real work".</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</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"> As before, we create a simple -signal handler that will set our finished</FONT> -<BR><FONT FACE="Arial,Helvetica"> flag. There are, of -course, more elegant ways to handle program shutdown</FONT> -<BR><FONT FACE="Arial,Helvetica"> requests but that isn't really -our focus right now, so we'll just do the</FONT> -<BR><FONT FACE="Arial,Helvetica"> easiest thing.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT><FONT FACE="Arial,Helvetica"></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"> finished = 1;</FONT> -<BR><FONT FACE="Arial,Helvetica">}</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> A server has to listen for -clients at a known TCP/IP port. The default ACE</FONT> -<BR><FONT FACE="Arial,Helvetica"> port is 10002 (at least on -my system) and that's good enough for what we</FONT> -<BR><FONT FACE="Arial,Helvetica"> want to do here. Obviously, -a more robust application would take a command</FONT> -<BR><FONT FACE="Arial,Helvetica"> line parameter or read from -a configuration file or do some other clever</FONT> -<BR><FONT FACE="Arial,Helvetica"> thing. Just like the -signal handler above, though, that's what we want to</FONT> -<BR><FONT FACE="Arial,Helvetica"> focus on, so we're taking -the easy way out.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">static const u_short PORT = ACE_DEFAULT_SERVER_PORT;</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Finally, we get to main. -Some C++ compilers will complain loudly if your</FONT> -<BR><FONT FACE="Arial,Helvetica"> function signature doesn't -match the prototype. Even though we're not</FONT> -<BR><FONT FACE="Arial,Helvetica"> going to use the parameters, -we still have to specify them.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT><FONT FACE="Arial,Helvetica"></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"> In our earlier servers, we -used a global pointer to get to the reactor. I've</FONT> -<BR><FONT FACE="Arial,Helvetica"> never really liked that idea, -so I've moved it into main() this time. When</FONT> -<BR><FONT FACE="Arial,Helvetica"> we get to the Client_Handler -object you'll see how we manage to get a</FONT> -<BR><FONT FACE="Arial,Helvetica"> pointer back to this reactor.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_Reactor reactor;</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> The acceptor -will take care of letting clients connect to us. It will</FONT> -<BR><FONT FACE="Arial,Helvetica"> also arrange -for a Client_Handler to be created for each new client.</FONT> -<BR><FONT FACE="Arial,Helvetica"> Since we're only -going to listen at one TCP/IP port, we only need one</FONT> -<BR><FONT FACE="Arial,Helvetica"> acceptor. -If we wanted, though, we could create several of these and</FONT> -<BR><FONT FACE="Arial,Helvetica"> listen at several -ports. (That's what we would do if we wanted to rewrite</FONT> -<BR><FONT FACE="Arial,Helvetica"> inetd for -instance.)</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> Client_Acceptor peer_acceptor;</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Create an ACE_INET_Addr -that represents our endpoint of a connection. We</FONT> -<BR><FONT FACE="Arial,Helvetica"> then open our -acceptor object with that Addr. Doing so tells the acceptor</FONT> -<BR><FONT FACE="Arial,Helvetica"> where to listen -for connections. Servers generally listen at "well known"</FONT> -<BR><FONT FACE="Arial,Helvetica"> addresses. -If not, there must be some mechanism by which the client is</FONT> -<BR><FONT FACE="Arial,Helvetica"> informed of the -server's address.</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> Note how ACE_ERROR_RETURN -is used if we fail to open the acceptor. This</FONT> -<BR><FONT FACE="Arial,Helvetica"> technique is -used over and over again in our tutorials.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> if (peer_acceptor.open (ACE_INET_Addr -(PORT), &reactor) == -1)</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_ERROR_RETURN ((LM_ERROR, -"%p\n", "open"), -1);</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Here, we know -that the open was successful. If it had failed, we would</FONT> -<BR><FONT FACE="Arial,Helvetica"> have exited above. -A nice side-effect of the open() is that we're already</FONT> -<BR><FONT FACE="Arial,Helvetica"> registered with -the reactor we provided it.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Install our signal -handler. You can actually register signal handlers</FONT> -<BR><FONT FACE="Arial,Helvetica"> with the reactor. -You might do that when the signal handler is</FONT> -<BR><FONT FACE="Arial,Helvetica"> responsible for -performing "real" work. Our simple flag-setter doesn't</FONT> -<BR><FONT FACE="Arial,Helvetica"> justify deriving -from ACE_Event_Handler and providing a callback function</FONT> -<BR><FONT FACE="Arial,Helvetica"> though.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_Sig_Action sa ((ACE_SignalHandler) -handler, SIGINT);</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Like ACE_ERROR_RETURN, -the ACE_DEBUG macro gets used quite a bit. It's a</FONT> -<BR><FONT FACE="Arial,Helvetica"> handy way to -generate uniform debug output from your program.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_DEBUG ((LM_DEBUG, "(%P|%t) -starting up server daemon\n"));</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> This will loop -"forever" invoking the handle_events() method of our</FONT> -<BR><FONT FACE="Arial,Helvetica"> reactor. handle_events() -watches for activity on any registered handlers</FONT> -<BR><FONT FACE="Arial,Helvetica"> and invokes their -appropriate callbacks when necessary. Callback-driven</FONT> -<BR><FONT FACE="Arial,Helvetica"> programming is -a big thing in ACE, you should get used to it. If the</FONT> -<BR><FONT FACE="Arial,Helvetica"> signal handler -catches something, the finished flag will be set and we'll</FONT> -<BR><FONT FACE="Arial,Helvetica"> exit. Conveniently -enough, handle_events() is also interrupted by signals</FONT> -<BR><FONT FACE="Arial,Helvetica"> and will exit -back to the while() loop. (If you want your event loop to</FONT> -<BR><FONT FACE="Arial,Helvetica"> not be interrupted -by signals, checkout the <i>restart</i> flag on the</FONT> -<BR><FONT FACE="Arial,Helvetica"> open() method -of ACE_Reactor if you're interested.)</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> while (!finished)</FONT> -<BR><FONT FACE="Arial,Helvetica"> reactor.handle_events -();</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> ACE_DEBUG ((LM_DEBUG, "(%P|%t) shutting -down server daemon\n"));</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> return 0;</FONT> -<BR><FONT FACE="Arial,Helvetica">}</FONT> - -<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/005/page03.html b/docs/tutorials/005/page03.html deleted file mode 100644 index fb8acc3e913..00000000000 --- a/docs/tutorials/005/page03.html +++ /dev/null @@ -1,94 +0,0 @@ -<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="Billy Quinn"> - <META NAME="Description" CONTENT="A first step towards using ACE productively"> - <TITLE>ACE Tutorial 005</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 005</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>On the road to a multithreaded server</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> - -<P>Now, let's take a look at <I><A HREF="client_acceptor.h">client_acceptor.h</A></I>. -Since I went on about how it does all the work of letting clients connect -to us, it must be rather complext. Right? Wrong. - -<P>The more you use ACE, the more you'll find that they've already taken -care of most details for you. With respect to the acceptance of client -connections: there just aren't that many ways to do it! The -ACE team has chosen an approach and created a C++ template that does -all of the work for you. All you're required to do is provide it -with an object type to instantiate when a new connection arrives. - -<P> -<HR WIDTH="100%"> - -<P><FONT FACE="Arial,Helvetica">// $Id$</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"> The ACE_Acceptor<> template lives -in the ace/Acceptor.h header file.</FONT> -<BR><FONT FACE="Arial,Helvetica"> You'll find a very consitent naming -convention between the ACE objects</FONT> -<BR><FONT FACE="Arial,Helvetica"> and the headers where they can be -found. In general, the ACE object</FONT> -<BR><FONT FACE="Arial,Helvetica"> <I>ACE_Foobar</I> will be found -in <I>ace/Foobar.h</I>.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</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"> Since we want to work with sockets, -we'll need a SOCK_Acceptor to allow</FONT> -<BR><FONT FACE="Arial,Helvetica"> the clients to connect to us.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</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"> The Client_Handler object we develop -will be used to handle clients</FONT> -<BR><FONT FACE="Arial,Helvetica"> once they're connected. The -ACE_Acceptor<> template's first parameter</FONT> -<BR><FONT FACE="Arial,Helvetica"> requires such an object. In -some cases, you can get by with just a</FONT> -<BR><FONT FACE="Arial,Helvetica"> forward declaration on the class, -in others you have to have the whole</FONT> -<BR><FONT FACE="Arial,Helvetica"> thing.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</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"> Parameterize the ACE_Acceptor<> -such that it will listen for socket</FONT> -<BR><FONT FACE="Arial,Helvetica"> connection attempts and create Client_Handler -objects when they happen.</FONT> -<BR><FONT FACE="Arial,Helvetica"> In Tutorial 001, we wrote the basic -acceptor logic on our own before</FONT> -<BR><FONT FACE="Arial,Helvetica"> we realized that ACE_Acceptor<> -was available. You'll get spoiled using</FONT> -<BR><FONT FACE="Arial,Helvetica"> the ACE templates because they take -away a lot of the tedious details!</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">typedef ACE_Acceptor < Client_Handler, -ACE_SOCK_ACCEPTOR > Client_Acceptor;</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">#endif // CLIENT_ACCEPTOR_H</FONT> - -<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/005/page04.html b/docs/tutorials/005/page04.html deleted file mode 100644 index 2a526c22911..00000000000 --- a/docs/tutorials/005/page04.html +++ /dev/null @@ -1,192 +0,0 @@ -<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="Billy Quinn"> - <META NAME="Description" CONTENT="A first step towards using ACE productively"> - <TITLE>ACE Tutorial 005</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 005</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>On the road to a multithreaded server</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> - -<P>Ok, so we've got a main() loop that sets up the acceptor and we've seen -how easy it is to create the acceptor object. So far, we've hardly -written any code at all. Well, that's just about to change... - -<P>First, we look at <I><A HREF="client_handler.h">client_handler.h</A></I> -for the declaration of the Client_Handler object. Then we look at -the definition where all of the real work of the application takes place. - -<P> -<HR WIDTH="100%"> - -<P><FONT FACE="Arial,Helvetica">// $Id$</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"> Our client handler must exist -somewhere in the ACE_Event_Handler object</FONT> -<BR><FONT FACE="Arial,Helvetica"> hierarchy. This is -a requirement of the ACE_Reactor because it maintains</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_Event_Handler pointers -for each registered event handler. You could</FONT> -<BR><FONT FACE="Arial,Helvetica"> derive our Client_Handler -directly from ACE_Event_Handler but you still have</FONT> -<BR><FONT FACE="Arial,Helvetica"> to have an ACE_SOCK_Stream -for the actually connection. With a direct</FONT> -<BR><FONT FACE="Arial,Helvetica"> derivative of ACE_Event_Handler, -you'll have to contain and maintain an</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_SOCK_Stream instance -yourself. With ACE_Svc_Handler (which is a</FONT> -<BR><FONT FACE="Arial,Helvetica"> derivative of ACE_Event_Handler) -some of those details are handled for you.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</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">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Another feature of ACE_Svc_Handler -is it's ability to present the ACE_Task<></FONT> -<BR><FONT FACE="Arial,Helvetica"> interface as well. -That's what the ACE_NULL_SYNCH parameter below is all</FONT> -<BR><FONT FACE="Arial,Helvetica"> about. That's beyond -our scope here but we'll come back to it in the next</FONT> -<BR><FONT FACE="Arial,Helvetica"> tutorial when we start looking -at concurrency options.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">class Client_Handler : public ACE_Svc_Handler -< 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"> // Constructor...</FONT> -<BR><FONT FACE="Arial,Helvetica"> Client_Handler (void);</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> The destroy() -method is our preferred method of destruction. We could</FONT> -<BR><FONT FACE="Arial,Helvetica"> have overloaded -the <i>delete</i> operator but that is neither easy nor</FONT> -<BR><FONT FACE="Arial,Helvetica"> intuitive (at -least to me). Instead, we provide a new method of</FONT> -<BR><FONT FACE="Arial,Helvetica"> destruction and -we make our destructor protected so that only ourselves,</FONT> -<BR><FONT FACE="Arial,Helvetica"> our derivatives -and our friends can <i>delete</i> us. It's a nice</FONT> -<BR><FONT FACE="Arial,Helvetica"> compromise.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> void destroy (void);</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Most ACE objects -have an open() method. That's how you make them ready</FONT> -<BR><FONT FACE="Arial,Helvetica"> to do work. -ACE_Event_Handler has a virtual open() method which allows us</FONT> -<BR><FONT FACE="Arial,Helvetica"> to create this -overrride. ACE_Acceptor<> will invoke this method after</FONT> -<BR><FONT FACE="Arial,Helvetica"> creating a new -Client_Handler when a client connects. Notice that the</FONT> -<BR><FONT FACE="Arial,Helvetica"> parameter to -open() is a void*. It just so happens that the pointer</FONT> -<BR><FONT FACE="Arial,Helvetica"> points to the -acceptor which created us. You would like for the parameter</FONT> -<BR><FONT FACE="Arial,Helvetica"> to be an ACE_Acceptor<>* -but since ACE_Event_Handler is generic, that</FONT> -<BR><FONT FACE="Arial,Helvetica"> would tie it -too closely to the ACE_Acceptor<> set of objects. In our</FONT> -<BR><FONT FACE="Arial,Helvetica"> definition of -open() you'll see how we get around that.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> int open (void *_acceptor);</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> When there is -activity on a registered handler, the handle_input() method</FONT> -<BR><FONT FACE="Arial,Helvetica"> of the handler -will be invoked. If that method returns an error code (eg</FONT> -<BR><FONT FACE="Arial,Helvetica"> -- -1) then the -reactor will invoke handle_close() to allow the object to</FONT> -<BR><FONT FACE="Arial,Helvetica"> clean itself -up. Since an event handler can be registered for more than</FONT> -<BR><FONT FACE="Arial,Helvetica"> one type of callback, -the callback mask is provided to inform</FONT> -<BR><FONT FACE="Arial,Helvetica"> handle_close() -exactly which method failed. That way, you don't have to</FONT> -<BR><FONT FACE="Arial,Helvetica"> maintain state -information between your handle_* method calls. The _handle</FONT> -<BR><FONT FACE="Arial,Helvetica"> parameter is -explained below...</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> int handle_close (ACE_HANDLE _handle, -ACE_Reactor_Mask _mask);</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">protected:</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> When we register -with the reactor, we're going to tell it that we want to</FONT> -<BR><FONT FACE="Arial,Helvetica"> be notified of -READ events. When the reactor sees that there is read</FONT> -<BR><FONT FACE="Arial,Helvetica"> activity for -us, our handle_input() will be invoked. The <i>_handle</i></FONT> -<BR><FONT FACE="Arial,Helvetica"> provided is the -handle (file descriptor in Unix) of the actual connection</FONT> -<BR><FONT FACE="Arial,Helvetica"> causing the activity. -Since we're derived from ACE_Svc_Handler<> and it</FONT> -<BR><FONT FACE="Arial,Helvetica"> maintains it's -own peer (ACE_SOCK_Stream) object, this is redundant for</FONT> -<BR><FONT FACE="Arial,Helvetica"> us. However, -if we had been derived directly from ACE_Event_Handler, we</FONT> -<BR><FONT FACE="Arial,Helvetica"> may have chosen -not to contain the peer. In that case, the <i>_handle</i></FONT> -<BR><FONT FACE="Arial,Helvetica"> would be important -to us for reading the client's data.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> int handle_input (ACE_HANDLE _handle);</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> This has nothing -at all to do with ACE. I've added this here as a worker</FONT> -<BR><FONT FACE="Arial,Helvetica"> function which -I will call from handle_input(). That allows me to</FONT> -<BR><FONT FACE="Arial,Helvetica"> introduce concurrencly -in later tutorials with a no changes to the worker</FONT> -<BR><FONT FACE="Arial,Helvetica"> function. -You can think of process() as application-level code and</FONT> -<BR><FONT FACE="Arial,Helvetica"> everything elase -as application-framework code.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> int process (char *_rdbuf, int -_rdbuf_len);</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> We don't really -do anything in our destructor but we've declared it to be</FONT> -<BR><FONT FACE="Arial,Helvetica"> protected to -prevent casual deletion of this object. As I said above, I</FONT> -<BR><FONT FACE="Arial,Helvetica"> really would -prefer that everyone goes through the destroy() method to get</FONT> -<BR><FONT FACE="Arial,Helvetica"> rid of us.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> ~Client_Handler (void);</FONT> -<BR><FONT FACE="Arial,Helvetica">};</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">#endif // CLIENT_HANDLER_H</FONT> - -<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/005/page05.html b/docs/tutorials/005/page05.html deleted file mode 100644 index 117366b5af3..00000000000 --- a/docs/tutorials/005/page05.html +++ /dev/null @@ -1,385 +0,0 @@ -<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="Billy Quinn"> - <META NAME="Description" CONTENT="A first step towards using ACE productively"> - <TITLE>ACE Tutorial 005</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 005</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>On the road to a multithreaded server</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> - -<P>Now we're finally at <I><A HREF="client_handler.cpp">client_handler.cpp</A></I> -where we have to write some code. This file has more code than the -rest of the application all together. - -<P> -<HR WIDTH="100%"> -<BR> -<BR> <FONT FACE="Arial,Helvetica">// $Id$</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> In client_handler.h I alluded -to the fact that we'll mess around with a</FONT> -<BR><FONT FACE="Arial,Helvetica"> Client_Acceptor pointer. -To do so, we need the Client_Acceptor object</FONT> -<BR><FONT FACE="Arial,Helvetica"> declaration.</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> We know that including client_handler.h -is redundant because</FONT> -<BR><FONT FACE="Arial,Helvetica"> client_acceptor.h includes -it. Still, the sentry prevents double-inclusion</FONT> -<BR><FONT FACE="Arial,Helvetica"> from causing problems and -it's sometimes good to be explicit about what</FONT> -<BR><FONT FACE="Arial,Helvetica"> we're using.</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> On the other hand, we don't -directly include any ACE header files here.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><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"> Our constructor doesn't do -anything. That's generally a good idea. Unless</FONT> -<BR><FONT FACE="Arial,Helvetica"> you want to start throwing -exceptions, there isn't a really good way to</FONT> -<BR><FONT FACE="Arial,Helvetica"> indicate that a constructor -has failed. If I had my way, I'd have a boolean</FONT> -<BR><FONT FACE="Arial,Helvetica"> return code from it that -would cause <I>new</I> to return 0 if I failed. Oh</FONT> -<BR><FONT FACE="Arial,Helvetica"> well...</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><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"> Our destructor doesn't do -anything either. That is also by design.</FONT> -<BR><FONT FACE="Arial,Helvetica"> Remember, we really want -folks to use destroy() to get rid of us. If that's</FONT> -<BR><FONT FACE="Arial,Helvetica"> so, then there's nothing -left to do when the destructor gets invoked.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><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"> The much talked about destroy() -method! The reason I keep going on about</FONT> -<BR><FONT FACE="Arial,Helvetica"> this is because it's just -a Bad Idea (TM) to do real work inside of a</FONT> -<BR><FONT FACE="Arial,Helvetica"> destructor. Although -this method is <I>void</I>, it really should return</FONT> -<BR><FONT FACE="Arial,Helvetica"> <I>int</I> so that it can -tell the caller there was a problem. Even as</FONT> -<BR><FONT FACE="Arial,Helvetica"> <I>void</I> you could at -least throw an exception which you would never want</FONT> -<BR><FONT FACE="Arial,Helvetica"> to do in a destructor.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">void Client_Handler::destroy (void)</FONT> -<BR><FONT FACE="Arial,Helvetica">{</FONT> -<BR><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> We probably got -here because of an error on the stream, so the peer</FONT> -<BR><FONT FACE="Arial,Helvetica"> connection is -probably already closed. Still... there are other ways to</FONT> -<BR><FONT FACE="Arial,Helvetica"> get here and -closing a closed peer doesn't hurt.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> this->peer ().close ();</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Tell the reactor -to forget all about us. Notice that we use the same args</FONT> -<BR><FONT FACE="Arial,Helvetica"> here that we -use in the open() method to register ourselves. In addition,</FONT> -<BR><FONT FACE="Arial,Helvetica"> we use the DONT_CALL -flag to prevent handle_close() being called. Since we</FONT> -<BR><FONT FACE="Arial,Helvetica"> likely got here -due to handle_close(), that could cause a bit of nasty</FONT> -<BR><FONT FACE="Arial,Helvetica"> recursion!</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> this->reactor ()->remove_handler -(this,</FONT> -<BR><FONT FACE="Arial,Helvetica"> -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"> This is how we're -able to tell folks not to use <I>delete</I>. By deleting</FONT> -<BR><FONT FACE="Arial,Helvetica"> our own instance, -we take care of memory leaks after ensuring</FONT> -<BR><FONT FACE="Arial,Helvetica"> that the object -is shut down correctly.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> 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"> As mentioned before, the -open() method is called by the Client_Acceptor when</FONT> -<BR><FONT FACE="Arial,Helvetica"> a new client connection has -been accepted. The Client_Acceptor instance</FONT> -<BR><FONT FACE="Arial,Helvetica"> pointer is cast to a void* -and given to us here. We'll use that to avoid</FONT> -<BR><FONT FACE="Arial,Helvetica"> some global data...</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">int Client_Handler::open (void *_acceptor)</FONT> -<BR><FONT FACE="Arial,Helvetica">{</FONT> -<BR><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Convert the void* -to a Client_Acceptor*. You should probably use those</FONT> -<BR><FONT FACE="Arial,Helvetica"> fancy new C++ -cast operators but I can never remember how/when to do so.</FONT> -<BR><FONT FACE="Arial,Helvetica"> Since you can -cast just about anything around a void* without compiler</FONT> -<BR><FONT FACE="Arial,Helvetica"> warnings be very -sure of what you're doing when you do this kind of thing.</FONT> -<BR><FONT FACE="Arial,Helvetica"> That's where -the new-style cast operators can save you.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> Client_Acceptor *acceptor = (Client_Acceptor -*) _acceptor;</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Our reactor reference -will be set when we register ourselves but I decided</FONT> -<BR><FONT FACE="Arial,Helvetica"> to go ahead and -set it here. No good reason really...</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> this->reactor (acceptor->reactor -());</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> We need this -to store the address of the client that we are now connected</FONT> -<BR><FONT FACE="Arial,Helvetica"> to. We'll -use it later to display a debug message.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_INET_Addr addr;</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Our ACE_Svc_Handler -baseclass gives us the peer() method as a way to</FONT> -<BR><FONT FACE="Arial,Helvetica"> access our underlying -ACE_SOCK_Stream. On that object, we can invoke the</FONT> -<BR><FONT FACE="Arial,Helvetica"> get_remote_addr() -method to get get an ACE_INET_Addr having our client's</FONT> -<BR><FONT FACE="Arial,Helvetica"> address information. -As with most ACE methods, we'll get back (and return)</FONT> -<BR><FONT FACE="Arial,Helvetica"> a -1 if there -was any kind of error. Once we have the ACE_INET_Addr, we</FONT> -<BR><FONT FACE="Arial,Helvetica"> can query it -to find out the clien's host name, TCP/IP address, TCP/IP</FONT> -<BR><FONT FACE="Arial,Helvetica"> port value and -so forth. One word of warning: the get_host_name()</FONT> -<BR><FONT FACE="Arial,Helvetica"> method of ACE_INET_Addr -may return you an empty string if your name server</FONT> -<BR><FONT FACE="Arial,Helvetica"> can't resolve -it. On the other hand, get_host_addr() will always give you</FONT> -<BR><FONT FACE="Arial,Helvetica"> the dotted-decimal -string representing the TCP/IP address.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> if (this->peer ().get_remote_addr -(addr) == -1)</FONT> -<BR><FONT FACE="Arial,Helvetica"> {</FONT> -<BR><FONT FACE="Arial,Helvetica"> return --1;</FONT> -<BR><FONT FACE="Arial,Helvetica"> }</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> If we managed -to get the client's address then we're connected to a real</FONT> -<BR><FONT FACE="Arial,Helvetica"> and valid client. -I suppose that in some cases, the client may connect</FONT> -<BR><FONT FACE="Arial,Helvetica"> and disconnect -so quickly that it is invalid by the time we get here. In</FONT> -<BR><FONT FACE="Arial,Helvetica"> any case, the -test above should always be done to ensure that the</FONT> -<BR><FONT FACE="Arial,Helvetica"> connection is -worth keeping.</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> Now, regiser ourselves -with a reactor and tell that reactor that we want</FONT> -<BR><FONT FACE="Arial,Helvetica"> to be notified -when there is something to read. Remember, we took our</FONT> -<BR><FONT FACE="Arial,Helvetica"> reactor value -from the acceptor which created us in the first place.</FONT> -<BR><FONT FACE="Arial,Helvetica"> Since we're exploring -a single-threaded implementation, this is the</FONT> -<BR><FONT FACE="Arial,Helvetica"> correct thing -to do.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> if (this->reactor ()->register_handler -(this, ACE_Event_Handler::READ_MASK) == -1)</FONT> -<BR><FONT FACE="Arial,Helvetica"> {</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_ERROR_RETURN -((LM_ERROR, "(%P|%t) can't register with reactor\n"), -1);</FONT> -<BR><FONT FACE="Arial,Helvetica"> }</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Here, we use -the ACE_INET_Addr object to print a message with the name of</FONT> -<BR><FONT FACE="Arial,Helvetica"> the client we're -connected to. Again, it is possible that you'll get an</FONT> -<BR><FONT FACE="Arial,Helvetica"> empty string -for the host name if your DNS isn't configured correctly or</FONT> -<BR><FONT FACE="Arial,Helvetica"> if there is some -other reason that a TCP/IP addreess cannot be converted</FONT> -<BR><FONT FACE="Arial,Helvetica"> into a host name.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> 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"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Always return -zero on success.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> 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"> In the open() method, we -registered with the reactor and requested to be</FONT> -<BR><FONT FACE="Arial,Helvetica"> notified when there is data -to be read. When the reactor sees that activity</FONT> -<BR><FONT FACE="Arial,Helvetica"> it will invoke this handle_input() -method on us. As I mentioned, the _handle</FONT> -<BR><FONT FACE="Arial,Helvetica"> parameter isn't useful to -us but it narrows the list of methods the reactor</FONT> -<BR><FONT FACE="Arial,Helvetica"> has to worry about and the -list of possible virtual functions we would have</FONT> -<BR><FONT FACE="Arial,Helvetica"> to override.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</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"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Some compilers -don't like it when you fail to use a parameter. This macro</FONT> -<BR><FONT FACE="Arial,Helvetica"> will keep 'em -quiet for you.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_UNUSED_ARG (_handle);</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Now, we create -and initialize a buffer for receiving the data. Since this</FONT> -<BR><FONT FACE="Arial,Helvetica"> is just a simple -test app, we'll use a small buffer size.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> char buf[128];</FONT> -<BR><FONT FACE="Arial,Helvetica"> memset (buf, 0, sizeof (buf));</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Invoke the process() -method with a pointer to our data area. We'll let</FONT> -<BR><FONT FACE="Arial,Helvetica"> that method worry -about interfacing with the data. You might choose to go</FONT> -<BR><FONT FACE="Arial,Helvetica"> ahead and read -the data and then pass the result to process(). However,</FONT> -<BR><FONT FACE="Arial,Helvetica"> application logic -may require that you read a few bytes to determine what</FONT> -<BR><FONT FACE="Arial,Helvetica"> else to read... -It's best if we push that all into the application-logic</FONT> -<BR><FONT FACE="Arial,Helvetica"> level.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> return this->process (buf, sizeof -(buf));</FONT> -<BR><FONT FACE="Arial,Helvetica">}</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> If we return -1 out of handle_input() -or if the reactor sees other problems</FONT> -<BR><FONT FACE="Arial,Helvetica"> with us then handle_close() -will be called. It uses our destroy() method to</FONT> -<BR><FONT FACE="Arial,Helvetica"> shut us down cleanly and -get rid of our instance.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><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"> ACE_UNUSED_ARG (_handle);</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_UNUSED_ARG (_mask);</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> this->destroy ();</FONT> -<BR><FONT FACE="Arial,Helvetica"> 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"> And, at last, we get to the -application-logic level. Out of everything</FONT> -<BR><FONT FACE="Arial,Helvetica"> we've done so far, this is -the only thing that really has anything to do</FONT> -<BR><FONT FACE="Arial,Helvetica"> with what your application -will do. In this method we will read and process</FONT> -<BR><FONT FACE="Arial,Helvetica"> the client's data. -In a real appliation, you will probably have a bit more</FONT> -<BR><FONT FACE="Arial,Helvetica"> in main() to deal with command -line options but after that point, all of the</FONT> -<BR><FONT FACE="Arial,Helvetica"> action takes place here.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</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"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Using the buffer -provided for us, we read the data from the client. If</FONT> -<BR><FONT FACE="Arial,Helvetica"> there is a read -error (eg -- recv() returns -1) then it's a pretty good</FONT> -<BR><FONT FACE="Arial,Helvetica"> bet that the -connection is gone. Likewise, if we read zero bytes then</FONT> -<BR><FONT FACE="Arial,Helvetica"> something wrong -has happened. The reactor wouldn't have called us if</FONT> -<BR><FONT FACE="Arial,Helvetica"> there wasn't -some kind of read activity but there wouldn't be activity if</FONT> -<BR><FONT FACE="Arial,Helvetica"> there were no -bytes to read...</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> On the other hand, -if we got some data then we can display it in a debug</FONT> -<BR><FONT FACE="Arial,Helvetica"> message for everyone -to see.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> switch (this->peer ().recv (_rdbuf, -_rdbuf_len))</FONT> -<BR><FONT FACE="Arial,Helvetica"> {</FONT> -<BR><FONT FACE="Arial,Helvetica"> case -1:</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_ERROR_RETURN -((LM_ERROR, "(%P|%t) %p bad read\n", "client"), -1);</FONT> -<BR><FONT FACE="Arial,Helvetica"> case 0:</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_ERROR_RETURN -((LM_ERROR, "(%P|%t) closing daemon (fd = %d)\n", this->get_handle ()), --1);</FONT> -<BR><FONT FACE="Arial,Helvetica"> default:</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_DEBUG -((LM_DEBUG, "(%P|%t) from client: %s", _rdbuf));</FONT> -<BR><FONT FACE="Arial,Helvetica"> }</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> return 0;</FONT> -<BR><FONT FACE="Arial,Helvetica">}</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P> -<HR WIDTH="100%"> - -<P>That's the last of the C++ code. On the final two pages I'll -go over the Makefile and a short perl script I wrote to "assist" the -Makefile. Please... Continue... - -<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/005/page06.html b/docs/tutorials/005/page06.html deleted file mode 100644 index 95a341cf0ea..00000000000 --- a/docs/tutorials/005/page06.html +++ /dev/null @@ -1,195 +0,0 @@ -<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="Billy Quinn"> - <META NAME="Description" CONTENT="A first step towards using ACE productively"> - <TITLE>ACE Tutorial 005</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 005</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>On the road to a multithreaded server</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> - -<P>Before we go, I wanted you to see the <A HREF="Makefile">Makefile</A>. - -<P> -<HR WIDTH="100%"> -<BR> -<UL><FONT FACE="Arial,Helvetica">#----------------------------------------------------------------------------</FONT> -<BR><FONT FACE="Arial,Helvetica"># -$Id$</FONT> -<BR><FONT FACE="Arial,Helvetica">#----------------------------------------------------------------------------</FONT> - -<P><FONT FACE="Arial,Helvetica">#----------------------------------------------------------------------------</FONT> -<BR><FONT FACE="Arial,Helvetica"># -Local macros</FONT> -<BR><FONT FACE="Arial,Helvetica">#----------------------------------------------------------------------------</FONT> - -<P><FONT FACE="Arial,Helvetica"># You can generally find a Makefile in -the ACE examples, tests or the library</FONT> -<BR><FONT FACE="Arial,Helvetica"># itself that will satisfy our application -needs. This one was taken from</FONT> -<BR><FONT FACE="Arial,Helvetica"># one of the examples.</FONT> - -<P><FONT FACE="Arial,Helvetica"> -# Define the name of the binary we want to create. There has to be</FONT> -<BR><FONT FACE="Arial,Helvetica"> -# a CPP file $(BIN).cpp but it doesn't necessarily have to have your</FONT> -<BR><FONT FACE="Arial,Helvetica"> -# main() in it. Most of the time, though, it will.</FONT> -<BR><FONT FACE="Arial,Helvetica">BIN = server</FONT> - -<P><FONT FACE="Arial,Helvetica"> -# Few applications will have a single source file. We use the FILES</FONT> -<BR><FONT FACE="Arial,Helvetica"> -# macro to build up a list of additional files to compile. Notice</FONT> -<BR><FONT FACE="Arial,Helvetica"> -# that we leave off the extension just as with BIN</FONT> -<BR><FONT FACE="Arial,Helvetica">FILES =</FONT> -<BR><FONT FACE="Arial,Helvetica">FILES += client_handler</FONT> - -<P><FONT FACE="Arial,Helvetica"> -# The BUILD macro is used by the ACE makefiles. Basically, it tells</FONT> -<BR><FONT FACE="Arial,Helvetica"> -# the system what to build. I don't really know what VBIN is other</FONT> -<BR><FONT FACE="Arial,Helvetica"> -# than it is constructed from the value of BIN. Just go with it...</FONT> -<BR><FONT FACE="Arial,Helvetica">BUILD = $(VBIN)</FONT> - -<P><FONT FACE="Arial,Helvetica"> -# Here we use some GNU make extensions to build the SRC macro. Basically,</FONT> -<BR><FONT FACE="Arial,Helvetica"> -# we're just adding .cpp to the value of BIN and for each entry of the</FONT> -<BR><FONT FACE="Arial,Helvetica"> -# FILES macro.</FONT> -<BR><FONT FACE="Arial,Helvetica">SRC = $(addsuffix .cpp,$(BIN)) $(addsuffix -.cpp,$(FILES))</FONT> - -<P><FONT FACE="Arial,Helvetica"> -# This is used by my Indent target below. It's not a part of standard</FONT> -<BR><FONT FACE="Arial,Helvetica"> -# ACE and you don't need it yourself.</FONT> -<BR><FONT FACE="Arial,Helvetica">HDR = *.h</FONT> - -<P><FONT FACE="Arial,Helvetica">#----------------------------------------------------------------------------</FONT> -<BR><FONT FACE="Arial,Helvetica"># -Include macros and targets</FONT> -<BR><FONT FACE="Arial,Helvetica">#----------------------------------------------------------------------------</FONT> - -<P><FONT FACE="Arial,Helvetica"> -# This is where the real power lies! These included makefile components</FONT> -<BR><FONT FACE="Arial,Helvetica"> -# are similar to the C++ templates in ACE. That is, they do a tremendous</FONT> -<BR><FONT FACE="Arial,Helvetica"> -# amount of work for you and all you have to do is include them.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -# As a matter of fact, in our project, I created a single file named</FONT> -<BR><FONT FACE="Arial,Helvetica"> -# "app.mk" that includes all of these. Our project makefiles then -just</FONT> -<BR><FONT FACE="Arial,Helvetica"> -# need to include app.mk to get everything they need.</FONT> - -<P><FONT FACE="Arial,Helvetica">include $(ACE_ROOT)/include/makeinclude/wrapper_macros.GNU</FONT> -<BR><FONT FACE="Arial,Helvetica">include $(ACE_ROOT)/include/makeinclude/macros.GNU</FONT> -<BR><FONT FACE="Arial,Helvetica">include $(ACE_ROOT)/include/makeinclude/rules.common.GNU</FONT> -<BR><FONT FACE="Arial,Helvetica">include $(ACE_ROOT)/include/makeinclude/rules.nonested.GNU</FONT> -<BR><FONT FACE="Arial,Helvetica">include $(ACE_ROOT)/include/makeinclude/rules.lib.GNU</FONT> -<BR><FONT FACE="Arial,Helvetica">include $(ACE_ROOT)/include/makeinclude/rules.bin.GNU</FONT> -<BR><FONT FACE="Arial,Helvetica">include $(ACE_ROOT)/include/makeinclude/rules.local.GNU</FONT> - -<P><FONT FACE="Arial,Helvetica">#----------------------------------------------------------------------------</FONT> -<BR><FONT FACE="Arial,Helvetica"># -Local targets</FONT> -<BR><FONT FACE="Arial,Helvetica">#----------------------------------------------------------------------------</FONT> - -<P><FONT FACE="Arial,Helvetica"> -# Sometimes I like to reformat my code to make it more readable. -This is</FONT> -<BR><FONT FACE="Arial,Helvetica"> -# more useful for the comments than anything else. Unfortunately, -the</FONT> -<BR><FONT FACE="Arial,Helvetica"> -# "indent" program doesn't quite grok C++ so I have to post-process it's</FONT> -<BR><FONT FACE="Arial,Helvetica"> -# output just a bit.</FONT> -<BR><FONT FACE="Arial,Helvetica">Indent : #</FONT> -<BR><FONT FACE="Arial,Helvetica"> -for i in $(SRC) $(HDR) ; do \</FONT> -<BR><FONT FACE="Arial,Helvetica"> -indent -npsl -l80 -fca -fc1 -cli0 -cdb < $$i | \</FONT> -<BR><FONT FACE="Arial,Helvetica"> -sed -e 's/: :/::/g' \</FONT> -<BR><FONT FACE="Arial,Helvetica"> --e 's/^.*\(public:\)/\1/' \</FONT> -<BR><FONT FACE="Arial,Helvetica"> --e 's/^.*\(protected:\)/\1/' \</FONT> -<BR><FONT FACE="Arial,Helvetica"> --e 's/^.*\(private:\)/\1/' \</FONT> -<BR><FONT FACE="Arial,Helvetica"> --e 's/:\(public\)/ : \1/' \</FONT> -<BR><FONT FACE="Arial,Helvetica"> --e 's/:\(protected\)/ : \1/' \</FONT> -<BR><FONT FACE="Arial,Helvetica"> --e 's/:\(private\)/ : \1/' \</FONT> -<BR><FONT FACE="Arial,Helvetica"> -> $$i~ ;\</FONT> -<BR><FONT FACE="Arial,Helvetica"> -mv $$i~ $$i ;\</FONT> -<BR><FONT FACE="Arial,Helvetica"> -done</FONT> - -<P><FONT FACE="Arial,Helvetica"> -# One of the targets in the ACE makefiles is "depend". It will invoke</FONT> -<BR><FONT FACE="Arial,Helvetica"> -# your compiler in a way that will generate a list of dependencies for</FONT> -<BR><FONT FACE="Arial,Helvetica"> -# you. This is a great thing! Unfortunately, it puts all of -that mess</FONT> -<BR><FONT FACE="Arial,Helvetica"> -# directly into the Makefile. I prefer my Makefile to stay clean -and</FONT> -<BR><FONT FACE="Arial,Helvetica"> -# uncluttered. The perl script referenced here pulls the dependency</FONT> -<BR><FONT FACE="Arial,Helvetica"> -# stuff back out of the Makefile and into a file ".depend" which we then</FONT> -<BR><FONT FACE="Arial,Helvetica"> -# include just like the makefile components above.</FONT> -<BR><FONT FACE="Arial,Helvetica">Depend : depend</FONT> -<BR><FONT FACE="Arial,Helvetica"> -perl fix.Makefile</FONT> -<BR><FONT FACE="Arial,Helvetica"> </FONT> -<BR><FONT FACE="Arial,Helvetica">#----------------------------------------------------------------------------</FONT> -<BR><FONT FACE="Arial,Helvetica"># -Dependencies</FONT> -<BR><FONT FACE="Arial,Helvetica">#----------------------------------------------------------------------------</FONT> - -<P><FONT FACE="Arial,Helvetica"> -# Don't put anything below here. Between the "depend" target and -fix.Makefile</FONT> -<BR><FONT FACE="Arial,Helvetica"> -# it's guaranteed to be lost!</FONT> - -<P><FONT FACE="Arial,Helvetica"> -# This is inserted by the fix.Makefile script</FONT> -<BR><FONT FACE="Arial,Helvetica">include .depend</FONT></UL> - -<HR WIDTH="100%"> - -<P>Remember, make wants to see tabs leading all of the directives. -If you do a cut/paste job you'll need to convert all leading spaces to -tabs or make will be very unhappy with you. - -<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/005/page07.html b/docs/tutorials/005/page07.html deleted file mode 100644 index 069f94be956..00000000000 --- a/docs/tutorials/005/page07.html +++ /dev/null @@ -1,123 +0,0 @@ -<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="Billy Quinn"> - <META NAME="Description" CONTENT="A first step towards using ACE productively"> - <TITLE>ACE Tutorial 005</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 005</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>On the road to a multithreaded server</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> - -<P>And last (and probably least) is the <A HREF="fix.Makefile">perl script</A> -that pulls the dependency stuff out of Makefile and into .depend. - -<P> -<HR WIDTH="100%"> -<BR> <FONT FACE="Arial,Helvetica">#!/usr/bin/perl</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -# Open the Makefile that has been mangled by 'make depend'</FONT> -<BR><FONT FACE="Arial,Helvetica"> -# and suck it into a perl array.</FONT> -<BR><FONT FACE="Arial,Helvetica">open(IF,"<Makefile") || die;</FONT> -<BR><FONT FACE="Arial,Helvetica">@makefile = <IF>;</FONT> -<BR><FONT FACE="Arial,Helvetica">close(IF);</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -# Now open our .depend file and a temporary Makefile.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -# We'll split the original Makefile between these two.</FONT> -<BR><FONT FACE="Arial,Helvetica">open(DF,">.depend") || die;</FONT> -<BR><FONT FACE="Arial,Helvetica">open(MF,">Makefile.tmp") || die;</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -# For each line we read out of the original file...</FONT> -<BR><FONT FACE="Arial,Helvetica">foreach (@makefile) {</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -# If we're into the dependency section, write the line</FONT> -<BR><FONT FACE="Arial,Helvetica"> -# into the .depend file.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -#</FONT> -<BR><FONT FACE="Arial,Helvetica"> -if( $depend ) {</FONT> -<BR><FONT FACE="Arial,Helvetica"> -print DF $_;</FONT> -<BR><FONT FACE="Arial,Helvetica"> -}</FONT> -<BR><FONT FACE="Arial,Helvetica"> -else {</FONT> -<BR><FONT FACE="Arial,Helvetica"> -# If we haven't gotten to the dependency section yet</FONT> -<BR><FONT FACE="Arial,Helvetica"> -# then see if the current line is the separator that</FONT> -<BR><FONT FACE="Arial,Helvetica"> -# "make depend" causes to be inserted.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -#</FONT> -<BR><FONT FACE="Arial,Helvetica"> -if( m/^\Q# DO NOT DELETE THIS LINE -- g++dep uses it.\E/ ) {</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -# If so, change our "mode" and skip this line.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -++$depend;</FONT> -<BR><FONT FACE="Arial,Helvetica"> -next;</FONT> -<BR><FONT FACE="Arial,Helvetica"> -}</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -# Also skip the "include .depend" that we insert. If we</FONT> -<BR><FONT FACE="Arial,Helvetica"> -# don't do this, it is possible to have a bunch of these</FONT> -<BR><FONT FACE="Arial,Helvetica"> -# inserted into the output when we read an unmangled Makefile</FONT> -<BR><FONT FACE="Arial,Helvetica"> -next if( m/^include .depend/ );</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -# Print the non-dependency info to the temporary Makefile</FONT> -<BR><FONT FACE="Arial,Helvetica"> -print MF $_;</FONT> -<BR><FONT FACE="Arial,Helvetica"> -}</FONT> -<BR><FONT FACE="Arial,Helvetica">}</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"># Tell our new Makefile to include the -dependency file</FONT> -<BR><FONT FACE="Arial,Helvetica">print MF "include .depend\n";</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"># Close the two output files...</FONT> -<BR><FONT FACE="Arial,Helvetica">close(DF);</FONT> -<BR><FONT FACE="Arial,Helvetica">close(MF);</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"># Unlink (remove) the original Makefile -and rename our</FONT> -<BR><FONT FACE="Arial,Helvetica"># temporary file. There's obviously -room for error checking</FONT> -<BR><FONT FACE="Arial,Helvetica"># here but we've got the Makefile checked -into some revision</FONT> -<BR><FONT FACE="Arial,Helvetica"># control system anyway. Don't we?</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">unlink("Makefile");</FONT> -<BR><FONT FACE="Arial,Helvetica">rename("Makefile.tmp","Makefile");</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">exit(0);</FONT> - -<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/005/page08.html b/docs/tutorials/005/page08.html deleted file mode 100644 index 6cc18602049..00000000000 --- a/docs/tutorials/005/page08.html +++ /dev/null @@ -1,53 +0,0 @@ -<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="Billy Quinn"> - <META NAME="Description" CONTENT="A first step towards using ACE productively"> - <TITLE>ACE Tutorial 005</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 005</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>On the road to a multithreaded server</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> - -<P>That's it for Tutorial 5. In this tutorial we've built a single-threaded -reactor-based server. We've done a couple of things that aren't exactly -necessary for such an implementation but I plan to build on that as -we explore two other concurrency strategies: thread per connection -and thread pool. - -<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_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="fix.Makefile">fix.Makefile</A></LI> -</UL> - - -<P> -<HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial -Index</A>]</CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/005/server.brk b/docs/tutorials/005/server.brk deleted file mode 100644 index ba3d878a1da..00000000000 --- a/docs/tutorials/005/server.brk +++ /dev/null @@ -1,154 +0,0 @@ - -#include "ace/Acceptor.h" -#include "ace/SOCK_Acceptor.h" -#include "ace/Reactor.h" -#include "ace/Thread.h" - - -ACE_Reactor * g_reactor; - -static sig_atomic_t finished = 0; - -class Logging_Handler; - -extern "C" void handler (int) { finished = 1; } - - - -class Reactor_Derived : public ACE_Reactor -{ - -public : - Reactor_Derived() : () - { - counter = 0; - } - - virtual ~Reactor_Derived() - { - cout << "*****Calling the reactor destructor*****" << endl; - } - -private : - friend class Logging_Handler; - - // counter is used to keep track of the number of service handlers - // registered with this reactor (Surely theres a better way ;-) - int counter; -}; - -class Logging_Handler : public ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH> -{ - -public: - - Logging_Handler (void) { }; - - virtual void destroy (void) - { - if (this->thread_reactorP->remove_handler(this, - ACE_Event_Handler::READ_MASK | ACE_Event_Handler::DONT_CALL) == -1 - ) - ACE_ERROR_RETURN ((LM_ERROR, "can'(%P|%t) t remove service from reactor\n"), -1); - - // Decrement the handler tracking variable in the reactor to - // indicate this service handler has terminated - --thread_reactorP->counter; - - this->peer ().close (); - delete this; - } - - static void *run_thread(Logging_Handler *this_) - { - Reactor_Derived thread_reactor; - - this_->thread_reactorP = &thread_reactor; - - // Increment our handler counter to account for this service handler - ++thread_reactor.counter; - - if (thread_reactor.register_handler(this_, ACE_Event_Handler::READ_MASK) == -1) - ACE_ERROR_RETURN ((LM_ERROR,"can'(%P|%t) t register with reactor\n"), -1); - - while( thread_reactor.counter > 0 ) - { - // If thread_reactor.counter = 0 then we have no more service - // handlers connected to the reactor. We set a timeout value - // of 1 second so that the handle_events loop break out every - // second to check on the count ( because of it blocking - // even when there are no connections we need to do this) - thread_reactor.handle_events(ACE_Time_Value(1,0)); - } - } - - virtual int open (void *) - { - ACE_Thread::spawn(&Logging_Handler::run_thread,this); - return 0; - } - - virtual int close (u_long) - { - this->destroy (); - return 0; - } - -protected: - - virtual int handle_input (ACE_HANDLE) - { - char buf[128]; - memset(buf,0,sizeof(buf)); - - switch( this->peer().recv(buf,sizeof buf) ) - { - case -1: - ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) %p bad read\n", "client logger"), -1); - case 0: - ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) closing log daemon (fd = %d)\n", this->get_handle ()), -1); - default: - ACE_DEBUG ((LM_DEBUG, "(%p|%t) from client : %s",buf)); - } - - return 0; - } - - -private: - Reactor_Derived *thread_reactorP; -}; - - -typedef ACE_Acceptor <Logging_Handler, ACE_SOCK_ACCEPTOR> Logging_Acceptor; - - -static const u_short PORT = ACE_DEFAULT_SERVER_PORT; - -int main (int argc, char *argv[]) -{ - g_reactor = new ACE_Reactor; - - // Acceptor factory. - Logging_Acceptor peer_acceptor; - - if (peer_acceptor.open (ACE_INET_Addr (PORT)) == -1) - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "open"), -1); - - else if (g_reactor->register_handler (&peer_acceptor, ACE_Event_Handler::READ_MASK) == -1) - ACE_ERROR_RETURN ((LM_ERROR, "registering service with ACE_Reactor\n"), -1); - - ACE_Sig_Action sa ((ACE_SignalHandler) handler, SIGINT); - - // Run forever, performing logging service. - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) starting up server logging daemon\n")); - - // Perform logging service until QUIT_HANDLER receives SIGINT. - while ( !finished ) - g_reactor->handle_events (); - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) shutting down server logging daemon\n")); - - return 0; -} diff --git a/docs/tutorials/005/server.cpp b/docs/tutorials/005/server.cpp deleted file mode 100644 index ee46a9d2b57..00000000000 --- a/docs/tutorials/005/server.cpp +++ /dev/null @@ -1,121 +0,0 @@ -// $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); - - /* - Here, we know that the open was successful. If it had failed, we would - have exited above. A nice side-effect of the open() is that we're already - registered with the reactor we provided it. - */ - - /* - 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; -} - -#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION) -template class ACE_Acceptor <Client_Handler, ACE_SOCK_ACCEPTOR>; -template class ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH>; -#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA) -#pragma instantiate ACE_Acceptor <Client_Handler, ACE_SOCK_ACCEPTOR> -#pragma instantiate ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH> -#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */ diff --git a/docs/tutorials/006/Makefile b/docs/tutorials/006/Makefile deleted file mode 100644 index e75efab5b2f..00000000000 --- a/docs/tutorials/006/Makefile +++ /dev/null @@ -1,100 +0,0 @@ -#---------------------------------------------------------------------------- -# $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 - - # 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 - -.depend : # - touch .depend - -#---------------------------------------------------------------------------- -# 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/006/client_acceptor.h b/docs/tutorials/006/client_acceptor.h deleted file mode 100644 index b0944f3a316..00000000000 --- a/docs/tutorials/006/client_acceptor.h +++ /dev/null @@ -1,81 +0,0 @@ - -// $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; - -/* - Here, we use the parameterized ACE_Acceptor<> as a baseclass for our customized - Client_Acceptor object. I've done this so that we can provide it with our choice - of concurrency strategies when the object is created. Each Client_Handler it - creates will use this information to determine how to act. If we were going - to create a system that was always thread-per-connection, we would not have - bothered to extend Client_Acceptor. - */ -class Client_Acceptor : public Client_Acceptor_Base -{ -public: - /* - This is always a good idea. If nothing else, it makes your code more - orthogonal no matter what baseclasses your objects have. - */ - typedef Client_Acceptor_Base inherited; - - /* - Construct the object with the concurrency strategy. Since this tutorial - is focused on thread-per-connection, we make that the default. We could - have chosen to omitt the default and populate it in main() instead. - */ - Client_Acceptor( int _thread_per_connection = 1 ) - : thread_per_connection_(_thread_per_connection) - { - } - - /* - Return the value of our strategy flag. This is used by the Client_Handler - to decide how to act. If 'true' then the handler will behave in a - thread-per-connection manner. - */ - int thread_per_connection(void) - { return this->thread_per_connection_; } - -protected: - int thread_per_connection_; - -}; - -#endif // CLIENT_ACCEPTOR_H diff --git a/docs/tutorials/006/client_handler.cpp b/docs/tutorials/006/client_handler.cpp deleted file mode 100644 index 16fd098f12c..00000000000 --- a/docs/tutorials/006/client_handler.cpp +++ /dev/null @@ -1,313 +0,0 @@ - -// $Id$ - -/* - In client_handler.h I alluded to the fact that we'll mess around with a - Client_Acceptor pointer. To do so, we need the Client_Acceptor object - declaration. - - We know that including client_handler.h is redundant because - client_acceptor.h includes it. Still, the sentry prevents double-inclusion - from causing problems and it's sometimes good to be explicit about what - we're using. - - On the other hand, we don't directly include any ACE header files here. - */ -#include "client_acceptor.h" -#include "client_handler.h" - -/* - Our constructor doesn't do anything. That's generally a good idea. Unless - you want to start throwing exceptions, there isn't a really good way to - indicate that a constructor has failed. If I had my way, I'd have a boolean - return code from it that would cause new to return 0 if I failed. Oh - well... - */ -Client_Handler::Client_Handler (void) -{ -} - -/* - Our destructor doesn't do anything either. That is also by design. - Remember, we really want folks to use destroy() to get rid of us. If that's - so, then there's nothing left to do when the destructor gets invoked. - */ -Client_Handler::~Client_Handler (void) -{ -} - -/* - The much talked about destroy() method! The reason I keep going on about - this is because it's just a Bad Idea (TM) to do real work inside of a - destructor. Although this method is void, it really should return - int so that it can tell the caller there was a problem. Even as - void you could at least throw an exception which you would never want - to do in a destructor. - */ -void Client_Handler::destroy (void) -{ - /* - We probably got here because of an error on the stream, so the peer - connection is probably already closed. Still... there are other ways to - get here and closing a closed peer doesn't hurt. - */ - this->peer ().close (); - - /* - Tell the reactor to forget all about us. Notice that we use the same args - here that we use in the open() method to register ourselves. In addition, - we use the DONT_CALL flag to prevent handle_close() being called. Since we - likely got here due to handle_close(), that could cause a bit of nasty - recursion! - */ - this->reactor ()->remove_handler (this, - ACE_Event_Handler:: READ_MASK | ACE_Event_Handler::DONT_CALL); - - /* - This is how we're able to tell folks not to use delete. By - deleting our own instance, we take care of memory leaks after ensuring - that the object is shut down correctly. - */ - delete this; -} - -/* - As mentioned before, the open() method is called by the Client_Acceptor when - a new client connection has been accepted. The Client_Acceptor instance - pointer is cast to a void* and given to us here. We'll use that to avoid - some global data... - */ -int Client_Handler::open (void *_acceptor) -{ - /* - We need this to store the address of the client that we are now connected - to. We'll use it later to display a debug message. - */ - ACE_INET_Addr addr; - - /* - Our ACE_Svc_Handler baseclass gives us the peer() method as a way to - access our underlying ACE_SOCK_Stream. On that object, we can invoke the - get_remote_addr() method to get get an ACE_INET_Addr having our client's - address information. As with most ACE methods, we'll get back (and return) - a -1 if there was any kind of error. Once we have the ACE_INET_Addr, we - can query it to find out the clien's host name, TCP/IP address, TCP/IP - port value and so forth. One word of warning: the get_host_name() - method of ACE_INET_Addr may return you an empty string if your name server - can't resolve it. On the other hand, get_host_addr() will always give you - the dotted-decimal string representing the TCP/IP address. - */ - if (this->peer ().get_remote_addr (addr) == -1) - { - return -1; - } - - /* - Convert the void* to a Client_Acceptor*. You should probably use those - fancy new C++ cast operators but I can never remember how/when to do so. - Since you can cast just about anything around a void* without compiler - warnings be very sure of what you're doing when you do this kind of thing. - That's where the new-style cast operators can save you. - */ - Client_Acceptor *acceptor = (Client_Acceptor *) _acceptor; - - /* - Our Client_Acceptor is constructed with a concurrency strategy. Here, we - go back to it to find out what that strategy was. If thread-per-connection - was selected then we simply activate a thread for ourselves and exit. Our - svc() method will then begin executing in that thread. - - If we are told to use the single-threaded strategy, there is no difference - between this and the Tutorial 5 implementation. - */ - if( acceptor->thread_per_connection() ) - { - return this->activate(); - } - - /* - Our reactor reference will be set when we register ourselves but I decided - to go ahead and set it here. No good reason really... - */ - this->reactor (acceptor->reactor ()); - - /* - If we managed to get the client's address then we're connected to a real - and valid client. I suppose that in some cases, the client may connect - and disconnect so quickly that it is invalid by the time we get here. In - any case, the test above should always be done to ensure that the - connection is worth keeping. - - Now, regiser ourselves with a reactor and tell that reactor that we want - to be notified when there is something to read. Remember, we took our - reactor value from the acceptor which created us in the first place. - Since we're exploring a single-threaded implementation, this is the - correct thing to do. - */ - if (this->reactor ()->register_handler (this, ACE_Event_Handler::READ_MASK) == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) can't register with reactor\n"), -1); - } - - /* - Here, we use the ACE_INET_Addr object to print a message with the name of - the client we're connected to. Again, it is possible that you'll get an - empty string for the host name if your DNS isn't configured correctly or - if there is some other reason that a TCP/IP addreess cannot be converted - into a host name. - */ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) connected with %s\n", addr.get_host_name ())); - - /* - Always return zero on success. - */ - return 0; -} - -/* - As mentioned in the header, the typical way to close an object in a threaded - context is to invoke it's close() method. Since we already have a handle_close() - method built to cleanup after us, we'll just forward the request on to that - object. - */ -int Client_Handler::close(u_long flags) -{ - /* - Down in the depths of our baseclass, this will eventually cause us - to be destroyed. Since all of the destructors are virtual, everything - gets cleaned up nicely. - */ - this->handle_close(ACE_INVALID_HANDLE,0); - - /* - Don't forward the close() to the baseclass! handle_close() above has - already taken care of delete'ing. Forwarding close() would cause that - to happen again and things would get really ugly at that point! - */ - 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. - */ -int Client_Handler::handle_input (ACE_HANDLE _handle) -{ - /* - Some compilers don't like it when you fail to use a parameter. This macro - will keep 'em quiet for you. - */ - ACE_UNUSED_ARG (_handle); - - /* - Now, we create and initialize a buffer for receiving the data. Since this - is just a simple test app, we'll use a small buffer size. - */ - char buf[128]; - ACE_OS::memset (buf, 0, sizeof (buf)); - - /* - Invoke the process() method with a pointer to our data area. We'll let - that method worry about interfacing with the data. You might choose to go - ahead and read the data and then pass the result to process(). However, - application logic may require that you read a few bytes to determine what - else to read... It's best if we push that all into the application-logic - level. - */ - return this->process (buf, sizeof (buf)); -} - -/* - If we return -1 out of handle_input() or if the reactor sees other problems - with us then handle_close() will be called. It uses our destroy() method to - shut us down cleanly and get rid of our instance. - */ -int Client_Handler::handle_close (ACE_HANDLE _handle, ACE_Reactor_Mask _mask) -{ - ACE_UNUSED_ARG (_handle); - ACE_UNUSED_ARG (_mask); - - this->destroy (); - return 0; -} - -/* - The ACE_Svc_Handler<> is ultimately derived from ACE_Task<>. If you want to - create a multi-threaded application, these are your tools! Simply override - the svc() method in your derivative and arrange for your activate() method - to be called. The svc() method then executes in the new thread. - */ -int Client_Handler::svc(void) -{ - /* - Like handle_input(), we create a buffer for loading the data. Doing so - in handle_input() doesn't help any but there is a small performance increase - by doing this here: the buffer is created once when the thread is created - instead of for each invocation of process(). - */ - char buf[128]; - - // Forever... - while( 1 ) - { - // Clean the buffer... - ACE_OS::memset (buf, 0, sizeof (buf)); - - /* - Invoke the proces() method to read and process the data. This is - exactly the way it is used by handle_input(). That's the reason I - created process() in the first place: so that it can be used in either - concurrency strategy. Since process() has all of our application-level - logic, it's nice that it doesn't have to change when we decide to go - multi-threaded. - - Notice that since the recv() method call in process() blocks until - there is data ready, this thread doesn't consume any CPU time until - there is actually data sent from the client. - */ - if( this->process(buf,sizeof(buf)) == -1 ) - { - return(-1); - } - } - - return(0); -} - -/* - And, at last, we get to the application-logic level. Out of everything - we've done so far, this is the only thing that really has anything to do - with what your application will do. In this method we will read and process - the client's data. In a real appliation, you will probably have a bit more - in main() to deal with command line options but after that point, all of the - action takes place here. - */ -int Client_Handler::process (char *_rdbuf, int _rdbuf_len) -{ - /* - Using the buffer provided for us, we read the data from the client. If - there is a read error (eg -- recv() returns -1) then it's a pretty good - bet that the connection is gone. Likewise, if we read zero bytes then - something wrong has happened. The reactor wouldn't have called us if - there wasn't some kind of read activity but there wouldn't be activity if - there were no bytes to read... - - On the other hand, if we got some data then we can display it in a debug - message for everyone to see. - */ - 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/006/client_handler.h b/docs/tutorials/006/client_handler.h deleted file mode 100644 index d80c23e942d..00000000000 --- a/docs/tutorials/006/client_handler.h +++ /dev/null @@ -1,121 +0,0 @@ - -// $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" - -/* - 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. If our Client_Acceptor has chosen thread-per-connection then our - open() method will activate us into a thread. At that point, our svc() - method will execute. We still don't take advantage of the thiings - ACE_NULL_SYNCH exists for but stick around for Tutorial 7 and pay special - attention to the Thread_Pool object there for an explanation. - */ -class Client_Handler : public ACE_Svc_Handler < ACE_SOCK_STREAM, ACE_NULL_SYNCH > -{ -public: - typedef ACE_Svc_Handler < ACE_SOCK_STREAM, ACE_NULL_SYNCH > inherited; - - // 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 an ACE_Task<> object falls out of the svc() method, the framework - will call the close() method. That's where we want to cleanup ourselves - if we're running in either thread-per-connection or thread-pool mode. - */ - int close(u_long flags = 0); - - /* - 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); - -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); - - /* - 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); - - /* - 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(). As promised in Tutorial 5 - I will use this now to make it easier to switch between our two possible - concurrency strategies. - */ - 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); -}; - -#endif // CLIENT_HANDLER_H diff --git a/docs/tutorials/006/fix.Makefile b/docs/tutorials/006/fix.Makefile deleted file mode 100644 index e99c194114a..00000000000 --- a/docs/tutorials/006/fix.Makefile +++ /dev/null @@ -1,60 +0,0 @@ -#!/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/006/page01.html b/docs/tutorials/006/page01.html deleted file mode 100644 index cd20f343e91..00000000000 --- a/docs/tutorials/006/page01.html +++ /dev/null @@ -1,33 +0,0 @@ -<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 006</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Creating a thread-per-connection server</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> - -<P>In this tutorial, we're going to extend Tutorial 5 to create a thread-per-connection -server. This implementation will create a new thread for each client -which connects to us. The ACE_Reactor is still used but only for -accepting new connections. The Client_Handler objects won't be registered -with the reactor. Instead, they'll be responsible for monitoring -their peer() directly. - -<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/006/page02.html b/docs/tutorials/006/page02.html deleted file mode 100644 index 29d4c457ff1..00000000000 --- a/docs/tutorials/006/page02.html +++ /dev/null @@ -1,205 +0,0 @@ -<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 006</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Creating a thread-per-connection server</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> - -<P>Again, we begin with <A HREF="server.cpp">server.cpp.</A> If you -look closely you will see that the only difference between this and the -Tutorial 5 implementation is a single comment. - -<P> -<HR WIDTH="100%"><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">// $Id: server.cpp,v 1.1 1998/08/30 13:38:28 -jcej Exp $</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> We try to keep main() very -simple. One of the ways we do that is to push</FONT> -<BR><FONT FACE="Arial,Helvetica"> much of the complicated stuff -into worker objects. In this case, we only</FONT> -<BR><FONT FACE="Arial,Helvetica"> need to include the acceptor -header in our main source file. We let it</FONT> -<BR><FONT FACE="Arial,Helvetica"> worry about the "real work".</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</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"> As before, we create a simple -signal handler that will set our finished</FONT> -<BR><FONT FACE="Arial,Helvetica"> flag. There are, of -course, more elegant ways to handle program shutdown</FONT> -<BR><FONT FACE="Arial,Helvetica"> requests but that isn't really -our focus right now, so we'll just do the</FONT> -<BR><FONT FACE="Arial,Helvetica"> easiest thing.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT><FONT FACE="Arial,Helvetica"></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"> finished = 1;</FONT> -<BR><FONT FACE="Arial,Helvetica">}</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> A server has to listen for -clients at a known TCP/IP port. The default ACE</FONT> -<BR><FONT FACE="Arial,Helvetica"> port is 10002 (at least on -my system) and that's good enough for what we</FONT> -<BR><FONT FACE="Arial,Helvetica"> want to do here. Obviously, -a more robust application would take a command</FONT> -<BR><FONT FACE="Arial,Helvetica"> line parameter or read from -a configuration file or do some other clever</FONT> -<BR><FONT FACE="Arial,Helvetica"> thing. Just like the -signal handler above, though, that's what we want to</FONT> -<BR><FONT FACE="Arial,Helvetica"> focus on, so we're taking -the easy way out.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">static const u_short PORT = ACE_DEFAULT_SERVER_PORT;</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Finally, we get to main. -Some C++ compilers will complain loudly if your</FONT> -<BR><FONT FACE="Arial,Helvetica"> function signature doesn't -match the prototype. Even though we're not</FONT> -<BR><FONT FACE="Arial,Helvetica"> going to use the parameters, -we still have to specify them.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT><FONT FACE="Arial,Helvetica"></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"> In our earlier servers, we -used a global pointer to get to the reactor. I've</FONT> -<BR><FONT FACE="Arial,Helvetica"> never really liked that idea, -so I've moved it into main() this time. When</FONT> -<BR><FONT FACE="Arial,Helvetica"> we get to the Client_Handler -object you'll see how we manage to get a</FONT> -<BR><FONT FACE="Arial,Helvetica"> pointer back to this reactor.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_Reactor reactor;</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> The acceptor -will take care of letting clients connect to us. It will</FONT> -<BR><FONT FACE="Arial,Helvetica"> also arrange -for a Client_Handler to be created for each new client.</FONT> -<BR><FONT FACE="Arial,Helvetica"> Since we're only -going to listen at one TCP/IP port, we only need one</FONT> -<BR><FONT FACE="Arial,Helvetica"> acceptor. -If we wanted, though, we could create several of these and</FONT> -<BR><FONT FACE="Arial,Helvetica"> listen at several -ports. (That's what we would do if we wanted to rewrite</FONT> -<BR><FONT FACE="Arial,Helvetica"> inetd for -instance.)</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> Client_Acceptor peer_acceptor;</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Create an ACE_INET_Addr -that represents our endpoint of a connection. We</FONT> -<BR><FONT FACE="Arial,Helvetica"> then open our -acceptor object with that Addr. Doing so tells the acceptor</FONT> -<BR><FONT FACE="Arial,Helvetica"> where to listen -for connections. Servers generally listen at "well known"</FONT> -<BR><FONT FACE="Arial,Helvetica"> addresses. -If not, there must be some mechanism by which the client is</FONT> -<BR><FONT FACE="Arial,Helvetica"> informed of the -server's address.</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> Note how ACE_ERROR_RETURN -is used if we fail to open the acceptor. This</FONT> -<BR><FONT FACE="Arial,Helvetica"> technique is -used over and over again in our tutorials.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> if (peer_acceptor.open (ACE_INET_Addr -(PORT), &reactor) == -1)</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_ERROR_RETURN ((LM_ERROR, -"%p\n", "open"), -1);</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> As with Tutorial -5, we know that we're now registered with our reactor</FONT> -<BR><FONT FACE="Arial,Helvetica"> so we don't have -to mess with that step.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Install our signal -handler. You can actually register signal handlers</FONT> -<BR><FONT FACE="Arial,Helvetica"> with the reactor. -You might do that when the signal handler is</FONT> -<BR><FONT FACE="Arial,Helvetica"> responsible for -performing "real" work. Our simple flag-setter doesn't</FONT> -<BR><FONT FACE="Arial,Helvetica"> justify deriving -from ACE_Event_Handler and providing a callback function</FONT> -<BR><FONT FACE="Arial,Helvetica"> though.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_Sig_Action sa ((ACE_SignalHandler) -handler, SIGINT);</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Like ACE_ERROR_RETURN, -the ACE_DEBUG macro gets used quite a bit. It's a</FONT> -<BR><FONT FACE="Arial,Helvetica"> handy way to -generate uniform debug output from your program.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_DEBUG ((LM_DEBUG, "(%P|%t) -starting up server daemon\n"));</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> This will loop -"forever" invoking the handle_events() method of our</FONT> -<BR><FONT FACE="Arial,Helvetica"> reactor. handle_events() -watches for activity on any registered handlers</FONT> -<BR><FONT FACE="Arial,Helvetica"> and invokes their -appropriate callbacks when necessary. Callback-driven</FONT> -<BR><FONT FACE="Arial,Helvetica"> programming is -a big thing in ACE, you should get used to it. If the</FONT> -<BR><FONT FACE="Arial,Helvetica"> signal handler -catches something, the finished flag will be set and we'll</FONT> -<BR><FONT FACE="Arial,Helvetica"> exit. Conveniently -enough, handle_events() is also interrupted by signals</FONT> -<BR><FONT FACE="Arial,Helvetica"> and will exit -back to the while() loop. (If you want your event loop to</FONT> -<BR><FONT FACE="Arial,Helvetica"> not be interrupted -by signals, checkout the <i>restart</i> flag on the</FONT> -<BR><FONT FACE="Arial,Helvetica"> open() method -of ACE_Reactor if you're interested.)</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> while (!finished)</FONT> -<BR><FONT FACE="Arial,Helvetica"> reactor.handle_events -();</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> ACE_DEBUG ((LM_DEBUG, "(%P|%t) shutting -down server daemon\n"));</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> return 0;</FONT> -<BR><FONT FACE="Arial,Helvetica">}</FONT> - -<P> -<HR WIDTH="100%"> - -<P>Let's move along and see what happend to the Client_Acceptor. - -<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/006/page03.html b/docs/tutorials/006/page03.html deleted file mode 100644 index b31b18aeac2..00000000000 --- a/docs/tutorials/006/page03.html +++ /dev/null @@ -1,167 +0,0 @@ -<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 006</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Creating a thread-per-connection server</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> - -<P>In <A HREF="client_acceptor.h">client_acceptor.h</A>, we've extended -our object just a bit. The primary reason is to allow us to select -the previous single-threaded implementation or our new thread-per-connection -implementation. Client_Acceptor itself doesn't use this information -but makes it available to the Client_Handler objects it creates. -If we wanted a single-strategy implementation, we would have made no changes -to the Tutorial 5 version of this file. - -<P> -<HR WIDTH="100%"> - -<P><FONT FACE="Arial,Helvetica">// $Id: client_acceptor.h,v 1.1 1998/08/30 -13:38:27 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"> The ACE_Acceptor<> template -lives in the ace/Acceptor.h header file. You'll</FONT> -<BR><FONT FACE="Arial,Helvetica"> find a very consitent naming -convention between the ACE objects and the</FONT> -<BR><FONT FACE="Arial,Helvetica"> headers where they can be -found. In general, the ACE object ACE_Foobar will</FONT> -<BR><FONT FACE="Arial,Helvetica"></FONT> <FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> be found in ace/Foobar.h.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</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"> Since we want to work with -sockets, we'll need a SOCK_Acceptor to allow the</FONT> -<BR><FONT FACE="Arial,Helvetica"> clients to connect to us.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</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"> The Client_Handler object -we develop will be used to handle clients once</FONT> -<BR><FONT FACE="Arial,Helvetica"> they're connected. -The ACE_Acceptor<> template's first parameter requires</FONT> -<BR><FONT FACE="Arial,Helvetica"> such an object. In -some cases, you can get by with just a forward</FONT> -<BR><FONT FACE="Arial,Helvetica"> declaration on the class, -in others you have to have the whole thing.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</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"> Parameterize the ACE_Acceptor<> -such that it will listen for socket</FONT> -<BR><FONT FACE="Arial,Helvetica"> connection attempts and create -Client_Handler objects when they happen. In</FONT> -<BR><FONT FACE="Arial,Helvetica"> Tutorial 001, we wrote the -basic acceptor logic on our own before we</FONT> -<BR><FONT FACE="Arial,Helvetica"> realized that ACE_Acceptor<> -was available. You'll get spoiled using the</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE templates because they -take away a lot of the tedious details!</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">typedef ACE_Acceptor < Client_Handler, -ACE_SOCK_ACCEPTOR > Client_Acceptor_Base;</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Here, we use the parameterized -ACE_Acceptor<> as a baseclass for our customized</FONT> -<BR><FONT FACE="Arial,Helvetica"> Client_Acceptor object. -I've done this so that we can provide it with our choice</FONT> -<BR><FONT FACE="Arial,Helvetica"> of concurrency strategies -when the object is created. Each Client_Handler it</FONT> -<BR><FONT FACE="Arial,Helvetica"> creates will use this information -to determine how to act. If we were going</FONT> -<BR><FONT FACE="Arial,Helvetica"> to create a system that was -always thread-per-connection, we would not have</FONT> -<BR><FONT FACE="Arial,Helvetica"> bothered to extend -Client_Acceptor.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</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"> -/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -This is always a good idea. If nothing else, it makes your code more</FONT> -<BR><FONT FACE="Arial,Helvetica"> -orthogonal no matter what baseclasses your objects have.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -*/</FONT> -<BR><FONT FACE="Arial,Helvetica"> -typedef Client_Acceptor_Base inherited;</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -Construct the object with the concurrency strategy. Since this tutorial</FONT> -<BR><FONT FACE="Arial,Helvetica"> -is focused on thread-per-connection, we make that the default. We -could</FONT> -<BR><FONT FACE="Arial,Helvetica"> -have chosen to omitt the default and populate it in main() instead.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -*/</FONT> -<BR><FONT FACE="Arial,Helvetica"> -Client_Acceptor( int _thread_per_connection = 1 )</FONT> -<BR><FONT FACE="Arial,Helvetica"> -: thread_per_connection_(_thread_per_connection)</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"> -Return the value of our strategy flag. This is used by the Client_Handler</FONT> -<BR><FONT FACE="Arial,Helvetica"> -to decide how to act. If 'true' then the handler will behave in a</FONT> -<BR><FONT FACE="Arial,Helvetica"> -thread-per-connection manner.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -*/</FONT> -<BR><FONT FACE="Arial,Helvetica"> -int thread_per_connection(void)</FONT> -<BR><FONT FACE="Arial,Helvetica"> -{ return this->thread_per_connection_; }</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">protected:</FONT> -<BR><FONT FACE="Arial,Helvetica"> -int thread_per_connection_;</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">};</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">#endif // CLIENT_ACCEPTOR_H</FONT> - -<P> -<HR WIDTH="100%"> - -<P>Ok, so far we haven't done much to change our concurrency strategy. -Let's move on to the Client_Handler and see if it has changed any. - -<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/006/page04.html b/docs/tutorials/006/page04.html deleted file mode 100644 index 7cdb48180af..00000000000 --- a/docs/tutorials/006/page04.html +++ /dev/null @@ -1,223 +0,0 @@ -<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 006</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Creating a thread-per-connection server</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> - -<P><A HREF="client_handler.h">client_handler.h</A> -shows a few more changes than the previous sources. The important -change is the addition of a svc() method where our connection thread will -exist. - -<P> -<HR WIDTH="100%"> - -<P><FONT FACE="Arial,Helvetica">// $Id: client_handler.h,v 1.1 1998/08/30 -23:47:13 schmidt 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"> Our client handler must exist -somewhere in the ACE_Event_Handler object</FONT> -<BR><FONT FACE="Arial,Helvetica"> hierarchy. This is -a requirement of the ACE_Reactor because it maintains</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_Event_Handler pointers -for each registered event handler. You could</FONT> -<BR><FONT FACE="Arial,Helvetica"> derive our Client_Handler -directly from ACE_Event_Handler but you still have</FONT> -<BR><FONT FACE="Arial,Helvetica"> to have an ACE_SOCK_Stream -for the actually connection. With a direct</FONT> -<BR><FONT FACE="Arial,Helvetica"> derivative of ACE_Event_Handler, -you'll have to contain and maintain an</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_SOCK_Stream instance -yourself. With ACE_Svc_Handler (which is a</FONT> -<BR><FONT FACE="Arial,Helvetica"> derivative of ACE_Event_Handler) -some of those details are handled for you.</FONT> -<BR><FONT FACE="Arial,Helvetica"> </FONT> -<BR><FONT FACE="Arial,Helvetica"> */</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">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Another feature of ACE_Svc_Handler -is it's ability to present the ACE_Task<></FONT> -<BR><FONT FACE="Arial,Helvetica"> interface as well. -That's what the ACE_NULL_SYNCH parameter below is all</FONT> -<BR><FONT FACE="Arial,Helvetica"> about. If our Client_Acceptor -has chosen thread-per-connection then our</FONT> -<BR><FONT FACE="Arial,Helvetica"> open() method will activate -us into a thread. At that point, our svc()</FONT> -<BR><FONT FACE="Arial,Helvetica"> method will execute. -We still don't take advantage of the thiings</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_NULL_SYNCH exists for -but stick around for Tutorial 7 and pay special</FONT> -<BR><FONT FACE="Arial,Helvetica"> attention to the Thread_Pool -object there for an explanation.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">class Client_Handler : public ACE_Svc_Handler -< 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"> // Constructor...</FONT> -<BR><FONT FACE="Arial,Helvetica"> Client_Handler (void);</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> The destroy() -method is our preferred method of destruction. We could</FONT> -<BR><FONT FACE="Arial,Helvetica"> have overloaded -the delete operator but that is neither easy nor</FONT> -<BR><FONT FACE="Arial,Helvetica"> intuitive (at -least to me). Instead, we provide a new method of</FONT> -<BR><FONT FACE="Arial,Helvetica"> destruction and -we make our destructor protected so that only ourselves,</FONT> -<BR><FONT FACE="Arial,Helvetica"> our derivatives -and our friends can delete us. It's a nice</FONT> -<BR><FONT FACE="Arial,Helvetica"> compromise.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> void destroy (void);</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Most ACE objects -have an open() method. That's how you make them ready</FONT> -<BR><FONT FACE="Arial,Helvetica"> to do work. -ACE_Event_Handler has a virtual open() method which allows us</FONT> -<BR><FONT FACE="Arial,Helvetica"> to create this -overrride. ACE_Acceptor<> will invoke this method after</FONT> -<BR><FONT FACE="Arial,Helvetica"> creating a new -Client_Handler when a client connects. Notice that the</FONT> -<BR><FONT FACE="Arial,Helvetica"> parameter to -open() is a void*. It just so happens that the pointer</FONT> -<BR><FONT FACE="Arial,Helvetica"> points to the -acceptor which created us. You would like for the parameter</FONT> -<BR><FONT FACE="Arial,Helvetica"> to be an ACE_Acceptor<>* -but since ACE_Event_Handler is generic, that</FONT> -<BR><FONT FACE="Arial,Helvetica"> would tie it -too closely to the ACE_Acceptor<> set of objects. In our</FONT> -<BR><FONT FACE="Arial,Helvetica"> definition of -open() you'll see how we get around that.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> int open (void *_acceptor);</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> When an ACE_Task<> -object falls out of the svc() method, the framework</FONT> -<BR><FONT FACE="Arial,Helvetica"> will call the -close() method. That's where we want to cleanup ourselves</FONT> -<BR><FONT FACE="Arial,Helvetica"> if we're running -in either thread-per-connection or thread-pool mode.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> int close(u_long flags = 0);</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> When there is -activity on a registered handler, the handle_input() method</FONT> -<BR><FONT FACE="Arial,Helvetica"> of the handler -will be invoked. If that method returns an error code (eg</FONT> -<BR><FONT FACE="Arial,Helvetica"> -- -1) then the -reactor will invoke handle_close() to allow the object to</FONT> -<BR><FONT FACE="Arial,Helvetica"> clean itself -up. Since an event handler can be registered for more than</FONT> -<BR><FONT FACE="Arial,Helvetica"> one type of callback, -the callback mask is provided to inform</FONT> -<BR><FONT FACE="Arial,Helvetica"> handle_close() -exactly which method failed. That way, you don't have to</FONT> -<BR><FONT FACE="Arial,Helvetica"> maintain state -information between your handle_* method calls. The _handle</FONT> -<BR><FONT FACE="Arial,Helvetica"> parameter is -explained below...</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> int handle_close (ACE_HANDLE _handle, -ACE_Reactor_Mask _mask);</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">protected:</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> If the Client_Acceptor -which created us has chosen a thread-per-connection</FONT> -<BR><FONT FACE="Arial,Helvetica"> strategy then -our open() method will activate us into a dedicate thread.</FONT> -<BR><FONT FACE="Arial,Helvetica"> The svc() method -will then execute in that thread performing some of the</FONT> -<BR><FONT FACE="Arial,Helvetica"> functions we -used to leave up to the reactor.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> int svc(void);</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> When we register -with the reactor, we're going to tell it that we want to</FONT> -<BR><FONT FACE="Arial,Helvetica"> be notified of -READ events. When the reactor sees that there is read</FONT> -<BR><FONT FACE="Arial,Helvetica"> activity for -us, our handle_input() will be invoked. The _handleg</FONT> -<BR><FONT FACE="Arial,Helvetica"> provided is the -handle (file descriptor in Unix) of the actual connection</FONT> -<BR><FONT FACE="Arial,Helvetica"> causing the activity. -Since we're derived from ACE_Svc_Handler<> and it</FONT> -<BR><FONT FACE="Arial,Helvetica"> maintains it's -own peer (ACE_SOCK_Stream) object, this is redundant for</FONT> -<BR><FONT FACE="Arial,Helvetica"> us. However, -if we had been derived directly from ACE_Event_Handler, we</FONT> -<BR><FONT FACE="Arial,Helvetica"> may have chosen -not to contain the peer. In that case, the _handleg</FONT> -<BR><FONT FACE="Arial,Helvetica"> would be important -to us for reading the client's data.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> int handle_input (ACE_HANDLE _handle);</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> This has nothing -at all to do with ACE. I've added this here as a worker</FONT> -<BR><FONT FACE="Arial,Helvetica"> function which -I will call from handle_input(). As promised in Tutorial 5</FONT> -<BR><FONT FACE="Arial,Helvetica"> I will use this -now to make it easier to switch between our two possible</FONT> -<BR><FONT FACE="Arial,Helvetica"> concurrency strategies.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> int process (char *_rdbuf, int -_rdbuf_len);</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> We don't really -do anything in our destructor but we've declared it to be</FONT> -<BR><FONT FACE="Arial,Helvetica"> protected to -prevent casual deletion of this object. As I said above, I</FONT> -<BR><FONT FACE="Arial,Helvetica"> really would -prefer that everyone goes through the destroy() method to get</FONT> -<BR><FONT FACE="Arial,Helvetica"> rid of us.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> ~Client_Handler (void);</FONT> -<BR><FONT FACE="Arial,Helvetica">};</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">#endif // CLIENT_HANDLER_H</FONT> - -<P> -<HR WIDTH="100%"> - -<P>So... we've added a svc() method and alluded to changes in open(). -Let's move on to the object definition and see what all the fuss is about. - -<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/006/page05.html b/docs/tutorials/006/page05.html deleted file mode 100644 index 5f8bedf16d9..00000000000 --- a/docs/tutorials/006/page05.html +++ /dev/null @@ -1,516 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="GENERATOR" CONTENT="Mozilla/4.05 [en] (WinNT; I) [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 006</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Creating a thread-per-connection server</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> - -<P><A HREF="client_handler.cpp">client_handler.cpp</A> exposes all the -things I've been hinting at. Pay special attention to the decision -made in open() as well as the bit of cleverness in svc(). - -<P> -<HR WIDTH="100%"> - -<P><FONT FACE="Arial,Helvetica">// $Id: client_handler.cpp,v 1.1 1998/08/30 -23:47:13 schmidt Exp $</FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> In client_handler.h I alluded -to the fact that we'll mess around with a</FONT> -<BR><FONT FACE="Arial,Helvetica"> Client_Acceptor pointer. -To do so, we need the Client_Acceptor object</FONT> -<BR><FONT FACE="Arial,Helvetica"> declaration.</FONT> - -<P><FONT FACE="Arial,Helvetica"> We know that including client_handler.h -is redundant because</FONT> -<BR><FONT FACE="Arial,Helvetica"> client_acceptor.h includes -it. Still, the sentry prevents double-inclusion</FONT> -<BR><FONT FACE="Arial,Helvetica"> from causing problems and -it's sometimes good to be explicit about what</FONT> -<BR><FONT FACE="Arial,Helvetica"> we're using.</FONT> - -<P><FONT FACE="Arial,Helvetica"> On the other hand, we don't -directly include any ACE header files here.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">#include "client_acceptor.h"</FONT> -<BR><FONT FACE="Arial,Helvetica">#include "client_handler.h"</FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Our constructor doesn't do -anything. That's generally a good idea. Unless</FONT> -<BR><FONT FACE="Arial,Helvetica"> you want to start throwing -exceptions, there isn't a really good way to</FONT> -<BR><FONT FACE="Arial,Helvetica"> indicate that a constructor -has failed. If I had my way, I'd have a boolean</FONT> -<BR><FONT FACE="Arial,Helvetica"> return code from it that -would cause new to return 0 if I failed. Oh</FONT> -<BR><FONT FACE="Arial,Helvetica"> well...</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">Client_Handler::Client_Handler (void)</FONT> -<BR><FONT FACE="Arial,Helvetica">{</FONT> -<BR><FONT FACE="Arial,Helvetica">}</FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Our destructor doesn't do -anything either. That is also by design.</FONT> -<BR><FONT FACE="Arial,Helvetica"> Remember, we really want -folks to use destroy() to get rid of us. If that's</FONT> -<BR><FONT FACE="Arial,Helvetica"> so, then there's nothing -left to do when the destructor gets invoked.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">Client_Handler::~Client_Handler (void)</FONT> -<BR><FONT FACE="Arial,Helvetica">{</FONT> -<BR><FONT FACE="Arial,Helvetica">}</FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> The much talked about destroy() -method! The reason I keep going on about</FONT> -<BR><FONT FACE="Arial,Helvetica"> this is because it's just -a Bad Idea (TM) to do real work inside of a</FONT> -<BR><FONT FACE="Arial,Helvetica"> destructor. Although -this method is void, it really should return</FONT> -<BR><FONT FACE="Arial,Helvetica"> int so that it can tell the -caller there was a problem. Even as</FONT> -<BR><FONT FACE="Arial,Helvetica"> void you could at least throw -an exception which you would never want</FONT> -<BR><FONT FACE="Arial,Helvetica"> to do in a destructor.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">void Client_Handler::destroy (void)</FONT> -<BR><FONT FACE="Arial,Helvetica">{</FONT> -<BR><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> We probably got -here because of an error on the stream, so the peer</FONT> -<BR><FONT FACE="Arial,Helvetica"> connection is -probably already closed. Still... there are other ways to</FONT> -<BR><FONT FACE="Arial,Helvetica"> get here and -closing a closed peer doesn't hurt.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> this->peer ().close ();</FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Tell the reactor -to forget all about us. Notice that we use the same args</FONT> -<BR><FONT FACE="Arial,Helvetica"> here that we -use in the open() method to register ourselves. In addition,</FONT> -<BR><FONT FACE="Arial,Helvetica"> we use the DONT_CALL -flag to prevent handle_close() being called. Since we</FONT> -<BR><FONT FACE="Arial,Helvetica"> likely got here -due to handle_close(), that could cause a bit of nasty</FONT> -<BR><FONT FACE="Arial,Helvetica"> recursion!</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> this->reactor ()->remove_handler -(this,</FONT> -<BR><FONT FACE="Arial,Helvetica"> -ACE_Event_Handler:: READ_MASK | ACE_Event_Handler::DONT_CALL);</FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> This is how we're -able to tell folks not to use delete. By</FONT> -<BR><FONT FACE="Arial,Helvetica"> deleting our -own instance, we take care of memory leaks after ensuring</FONT> -<BR><FONT FACE="Arial,Helvetica"> that the object -is shut down correctly.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> delete this;</FONT> -<BR><FONT FACE="Arial,Helvetica">}</FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> As mentioned before, the -open() method is called by the Client_Acceptor when</FONT> -<BR><FONT FACE="Arial,Helvetica"> a new client connection has -been accepted. The Client_Acceptor instance</FONT> -<BR><FONT FACE="Arial,Helvetica"> pointer is cast to a void* -and given to us here. We'll use that to avoid</FONT> -<BR><FONT FACE="Arial,Helvetica"> some global data...</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">int Client_Handler::open (void *_acceptor)</FONT> -<BR><FONT FACE="Arial,Helvetica">{</FONT> -<BR><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> We need this -to store the address of the client that we are now connected</FONT> -<BR><FONT FACE="Arial,Helvetica"> to. We'll -use it later to display a debug message.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_INET_Addr addr;</FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Our ACE_Svc_Handler -baseclass gives us the peer() method as a way to</FONT> -<BR><FONT FACE="Arial,Helvetica"> access our underlying -ACE_SOCK_Stream. On that object, we can invoke the</FONT> -<BR><FONT FACE="Arial,Helvetica"> get_remote_addr() -method to get get an ACE_INET_Addr having our client's</FONT> -<BR><FONT FACE="Arial,Helvetica"> address information. -As with most ACE methods, we'll get back (and return)</FONT> -<BR><FONT FACE="Arial,Helvetica"> a -1 if there -was any kind of error. Once we have the ACE_INET_Addr, we</FONT> -<BR><FONT FACE="Arial,Helvetica"> can query it -to find out the clien's host name, TCP/IP address, TCP/IP</FONT> -<BR><FONT FACE="Arial,Helvetica"> port value and -so forth. One word of warning: the get_host_name()</FONT> -<BR><FONT FACE="Arial,Helvetica"> method of ACE_INET_Addr -may return you an empty string if your name server</FONT> -<BR><FONT FACE="Arial,Helvetica"> can't resolve -it. On the other hand, get_host_addr() will always give you</FONT> -<BR><FONT FACE="Arial,Helvetica"> the dotted-decimal -string representing the TCP/IP address.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> if (this->peer ().get_remote_addr -(addr) == -1)</FONT> -<BR><FONT FACE="Arial,Helvetica"> {</FONT> -<BR><FONT FACE="Arial,Helvetica"> return --1;</FONT> -<BR><FONT FACE="Arial,Helvetica"> }</FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Convert the void* -to a Client_Acceptor*. You should probably use those</FONT> -<BR><FONT FACE="Arial,Helvetica"> fancy new C++ -cast operators but I can never remember how/when to do so.</FONT> -<BR><FONT FACE="Arial,Helvetica"> Since you can -cast just about anything around a void* without compiler</FONT> -<BR><FONT FACE="Arial,Helvetica"> warnings be very -sure of what you're doing when you do this kind of thing.</FONT> -<BR><FONT FACE="Arial,Helvetica"> That's where -the new-style cast operators can save you.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> Client_Acceptor *acceptor = (Client_Acceptor -*) _acceptor;</FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Our Client_Acceptor -is constructed with a concurrency strategy. Here, we</FONT> -<BR><FONT FACE="Arial,Helvetica"> go back to it -to find out what that strategy was. If thread-per-connection</FONT> -<BR><FONT FACE="Arial,Helvetica"> was selected -then we simply activate a thread for ourselves and exit. Our</FONT> -<BR><FONT FACE="Arial,Helvetica"> svc() method -will then begin executing in that thread.</FONT> - -<P><FONT FACE="Arial,Helvetica"> If we are told -to use the single-threaded strategy, there is no difference</FONT> -<BR><FONT FACE="Arial,Helvetica"> between this -and the Tutorial 5 implementation.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> if( acceptor->thread_per_connection() -)</FONT> -<BR><FONT FACE="Arial,Helvetica"> {</FONT> -<BR><FONT FACE="Arial,Helvetica"> return this->activate();</FONT> -<BR><FONT FACE="Arial,Helvetica"> }</FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Our reactor reference -will be set when we register ourselves but I decided</FONT> -<BR><FONT FACE="Arial,Helvetica"> to go ahead and -set it here. No good reason really...</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> this->reactor (acceptor->reactor -());</FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> If we managed -to get the client's address then we're connected to a real</FONT> -<BR><FONT FACE="Arial,Helvetica"> and valid client. -I suppose that in some cases, the client may connect</FONT> -<BR><FONT FACE="Arial,Helvetica"> and disconnect -so quickly that it is invalid by the time we get here. In</FONT> -<BR><FONT FACE="Arial,Helvetica"> any case, the -test above should always be done to ensure that the</FONT> -<BR><FONT FACE="Arial,Helvetica"> connection is -worth keeping.</FONT> - -<P><FONT FACE="Arial,Helvetica"> Now, regiser ourselves -with a reactor and tell that reactor that we want</FONT> -<BR><FONT FACE="Arial,Helvetica"> to be notified -when there is something to read. Remember, we took our</FONT> -<BR><FONT FACE="Arial,Helvetica"> reactor value -from the acceptor which created us in the first place.</FONT> -<BR><FONT FACE="Arial,Helvetica"> Since we're exploring -a single-threaded implementation, this is the</FONT> -<BR><FONT FACE="Arial,Helvetica"> correct thing -to do.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> if (this->reactor ()->register_handler -(this, ACE_Event_Handler::READ_MASK) == -1)</FONT> -<BR><FONT FACE="Arial,Helvetica"> {</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_ERROR_RETURN -((LM_ERROR, "(%P|%t) can't register with reactor\n"), -1);</FONT> -<BR><FONT FACE="Arial,Helvetica"> }</FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Here, we use -the ACE_INET_Addr object to print a message with the name of</FONT> -<BR><FONT FACE="Arial,Helvetica"> the client we're -connected to. Again, it is possible that you'll get an</FONT> -<BR><FONT FACE="Arial,Helvetica"> empty string -for the host name if your DNS isn't configured correctly or</FONT> -<BR><FONT FACE="Arial,Helvetica"> if there is some -other reason that a TCP/IP addreess cannot be converted</FONT> -<BR><FONT FACE="Arial,Helvetica"> into a host name.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_DEBUG ((LM_DEBUG, "(%P|%t) -connected with %s\n", addr.get_host_name ()));</FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Always return -zero on success.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> return 0;</FONT> -<BR><FONT FACE="Arial,Helvetica">}</FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> As mentioned in the header, -the typical way to close an object in a threaded</FONT> -<BR><FONT FACE="Arial,Helvetica"> context is to invoke it's -close() method. Since we already have a handle_close()</FONT> -<BR><FONT FACE="Arial,Helvetica"> method built to cleanup after -us, we'll just forward the request on to that</FONT> -<BR><FONT FACE="Arial,Helvetica"> object.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">int Client_Handler::close(u_long flags)</FONT> -<BR><FONT FACE="Arial,Helvetica">{</FONT> -<BR><FONT FACE="Arial,Helvetica"> -/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -Down in the depths of our baseclass, this will eventually cause us</FONT> -<BR><FONT FACE="Arial,Helvetica"> -to be destroyed. Since all of the destructors are virtual, everything</FONT> -<BR><FONT FACE="Arial,Helvetica"> -gets cleaned up nicely.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -*/</FONT> -<BR><FONT FACE="Arial,Helvetica"> -this->handle_close(ACE_INVALID_HANDLE,0);</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -Don't forward the close() to the baseclass! handle_close() above -has</FONT> -<BR><FONT FACE="Arial,Helvetica"> -already taken care of delete'ing. Forwarding close() would cause -that</FONT> -<BR><FONT FACE="Arial,Helvetica"> -to happen again and things would get really ugly at that point!</FONT> -<BR><FONT FACE="Arial,Helvetica"> -*/</FONT> -<BR><FONT FACE="Arial,Helvetica"> -return 0;</FONT> -<BR><FONT FACE="Arial,Helvetica">}</FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> In the open() method, we -registered with the reactor and requested to be</FONT> -<BR><FONT FACE="Arial,Helvetica"> notified when there is data -to be read. When the reactor sees that activity</FONT> -<BR><FONT FACE="Arial,Helvetica"> it will invoke this handle_input() -method on us. As I mentioned, the _handle</FONT> -<BR><FONT FACE="Arial,Helvetica"> parameter isn't useful to -us but it narrows the list of methods the reactor</FONT> -<BR><FONT FACE="Arial,Helvetica"> has to worry about and the -list of possible virtual functions we would have</FONT> -<BR><FONT FACE="Arial,Helvetica"> to override.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</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"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Some compilers -don't like it when you fail to use a parameter. This macro</FONT> -<BR><FONT FACE="Arial,Helvetica"> will keep 'em -quiet for you.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_UNUSED_ARG (_handle);</FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Now, we create -and initialize a buffer for receiving the data. Since this</FONT> -<BR><FONT FACE="Arial,Helvetica"> is just a simple -test app, we'll use a small buffer size.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> char buf[128];</FONT> -<BR><FONT FACE="Arial,Helvetica"> memset (buf, 0, sizeof (buf));</FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Invoke the process() -method with a pointer to our data area. We'll let</FONT> -<BR><FONT FACE="Arial,Helvetica"> that method worry -about interfacing with the data. You might choose to go</FONT> -<BR><FONT FACE="Arial,Helvetica"> ahead and read -the data and then pass the result to process(). However,</FONT> -<BR><FONT FACE="Arial,Helvetica"> application logic -may require that you read a few bytes to determine what</FONT> -<BR><FONT FACE="Arial,Helvetica"> else to read... -It's best if we push that all into the application-logic</FONT> -<BR><FONT FACE="Arial,Helvetica"> level.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> return this->process (buf, sizeof -(buf));</FONT> -<BR><FONT FACE="Arial,Helvetica">}</FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> If we return -1 out of handle_input() -or if the reactor sees other problems</FONT> -<BR><FONT FACE="Arial,Helvetica"> with us then handle_close() -will be called. It uses our destroy() method to</FONT> -<BR><FONT FACE="Arial,Helvetica"> shut us down cleanly and -get rid of our instance.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><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"> ACE_UNUSED_ARG (_handle);</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_UNUSED_ARG (_mask);</FONT> - -<P><FONT FACE="Arial,Helvetica"> this->destroy ();</FONT> -<BR><FONT FACE="Arial,Helvetica"> return 0;</FONT> -<BR><FONT FACE="Arial,Helvetica">}</FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> The ACE_Svc_Handler<> -is ultimately derived from ACE_Task<>. If you want to</FONT> -<BR><FONT FACE="Arial,Helvetica"> create a multi-threaded application, -these are your tools! Simply override</FONT> -<BR><FONT FACE="Arial,Helvetica"> the svc() method in your -derivative and arrange for your activate() method</FONT> -<BR><FONT FACE="Arial,Helvetica"> to be called. The svc() -method then executes in the new thread.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">int Client_Handler::svc(void)</FONT> -<BR><FONT FACE="Arial,Helvetica">{</FONT> -<BR><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Like handle_input(), -we create a buffer for loading the data. Doing so</FONT> -<BR><FONT FACE="Arial,Helvetica"> in handle_input() -doesn't help any but there is a small performance increase</FONT> -<BR><FONT FACE="Arial,Helvetica"> by doing this -here: the buffer is created once when the thread is created</FONT> -<BR><FONT FACE="Arial,Helvetica"> instead of for -each invocation of process().</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> char buf[128];</FONT> - -<P><FONT FACE="Arial,Helvetica"> // Forever...</FONT> -<BR><FONT FACE="Arial,Helvetica"> while( 1 )</FONT> -<BR><FONT FACE="Arial,Helvetica"> {</FONT> -<BR><FONT FACE="Arial,Helvetica"> // Clean the -buffer...</FONT> -<BR><FONT FACE="Arial,Helvetica"> memset (buf, -0, sizeof (buf));</FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -Invoke the proces() method to read and process the data. This is</FONT> -<BR><FONT FACE="Arial,Helvetica"> -exactly the way it is used by handle_input(). That's the reason I</FONT> -<BR><FONT FACE="Arial,Helvetica"> -created process() in the first place: so that it can be used in either</FONT> -<BR><FONT FACE="Arial,Helvetica"> -concurrency strategy. Since process() has all of our application-level</FONT> -<BR><FONT FACE="Arial,Helvetica"> -logic, it's nice that it doesn't have to change when we decide to go</FONT> -<BR><FONT FACE="Arial,Helvetica"> -multi-threaded.</FONT> - -<P><FONT FACE="Arial,Helvetica"> -Notice that since the recv() method call in process() blocks until</FONT> -<BR><FONT FACE="Arial,Helvetica"> -there is data ready, this thread doesn't consume any CPU time until</FONT> -<BR><FONT FACE="Arial,Helvetica"> -there is actually data sent from the client.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> if( this->process(buf,sizeof(buf)) -== -1 )</FONT> -<BR><FONT FACE="Arial,Helvetica"> {</FONT> -<BR><FONT FACE="Arial,Helvetica"> return(-1);</FONT> -<BR><FONT FACE="Arial,Helvetica"> }</FONT> -<BR><FONT FACE="Arial,Helvetica"> }</FONT> - -<P><FONT FACE="Arial,Helvetica"> return(0);</FONT> -<BR><FONT FACE="Arial,Helvetica">}</FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> And, at last, we get to the -application-logic level. Out of everything</FONT> -<BR><FONT FACE="Arial,Helvetica"> we've done so far, this is -the only thing that really has anything to do</FONT> -<BR><FONT FACE="Arial,Helvetica"> with what your application -will do. In this method we will read and process</FONT> -<BR><FONT FACE="Arial,Helvetica"> the client's data. -In a real appliation, you will probably have a bit more</FONT> -<BR><FONT FACE="Arial,Helvetica"> in main() to deal with command -line options but after that point, all of the</FONT> -<BR><FONT FACE="Arial,Helvetica"> action takes place here.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</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"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Using the buffer -provided for us, we read the data from the client. If</FONT> -<BR><FONT FACE="Arial,Helvetica"> there is a read -error (eg -- recv() returns -1) then it's a pretty good</FONT> -<BR><FONT FACE="Arial,Helvetica"> bet that the -connection is gone. Likewise, if we read zero bytes then</FONT> -<BR><FONT FACE="Arial,Helvetica"> something wrong -has happened. The reactor wouldn't have called us if</FONT> -<BR><FONT FACE="Arial,Helvetica"> there wasn't -some kind of read activity but there wouldn't be activity if</FONT> -<BR><FONT FACE="Arial,Helvetica"> there were no -bytes to read...</FONT> - -<P><FONT FACE="Arial,Helvetica"> On the other hand, -if we got some data then we can display it in a debug</FONT> -<BR><FONT FACE="Arial,Helvetica"> message for everyone -to see.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> switch (this->peer ().recv (_rdbuf, -_rdbuf_len))</FONT> -<BR><FONT FACE="Arial,Helvetica"> {</FONT> -<BR><FONT FACE="Arial,Helvetica"> case -1:</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_ERROR_RETURN -((LM_ERROR, "(%P|%t) %p bad read\n", "client"), -1);</FONT> -<BR><FONT FACE="Arial,Helvetica"> case 0:</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_ERROR_RETURN -((LM_ERROR, "(%P|%t) closing daemon (fd = %d)\n", this->get_handle ()), --1);</FONT> -<BR><FONT FACE="Arial,Helvetica"> default:</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_DEBUG -((LM_DEBUG, "(%P|%t) from client: %s", _rdbuf));</FONT> -<BR><FONT FACE="Arial,Helvetica"> }</FONT> - -<P><FONT FACE="Arial,Helvetica"> return 0;</FONT> -<BR><FONT FACE="Arial,Helvetica">}</FONT> - -<P> -<HR WIDTH="100%"> - -<P>Well, that's it! After all the talk & the hype, you would -have expected it to be more difficult to create a multi-threaded server. -Surprise! It really is that easy. You still have to handle -contention issues which we haven't addressed here and that is a rather -nasty topic. Still, for the simple case, this is all you have to -do. - -<P>The next page is the last for this tutorial. Head on over there -& we'll round up the file list one last time. - -<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/006/page06.html b/docs/tutorials/006/page06.html deleted file mode 100644 index b4ad640b25e..00000000000 --- a/docs/tutorials/006/page06.html +++ /dev/null @@ -1,52 +0,0 @@ -<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 006</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>On the road to a multithreaded server</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> - -<P>That's it for Tutorial 6. With very little effort we've managed -to extend the previous single-threaded server to an implementation which -allows runtime selection of single or multi-threaded operation. In -Tutorial 7 we'll extend that again to allow a thread-pool choice in addition -to the current two. - -<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_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="fix.Makefile">fix.Makefile</A></LI> -</UL> - - -<P> -<HR WIDTH="100%"> -<CENTER>[<A HREF="../../tutorials">Tutorial Index</A>]</CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/006/server.cpp b/docs/tutorials/006/server.cpp deleted file mode 100644 index 5195f46f8d0..00000000000 --- a/docs/tutorials/006/server.cpp +++ /dev/null @@ -1,122 +0,0 @@ -// $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); - - /* - As with Tutorial 5, we know that we're now registered with our reactor - so we don't have to mess with that step. - */ - - /* - 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; -} - -#if !defined(ACE_HAS_GNU_REPO) -#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION) -template class ACE_Acceptor <Client_Handler, ACE_SOCK_ACCEPTOR>; -template class ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH>; -#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA) -#pragma instantiate ACE_Acceptor <Client_Handler, ACE_SOCK_ACCEPTOR> -#pragma instantiate ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH> -#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */ -#endif /* ACE_HAS_GNU_REPO */ diff --git a/docs/tutorials/007/Makefile b/docs/tutorials/007/Makefile deleted file mode 100644 index c59e420cbfe..00000000000 --- a/docs/tutorials/007/Makefile +++ /dev/null @@ -1,102 +0,0 @@ -#---------------------------------------------------------------------------- -# $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 - -.depend : # - touch .depend - -#---------------------------------------------------------------------------- -# 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 deleted file mode 100644 index 6cc90612558..00000000000 --- a/docs/tutorials/007/client_acceptor.cpp +++ /dev/null @@ -1,67 +0,0 @@ - -// $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 deleted file mode 100644 index e1c0eded6fd..00000000000 --- a/docs/tutorials/007/client_acceptor.h +++ /dev/null @@ -1,137 +0,0 @@ - -// $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 deleted file mode 100644 index f91f0ec6c40..00000000000 --- a/docs/tutorials/007/client_handler.cpp +++ /dev/null @@ -1,230 +0,0 @@ - -// $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; -} - -/* - As mentioned in the header, the typical way to close an object in a threaded - context is to invoke it's close() method. Since we already have a handle_close() - method built to cleanup after us, we'll just forward the request on to that - object. - */ -int Client_Handler::close(u_long flags) -{ - this->handle_close(ACE_INVALID_HANDLE,0); - - /* - After we've taken care of ourselves, call the baseclass method - to do any other necessary cleanup. - */ - return inherited::close(); -} - -/* - 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]; - ACE_OS::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; -} - -/* - Remember that when we leave our svc() method, the framework will take care - of calling our close() method so that we can cleanup after ourselves. - */ -int Client_Handler::svc(void) -{ - char buf[128]; - ACE_OS::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 deleted file mode 100644 index 340cde65a4d..00000000000 --- a/docs/tutorials/007/client_handler.h +++ /dev/null @@ -1,164 +0,0 @@ - -// $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: - typedef ACE_Svc_Handler < ACE_SOCK_STREAM, ACE_NULL_SYNCH > inherited; - - // 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 an ACE_Task<> object falls out of the svc() method, the framework - will call the close() method. That's where we want to cleanup ourselves - if we're running in either thread-per-connection or thread-pool mode. - */ - int close(u_long flags = 0); - - /* - 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 deleted file mode 100755 index e99c194114a..00000000000 --- a/docs/tutorials/007/fix.Makefile +++ /dev/null @@ -1,60 +0,0 @@ -#!/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 deleted file mode 100644 index 9402426de3f..00000000000 --- a/docs/tutorials/007/page01.html +++ /dev/null @@ -1,33 +0,0 @@ -<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: thread-pool. 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". As you'll see, our basic objects will change -but not by a whole lot. 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 deleted file mode 100644 index c6e7bedec43..00000000000 --- a/docs/tutorials/007/page02.html +++ /dev/null @@ -1,197 +0,0 @@ -<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"> We try to keep main() very -simple. One of the ways we do that is to push</FONT> -<BR><FONT FACE="Arial,Helvetica"> much of the complicated stuff -into worker objects. In this case, we only</FONT> -<BR><FONT FACE="Arial,Helvetica"> need to include the acceptor -header in our main source file. We let it</FONT> -<BR><FONT FACE="Arial,Helvetica"> worry about the "real work".</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> - -<P><FONT FACE="Arial,Helvetica">#include "client_acceptor.h"</FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> As before, we create a simple -signal handler that will set our finished</FONT> -<BR><FONT FACE="Arial,Helvetica"> flag. There are, of -course, more elegant ways to handle program shutdown</FONT> -<BR><FONT FACE="Arial,Helvetica"> requests but that isn't really -our focus right now, so we'll just do the</FONT> -<BR><FONT FACE="Arial,Helvetica"> easiest thing.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</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"> finished = 1;</FONT> -<BR><FONT FACE="Arial,Helvetica">}</FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> A server has to listen for -clients at a known TCP/IP port. The default ACE</FONT> -<BR><FONT FACE="Arial,Helvetica"> port is 10002 (at least on -my system) and that's good enough for what we</FONT> -<BR><FONT FACE="Arial,Helvetica"> want to do here. Obviously, -a more robust application would take a command</FONT> -<BR><FONT FACE="Arial,Helvetica"> line parameter or read from -a configuration file or do some other clever</FONT> -<BR><FONT FACE="Arial,Helvetica"> thing. Just like the -signal handler above, though, that's what we want to</FONT> -<BR><FONT FACE="Arial,Helvetica"> focus on, so we're taking -the easy way out.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</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"> Finally, we get to main. -Some C++ compilers will complain loudly if your</FONT> -<BR><FONT FACE="Arial,Helvetica"> function signature doesn't -match the prototype. Even though we're not</FONT> -<BR><FONT FACE="Arial,Helvetica"> going to use the parameters, -we still have to specify them.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</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"> In our earlier servers, we -used a global pointer to get to the reactor. I've</FONT> -<BR><FONT FACE="Arial,Helvetica"> never really liked that idea, -so I've moved it into main() this time. When</FONT> -<BR><FONT FACE="Arial,Helvetica"> we get to the Client_Handler -object you'll see how we manage to get a</FONT> -<BR><FONT FACE="Arial,Helvetica"> pointer back to this reactor.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_Reactor reactor;</FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> The acceptor -will take care of letting clients connect to us. It will</FONT> -<BR><FONT FACE="Arial,Helvetica"> also arrange -for a Client_Handler to be created for each new client.</FONT> -<BR><FONT FACE="Arial,Helvetica"> Since we're only -going to listen at one TCP/IP port, we only need one</FONT> -<BR><FONT FACE="Arial,Helvetica"> acceptor. -If we wanted, though, we could create several of these and</FONT> -<BR><FONT FACE="Arial,Helvetica"> listen at several -ports. (That's what we would do if we wanted to rewrite</FONT> -<BR><FONT FACE="Arial,Helvetica"> inetd for -instance.)</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> Client_Acceptor peer_acceptor;</FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Create an ACE_INET_Addr -that represents our endpoint of a connection. We</FONT> -<BR><FONT FACE="Arial,Helvetica"> then open our -acceptor object with that Addr. Doing so tells the acceptor</FONT> -<BR><FONT FACE="Arial,Helvetica"> where to listen -for connections. Servers generally listen at "well known"</FONT> -<BR><FONT FACE="Arial,Helvetica"> addresses. -If not, there must be some mechanism by which the client is</FONT> -<BR><FONT FACE="Arial,Helvetica"> informed of the -server's address.</FONT> - -<P><FONT FACE="Arial,Helvetica"> Note how ACE_ERROR_RETURN -is used if we fail to open the acceptor. This</FONT> -<BR><FONT FACE="Arial,Helvetica"> technique is -used over and over again in our tutorials.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> if (peer_acceptor.open (ACE_INET_Addr -(PORT), &reactor) == -1)</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_ERROR_RETURN ((LM_ERROR, -"%p\n", "open"), -1);</FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Install our signal -handler. You can actually register signal handlers</FONT> -<BR><FONT FACE="Arial,Helvetica"> with the reactor. -You might do that when the signal handler is</FONT> -<BR><FONT FACE="Arial,Helvetica"> responsible for -performing "real" work. Our simple flag-setter doesn't</FONT> -<BR><FONT FACE="Arial,Helvetica"> justify deriving -from ACE_Event_Handler and providing a callback function</FONT> -<BR><FONT FACE="Arial,Helvetica"> though.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_Sig_Action sa ((ACE_SignalHandler) -handler, SIGINT);</FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Like ACE_ERROR_RETURN, -the ACE_DEBUG macro gets used quite a bit. It's a</FONT> -<BR><FONT FACE="Arial,Helvetica"> handy way to -generate uniform debug output from your program.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_DEBUG ((LM_DEBUG, "(%P|%t) -starting up server daemon\n"));</FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> This will loop -"forever" invoking the handle_events() method of our</FONT> -<BR><FONT FACE="Arial,Helvetica"> reactor. handle_events() -watches for activity on any registered handlers</FONT> -<BR><FONT FACE="Arial,Helvetica"> and invokes their -appropriate callbacks when necessary. Callback-driven</FONT> -<BR><FONT FACE="Arial,Helvetica"> programming is -a big thing in ACE, you should get used to it. If the</FONT> -<BR><FONT FACE="Arial,Helvetica"> signal handler -catches something, the finished flag will be set and we'll</FONT> -<BR><FONT FACE="Arial,Helvetica"> exit. Conveniently -enough, handle_events() is also interrupted by signals</FONT> -<BR><FONT FACE="Arial,Helvetica"> and will exit -back to the while() loop. (If you want your event loop to</FONT> -<BR><FONT FACE="Arial,Helvetica"> not be interrupted -by signals, checkout the <i>restart</i> flag on the</FONT> -<BR><FONT FACE="Arial,Helvetica"> open() method -of ACE_Reactor if you're interested.)</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> while (!finished)</FONT> -<BR><FONT FACE="Arial,Helvetica"> -reactor.handle_events ();</FONT> - -<P><FONT FACE="Arial,Helvetica"> ACE_DEBUG ((LM_DEBUG, "(%P|%t) shutting -down server daemon\n"));</FONT> -<BR><FONT FACE="Arial,Helvetica"> </FONT> -<BR><FONT FACE="Arial,Helvetica"> return 0;</FONT> -<BR><FONT FACE="Arial,Helvetica">}</FONT> - -<P> -<HR WIDTH="100%"> - -<P>Hmmm... No change there. Maybe I should leave out comments -on the stuff I don't change. 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 deleted file mode 100644 index 694ed2505cc..00000000000 --- a/docs/tutorials/007/page03.html +++ /dev/null @@ -1,263 +0,0 @@ -<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"> The ACE_Acceptor<> template -lives in the ace/Acceptor.h header file. You'll</FONT> -<BR><FONT FACE="Arial,Helvetica"> find a very consitent naming -convention between the ACE objects and the</FONT> -<BR><FONT FACE="Arial,Helvetica"> headers where they can be -found. In general, the ACE object ACE_Foobar will</FONT> -<BR><FONT FACE="Arial,Helvetica"> be found in ace/Foobar.h.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</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"> Since we want to work with -sockets, we'll need a SOCK_Acceptor to allow the</FONT> -<BR><FONT FACE="Arial,Helvetica"> clients to connect to us.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</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"> The Client_Handler object -we develop will be used to handle clients once</FONT> -<BR><FONT FACE="Arial,Helvetica"> they're connected. -The ACE_Acceptor<> template's first parameter requires</FONT> -<BR><FONT FACE="Arial,Helvetica"> such an object. In -some cases, you can get by with just a forward</FONT> -<BR><FONT FACE="Arial,Helvetica"> declaration on the class, -in others you have to have the whole thing.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</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"> Parameterize the ACE_Acceptor<> -such that it will listen for socket</FONT> -<BR><FONT FACE="Arial,Helvetica"> connection attempts and create -Client_Handler objects when they happen. In</FONT> -<BR><FONT FACE="Arial,Helvetica"> Tutorial 001, we wrote the -basic acceptor logic on our own before we</FONT> -<BR><FONT FACE="Arial,Helvetica"> realized that ACE_Acceptor<> -was available. You'll get spoiled using the</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE templates because they -take away a lot of the tedious details!</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">typedef ACE_Acceptor < 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"> This time we've added quite -a bit more to our acceptor. In addition to</FONT> -<BR><FONT FACE="Arial,Helvetica"> providing a choice of concurrency -strategies, we also maintain a Thread_Pool</FONT> -<BR><FONT FACE="Arial,Helvetica"> object in case that strategy -is chosen. The object still isn't very complex</FONT> -<BR><FONT FACE="Arial,Helvetica"> 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"> Why keep the thread pool as -a member? If we go back to the inetd concept</FONT> -<BR><FONT FACE="Arial,Helvetica"> you'll recall that we need -several acceptors to make that work. We may have</FONT> -<BR><FONT FACE="Arial,Helvetica"> a situation in which our -different client types requre different resources.</FONT> -<BR><FONT FACE="Arial,Helvetica"> That is, we may need a large -thread pool for some client types and a smaller</FONT> -<BR><FONT FACE="Arial,Helvetica"> one for others. We -could share a pool but then the client types may have</FONT> -<BR><FONT FACE="Arial,Helvetica"> undesirable impact on one -another.</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> Just in case you do want to -share a single thread pool, there is a constructor</FONT> -<BR><FONT FACE="Arial,Helvetica"> below that will let you do -that.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</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"> -typedef Client_Acceptor_Base inherited;</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -Now that we have more than two strategies, we need more than a boolean</FONT> -<BR><FONT FACE="Arial,Helvetica"> -to tell us what we're using. A set of enums is a good choice because</FONT> -<BR><FONT FACE="Arial,Helvetica"> -it allows us to use named values. Another option would be a set of</FONT> -<BR><FONT FACE="Arial,Helvetica"> -static const integers.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -*/</FONT> -<BR><FONT FACE="Arial,Helvetica"> -enum concurrency_t</FONT> -<BR><FONT FACE="Arial,Helvetica"> -{</FONT> -<BR><FONT FACE="Arial,Helvetica"> -single_threaded_,</FONT> -<BR><FONT FACE="Arial,Helvetica"> -thread_per_connection_,</FONT> -<BR><FONT FACE="Arial,Helvetica"> -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"> -The default constructor allows the programmer to choose the concurrency</FONT> -<BR><FONT FACE="Arial,Helvetica"> -strategy. Since we want to focus on thread-pool, that's what we'll -use</FONT> -<BR><FONT FACE="Arial,Helvetica"> -if nothing is specified.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -*/</FONT> -<BR><FONT FACE="Arial,Helvetica"> -Client_Acceptor( int _concurrency = thread_pool_ );</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -Another option is to construct the object with an existing thread pool.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -The concurrency strategy is pretty obvious at that point.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -*/</FONT> -<BR><FONT FACE="Arial,Helvetica"> -Client_Acceptor( Thread_Pool & _thread_pool );</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -Our destructor will take care of shutting down the thread-pool</FONT> -<BR><FONT FACE="Arial,Helvetica"> -if applicable.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -*/</FONT> -<BR><FONT FACE="Arial,Helvetica"> -~Client_Acceptor( void );</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -Open ourselves and register with the given reactor. The thread pool -size</FONT> -<BR><FONT FACE="Arial,Helvetica"> -can be specified here if you want to use that concurrency strategy.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -*/</FONT> -<BR><FONT FACE="Arial,Helvetica"> -int open( const ACE_INET_Addr & _addr, ACE_Reactor * _reactor,</FONT> -<BR><FONT FACE="Arial,Helvetica"> -int _pool_size = Thread_Pool::default_pool_size_ );</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -Close ourselves and our thread pool if applicable</FONT> -<BR><FONT FACE="Arial,Helvetica"> -*/</FONT> -<BR><FONT FACE="Arial,Helvetica"> -int close(void);</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -What is our concurrency strategy?</FONT> -<BR><FONT FACE="Arial,Helvetica"> -*/</FONT> -<BR><FONT FACE="Arial,Helvetica"> -int concurrency(void)</FONT> -<BR><FONT FACE="Arial,Helvetica"> -{ return this->concurrency_; }</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -Give back a pointer to our thread pool. Our Client_Handler objects</FONT> -<BR><FONT FACE="Arial,Helvetica"> -will need this so that their handle_input() methods can put themselves</FONT> -<BR><FONT FACE="Arial,Helvetica"> -into the pool. Another alternative would be a globally accessible</FONT> -<BR><FONT FACE="Arial,Helvetica"> -thread pool. ACE_Singleton<> is a way to achieve that.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -*/</FONT> -<BR><FONT FACE="Arial,Helvetica"> -Thread_Pool * thread_pool(void)</FONT> -<BR><FONT FACE="Arial,Helvetica"> -{ return & this->the_thread_pool_; }</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -Since we can be constructed with a Thread_Pool reference, there are times</FONT> -<BR><FONT FACE="Arial,Helvetica"> -when we need to know if the thread pool we're using is ours or if we're</FONT> -<BR><FONT FACE="Arial,Helvetica"> -just borrowing it from somebody else.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -*/</FONT> -<BR><FONT FACE="Arial,Helvetica"> -int thread_pool_is_private(void)</FONT> -<BR><FONT FACE="Arial,Helvetica"> -{ return &the_thread_pool_ == &private_thread_pool_; }</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">protected:</FONT> -<BR><FONT FACE="Arial,Helvetica"> -int concurrency_;</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -Thread_Pool private_thread_pool_;</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -Thread_Pool & 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 deleted file mode 100644 index c74bcdf7dae..00000000000 --- a/docs/tutorials/007/page04.html +++ /dev/null @@ -1,133 +0,0 @@ -<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>. -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"> Construct ourselves with -the chosen concurrency strategy. Notice that we also</FONT> -<BR><FONT FACE="Arial,Helvetica"> set our Thread_Pool reference -to our private instance.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">Client_Acceptor::Client_Acceptor( int -_concurrency )</FONT> -<BR><FONT FACE="Arial,Helvetica"> : concurrency_(_concurrency)</FONT> -<BR><FONT FACE="Arial,Helvetica"> ,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"> Construct ourselves with -a reference to somebody else' Thread_Pool. Obvioulsy</FONT> -<BR><FONT FACE="Arial,Helvetica"> our concurrency strategy -is "thread_pool_" at this point.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">Client_Acceptor::Client_Acceptor( Thread_Pool -& _thread_pool )</FONT> -<BR><FONT FACE="Arial,Helvetica"> : concurrency_(thread_pool_)</FONT> -<BR><FONT FACE="Arial,Helvetica"> ,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"> When we're destructed, we -may need to cleanup after ourselves. If we're running</FONT> -<BR><FONT FACE="Arial,Helvetica"> with a thread pool that we -own, it is up to us to close it down.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">Client_Acceptor::~Client_Acceptor( void -)</FONT> -<BR><FONT FACE="Arial,Helvetica">{</FONT> -<BR><FONT FACE="Arial,Helvetica"> -if( this->concurrency() == thread_pool_ && thread_pool_is_private() -)</FONT> -<BR><FONT FACE="Arial,Helvetica"> -{</FONT> -<BR><FONT FACE="Arial,Helvetica"> -thread_pool()->close();</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"> Similar to the destructor -(and close() below) it is necessary for us to open the</FONT> -<BR><FONT FACE="Arial,Helvetica"> thread pool in some circumstances.</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> Notice how we delegate most -of the open() work to the open() method of our baseclass.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">int Client_Acceptor::open( const ACE_INET_Addr -& _addr, ACE_Reactor * _reactor, int _pool_size )</FONT> -<BR><FONT FACE="Arial,Helvetica">{</FONT> -<BR><FONT FACE="Arial,Helvetica"> -if( this->concurrency() == thread_pool_ && thread_pool_is_private() -)</FONT> -<BR><FONT FACE="Arial,Helvetica"> -{</FONT> -<BR><FONT FACE="Arial,Helvetica"> -thread_pool()->open(_pool_size);</FONT> -<BR><FONT FACE="Arial,Helvetica"> -}</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -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"> Here again we find that we -have to manage the thread pool. Like open() we also delegate</FONT> -<BR><FONT FACE="Arial,Helvetica"> the other work to our baseclass.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">int Client_Acceptor::close(void)</FONT> -<BR><FONT FACE="Arial,Helvetica">{</FONT> -<BR><FONT FACE="Arial,Helvetica"> -if( this->concurrency() == thread_pool_ && thread_pool_is_private() -)</FONT> -<BR><FONT FACE="Arial,Helvetica"> -{</FONT> -<BR><FONT FACE="Arial,Helvetica"> -thread_pool()->close();</FONT> -<BR><FONT FACE="Arial,Helvetica"> -}</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -return inherited::close();</FONT> -<BR><FONT FACE="Arial,Helvetica">}</FONT> -<BR><FONT FACE="Arial,Helvetica"></FONT> <FONT FACE="Arial,Helvetica"></FONT> - -<P> -<HR WIDTH="100%"> - -<P>Nothing really surprising here. 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 deleted file mode 100644 index a5ad7a8d62e..00000000000 --- a/docs/tutorials/007/page05.html +++ /dev/null @@ -1,294 +0,0 @@ -<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> -<BR><FONT FACE="Arial,Helvetica">// $Id: client_handler.h,v 1.1 1998/08/30 -23:47:14 schmidt 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"> Our client handler must exist -somewhere in the ACE_Event_Handler object</FONT> -<BR><FONT FACE="Arial,Helvetica"> hierarchy. This is -a requirement of the ACE_Reactor because it maintains</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_Event_Handler pointers -for each registered event handler. You could</FONT> -<BR><FONT FACE="Arial,Helvetica"> derive our Client_Handler -directly from ACE_Event_Handler but you still have</FONT> -<BR><FONT FACE="Arial,Helvetica"> to have an ACE_SOCK_Stream -for the actually connection. With a direct</FONT> -<BR><FONT FACE="Arial,Helvetica"> derivative of ACE_Event_Handler, -you'll have to contain and maintain an</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_SOCK_Stream instance -yourself. With ACE_Svc_Handler (which is a</FONT> -<BR><FONT FACE="Arial,Helvetica"> derivative of ACE_Event_Handler) -some of those details are handled for you.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</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"> Another feature of ACE_Svc_Handler -is it's ability to present the ACE_Task<></FONT> -<BR><FONT FACE="Arial,Helvetica"> interface as well. -That's what the ACE_NULL_SYNCH parameter below is all</FONT> -<BR><FONT FACE="Arial,Helvetica"> about. That's beyond -our scope here but we'll come back to it in the next</FONT> -<BR><FONT FACE="Arial,Helvetica"> tutorial when we start looking -at concurrency options.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">class Client_Handler : public ACE_Svc_Handler -< ACE_SOCK_STREAM, ACE_NULL_SYNCH ></FONT> -<BR><FONT FACE="Arial,Helvetica">{</FONT> -<BR><FONT FACE="Arial,Helvetica">public:</FONT> -<BR><FONT FACE="Arial,Helvetica"> typedef ACE_Svc_Handler < ACE_SOCK_STREAM, -ACE_NULL_SYNCH > inherited;</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> // Constructor...</FONT> -<BR><FONT FACE="Arial,Helvetica"> Client_Handler (void);</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> The destroy() -method is our preferred method of destruction. We could</FONT> -<BR><FONT FACE="Arial,Helvetica"> have overloaded -the delete operator but that is neither easy nor</FONT> -<BR><FONT FACE="Arial,Helvetica"> intuitive (at -least to me). Instead, we provide a new method of</FONT> -<BR><FONT FACE="Arial,Helvetica"> destruction and -we make our destructor protected so that only ourselves,</FONT> -<BR><FONT FACE="Arial,Helvetica"> our derivatives -and our friends can delete us. It's a nice</FONT> -<BR><FONT FACE="Arial,Helvetica"> compromise.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> void destroy (void);</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Most ACE objects -have an open() method. That's how you make them ready</FONT> -<BR><FONT FACE="Arial,Helvetica"> to do work. -ACE_Event_Handler has a virtual open() method which allows us</FONT> -<BR><FONT FACE="Arial,Helvetica"> to create this -overrride. ACE_Acceptor<> will invoke this method after</FONT> -<BR><FONT FACE="Arial,Helvetica"> creating a new -Client_Handler when a client connects. Notice that the</FONT> -<BR><FONT FACE="Arial,Helvetica"> parameter to -open() is a void*. It just so happens that the pointer</FONT> -<BR><FONT FACE="Arial,Helvetica"> points to the -acceptor which created us. You would like for the parameter</FONT> -<BR><FONT FACE="Arial,Helvetica"> to be an ACE_Acceptor<>* -but since ACE_Event_Handler is generic, that</FONT> -<BR><FONT FACE="Arial,Helvetica"> would tie it -too closely to the ACE_Acceptor<> set of objects. In our</FONT> -<BR><FONT FACE="Arial,Helvetica"> definition of -open() you'll see how we get around that.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> int open (void *_acceptor);</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> When an ACE_Task<> -object falls out of the svc() method, the framework</FONT> -<BR><FONT FACE="Arial,Helvetica"> will call the -close() method. That's where we want to cleanup ourselves</FONT> -<BR><FONT FACE="Arial,Helvetica"> if we're running -in either thread-per-connection or thread-pool mode.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> int close(u_long flags = 0);</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> When there is -activity on a registered handler, the handle_input() method</FONT> -<BR><FONT FACE="Arial,Helvetica"> of the handler -will be invoked. If that method returns an error code (eg</FONT> -<BR><FONT FACE="Arial,Helvetica"> -- -1) then the -reactor will invoke handle_close() to allow the object to</FONT> -<BR><FONT FACE="Arial,Helvetica"> clean itself -up. Since an event handler can be registered for more than</FONT> -<BR><FONT FACE="Arial,Helvetica"> one type of callback, -the callback mask is provided to inform</FONT> -<BR><FONT FACE="Arial,Helvetica"> handle_close() -exactly which method failed. That way, you don't have to</FONT> -<BR><FONT FACE="Arial,Helvetica"> maintain state -information between your handle_* method calls. The _handle</FONT> -<BR><FONT FACE="Arial,Helvetica"> parameter is -explained below...</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> int handle_close (ACE_HANDLE _handle, -ACE_Reactor_Mask _mask);</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> When we register -with the reactor, we're going to tell it that we want to</FONT> -<BR><FONT FACE="Arial,Helvetica"> be notified of -READ events. When the reactor sees that there is read</FONT> -<BR><FONT FACE="Arial,Helvetica"> activity for -us, our handle_input() will be invoked. The _handleg</FONT> -<BR><FONT FACE="Arial,Helvetica"> provided is the -handle (file descriptor in Unix) of the actual connection</FONT> -<BR><FONT FACE="Arial,Helvetica"> causing the activity. -Since we're derived from ACE_Svc_Handler<> and it</FONT> -<BR><FONT FACE="Arial,Helvetica"> maintains it's -own peer (ACE_SOCK_Stream) object, this is redundant for</FONT> -<BR><FONT FACE="Arial,Helvetica"> us. However, -if we had been derived directly from ACE_Event_Handler, we</FONT> -<BR><FONT FACE="Arial,Helvetica"> may have chosen -not to contain the peer. In that case, the _handleg</FONT> -<BR><FONT FACE="Arial,Helvetica"> would be important -to us for reading the client's data.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> 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"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> If the Client_Acceptor -which created us has chosen a thread-per-connection</FONT> -<BR><FONT FACE="Arial,Helvetica"> strategy then -our open() method will activate us into a dedicate thread.</FONT> -<BR><FONT FACE="Arial,Helvetica"> The svc() method -will then execute in that thread performing some of the</FONT> -<BR><FONT FACE="Arial,Helvetica"> functions we -used to leave up to the reactor.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> int svc(void);</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> This has nothing -at all to do with ACE. I've added this here as a worker</FONT> -<BR><FONT FACE="Arial,Helvetica"> function which -I will call from handle_input(). That allows me to</FONT> -<BR><FONT FACE="Arial,Helvetica"> introduce concurrencly -in later tutorials with a no changes to the worker</FONT> -<BR><FONT FACE="Arial,Helvetica"> function. -You can think of process() as application-level code and</FONT> -<BR><FONT FACE="Arial,Helvetica"> everything elase -as application-framework code.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> int process (char *_rdbuf, int -_rdbuf_len);</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> We don't really -do anything in our destructor but we've declared it to be</FONT> -<BR><FONT FACE="Arial,Helvetica"> protected to -prevent casual deletion of this object. As I said above, I</FONT> -<BR><FONT FACE="Arial,Helvetica"> really would -prefer that everyone goes through the destroy() method to get</FONT> -<BR><FONT FACE="Arial,Helvetica"> rid of us.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> ~Client_Handler (void);</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> When we -get to the definition of Client_Handler we'll see that there are</FONT> -<BR><FONT FACE="Arial,Helvetica"> -several places where we go back to the Client_Acceptor for information.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -It is generally a good idea to do that through an accesor rather than</FONT> -<BR><FONT FACE="Arial,Helvetica"> -using the member variable directly.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> Client_Acceptor * client_acceptor( -void )</FONT> -<BR><FONT FACE="Arial,Helvetica"> -{ return this->client_acceptor_; }</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> And since -you shouldn't access a member variable directly, neither should you</FONT> -<BR><FONT FACE="Arial,Helvetica"> -set (mutate) it. Although it might seem silly to do it this way, -you'll thank</FONT> -<BR><FONT FACE="Arial,Helvetica"> -yourself for it later.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> void client_acceptor( Client_Acceptor -* _client_acceptor )</FONT> -<BR><FONT FACE="Arial,Helvetica"> -{ this->client_acceptor_ = _client_acceptor; }</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> The concurrency() -accessor tells us the current concurrency strategy. It actually</FONT> -<BR><FONT FACE="Arial,Helvetica"> -queries the Client_Acceptor for it but by having the accessor in place, -we could</FONT> -<BR><FONT FACE="Arial,Helvetica"> -change our implementation without affecting everything that needs to know.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> int concurrency(void);</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Likewise -for access to the Thread_Pool that we belong to.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> Thread_Pool * thread_pool(void);</FONT> -<BR><FONT FACE="Arial,Helvetica"></FONT> <FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> Client_Acceptor * client_acceptor_;</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> For some -reason I didn't create accessor/mutator methods for this. So much -for</FONT> -<BR><FONT FACE="Arial,Helvetica"> -consistency....</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -This variable is used to remember the thread in which we were created: -the "creator"</FONT> -<BR><FONT FACE="Arial,Helvetica"> -thread in other words. handle_input() needs to know if it is operating -in the</FONT> -<BR><FONT FACE="Arial,Helvetica"> -main reactor thread (which is the one that created us) or if it is operating -in</FONT> -<BR><FONT FACE="Arial,Helvetica"> -one of the thread pool threads. More on this when we get to handle_input().</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_thread_t -creator_;</FONT> -<BR><FONT FACE="Arial,Helvetica">};</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">#endif // CLIENT_HANDLER_H</FONT> - -<P> -<HR WIDTH="100%"> - -<P>Still, we're just not seeing a lot of changes due to intruduction of -the thread pool. 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 deleted file mode 100644 index f4e14834b49..00000000000 --- a/docs/tutorials/007/page06.html +++ /dev/null @@ -1,365 +0,0 @@ -<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. Just a few -though. - -<P> -<HR WIDTH="100%"> -<BR> -<BR><FONT FACE="Arial,Helvetica">// $Id: client_handler.cpp,v 1.1 1998/08/30 -23:47:14 schmidt Exp $</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> 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"> all of the comments that -you've already seen. That way, you can concentrate on the</FONT> -<BR><FONT FACE="Arial,Helvetica"> new items.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</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"> We're going to be registering -and unregistering a couple of times. To make sure that</FONT> -<BR><FONT FACE="Arial,Helvetica"> we use the same flags every -time, I've created these handy macros.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">#define REGISTER_MASK -ACE_Event_Handler::READ_MASK</FONT> -<BR><FONT FACE="Arial,Helvetica">#define REMOVE_MASK -(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"> Our constructor still doesn't -really do anything. We simply initialize the acceptor</FONT> -<BR><FONT FACE="Arial,Helvetica"> pointer to "null" and get -our current thread id. The static self() method of ACE_Thread</FONT> -<BR><FONT FACE="Arial,Helvetica"> will return you a thread -id native to your platform.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">Client_Handler::Client_Handler (void)</FONT> -<BR><FONT FACE="Arial,Helvetica"> : client_acceptor_(0)</FONT> -<BR><FONT FACE="Arial,Helvetica"> ,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"> Query our acceptor for the -concurrency strategy. Notice that we don't bother</FONT> -<BR><FONT FACE="Arial,Helvetica"> to check that our acceptor -pointer is valid. That is proably a bad idea...</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">int Client_Handler::concurrency(void)</FONT> -<BR><FONT FACE="Arial,Helvetica">{</FONT> -<BR><FONT FACE="Arial,Helvetica"> -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"> And here we ask the acceptor -about the thread pool.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</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"> -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"> The destroy() method hasn't -changed since we wrote it back in Tutorial 5.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">void Client_Handler::destroy (void)</FONT> -<BR><FONT FACE="Arial,Helvetica">{</FONT> -<BR><FONT FACE="Arial,Helvetica"> this->peer ().close ();</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> this->reactor ()->remove_handler -(this, REMOVE_MASK );</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> 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"> Back to our open() method. -This is straight out of Tutorial 6. There's</FONT> -<BR><FONT FACE="Arial,Helvetica"> nothing additional here for -the thread-pool implementation.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">int Client_Handler::open (void *_acceptor)</FONT> -<BR><FONT FACE="Arial,Helvetica">{</FONT> -<BR><FONT FACE="Arial,Helvetica"> client_acceptor( (Client_Acceptor -*) _acceptor );</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> if( concurrency() == Client_Acceptor::thread_per_connection_ -)</FONT> -<BR><FONT FACE="Arial,Helvetica"> {</FONT> -<BR><FONT FACE="Arial,Helvetica"> -return this->activate();</FONT> -<BR><FONT FACE="Arial,Helvetica"> }</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> this->reactor (client_acceptor()->reactor -());</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> ACE_INET_Addr addr;</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> if (this->peer ().get_remote_addr -(addr) == -1)</FONT> -<BR><FONT FACE="Arial,Helvetica"> {</FONT> -<BR><FONT FACE="Arial,Helvetica"> return --1;</FONT> -<BR><FONT FACE="Arial,Helvetica"> }</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> if (this->reactor ()->register_handler -(this, REGISTER_MASK) == -1)</FONT> -<BR><FONT FACE="Arial,Helvetica"> {</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_ERROR_RETURN -((LM_ERROR, "(%P|%t) can't register with reactor\n"), -1);</FONT> -<BR><FONT FACE="Arial,Helvetica"> }</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> 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"> 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"> As mentioned in the header, -the typical way to close an object in a threaded</FONT> -<BR><FONT FACE="Arial,Helvetica"> context is to invoke it's -close() method. Since we already have a handle_close()</FONT> -<BR><FONT FACE="Arial,Helvetica"> method built to cleanup after -us, we'll just forward the request on to that</FONT> -<BR><FONT FACE="Arial,Helvetica"> object.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">int Client_Handler::close(u_long flags)</FONT> -<BR><FONT FACE="Arial,Helvetica">{</FONT> -<BR><FONT FACE="Arial,Helvetica"> -this->handle_close(ACE_INVALID_HANDLE,0);</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -After we've taken care of ourselves, call the baseclass method</FONT> -<BR><FONT FACE="Arial,Helvetica"> -to do any other necessary cleanup.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -*/</FONT> -<BR><FONT FACE="Arial,Helvetica"> -return inherited::close();</FONT> -<BR><FONT FACE="Arial,Helvetica">}</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> In the open() method, we -registered with the reactor and requested to be</FONT> -<BR><FONT FACE="Arial,Helvetica"> notified when there is data -to be read. When the reactor sees that activity</FONT> -<BR><FONT FACE="Arial,Helvetica"> it will invoke this handle_input() -method on us. As I mentioned, the _handle</FONT> -<BR><FONT FACE="Arial,Helvetica"> parameter isn't useful to -us but it narrows the list of methods the reactor</FONT> -<BR><FONT FACE="Arial,Helvetica"> has to worry about and the -list of possible virtual functions we would have</FONT> -<BR><FONT FACE="Arial,Helvetica"> to override.</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> You've read that much before... -Now we have to do some extra stuff in case</FONT> -<BR><FONT FACE="Arial,Helvetica"> we're using the thread-pool -implementation. If we're called by our creator</FONT> -<BR><FONT FACE="Arial,Helvetica"> thread then we must be in -the reactor. In that case, we arrange to be put</FONT> -<BR><FONT FACE="Arial,Helvetica"> into the thread pool. -If we're not in the creator thread then we must be</FONT> -<BR><FONT FACE="Arial,Helvetica"> in the thread pool and we -can do some work.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</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"> ACE_UNUSED_ARG (_handle);</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Check our strategy. -If we're using the thread pool and we're in the creation</FONT> -<BR><FONT FACE="Arial,Helvetica"> -thread then we know we were called by the reactor.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> if( concurrency() == Client_Acceptor::thread_pool_ -)</FONT> -<BR><FONT FACE="Arial,Helvetica"> {</FONT> -<BR><FONT FACE="Arial,Helvetica"> -if( ACE_Thread::self() == creator_ )</FONT> -<BR><FONT FACE="Arial,Helvetica"> -{</FONT> -<BR><FONT FACE="Arial,Helvetica"> -/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -Remove ourselves from the reactor and ask to be put into the thread pool's</FONT> -<BR><FONT FACE="Arial,Helvetica"> -queue of work. (You should be able to use suspend_handler() but I've -had</FONT> -<BR><FONT FACE="Arial,Helvetica"> -problems with that.)</FONT> -<BR><FONT FACE="Arial,Helvetica"> -*/</FONT> -<BR><FONT FACE="Arial,Helvetica"> -this->reactor()->remove_handler( this, REMOVE_MASK );</FONT> -<BR><FONT FACE="Arial,Helvetica"> -return this->thread_pool()->enqueue(this);</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"> Any strategy -other than thread-per-connection will eventually get here. If we're -in the</FONT> -<BR><FONT FACE="Arial,Helvetica"> -single-threaded implementation or the thread-pool, we still have to pass -this way.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> char buf[128];</FONT> -<BR><FONT FACE="Arial,Helvetica"> memset (buf, 0, sizeof (buf));</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Invoke the process() -method to do the work but save it's return value instead</FONT> -<BR><FONT FACE="Arial,Helvetica"> -of returning it immediately.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> int rval = this->process(buf,sizeof(buf));</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Now, we look -again to see if we're in the thread-pool implementation. If so then -we</FONT> -<BR><FONT FACE="Arial,Helvetica"> -need to re-register ourselves with the reactor so that we can get more -work when it</FONT> -<BR><FONT FACE="Arial,Helvetica"> -is available. (If suspend_handler() worked then we would use resume_handler() -here.)</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> if( concurrency() == Client_Acceptor::thread_pool_ -)</FONT> -<BR><FONT FACE="Arial,Helvetica"> {</FONT> -<BR><FONT FACE="Arial,Helvetica"> -if( rval != -1 )</FONT> -<BR><FONT FACE="Arial,Helvetica"> -{</FONT> -<BR><FONT FACE="Arial,Helvetica"> -this->reactor()->register_handler( this, REGISTER_MASK );</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"> Return the result -of process()</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> 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"> ACE_UNUSED_ARG (_handle);</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_UNUSED_ARG (_mask);</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> this->destroy ();</FONT> -<BR><FONT FACE="Arial,Helvetica"> 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"> Remember that when we leave -our svc() method, the framework will take care</FONT> -<BR><FONT FACE="Arial,Helvetica"> of calling our close() method -so that we can cleanup after ourselves.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">int Client_Handler::svc(void)</FONT> -<BR><FONT FACE="Arial,Helvetica">{</FONT> -<BR><FONT FACE="Arial,Helvetica"> char buf[128];</FONT> -<BR><FONT FACE="Arial,Helvetica"> memset (buf, 0, sizeof (buf));</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> while( 1 )</FONT> -<BR><FONT FACE="Arial,Helvetica"> {</FONT> -<BR><FONT FACE="Arial,Helvetica"> if( this->process(buf,sizeof(buf)) -== -1 )</FONT> -<BR><FONT FACE="Arial,Helvetica"> -{</FONT> -<BR><FONT FACE="Arial,Helvetica"> -return(-1);</FONT> -<BR><FONT FACE="Arial,Helvetica"> }</FONT> -<BR><FONT FACE="Arial,Helvetica"> }</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> 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"> Once again, we see that the -application-level logic has not been at all affected</FONT> -<BR><FONT FACE="Arial,Helvetica"> by our choice of threading -models. Of course, I'm not sharing data between threads</FONT> -<BR><FONT FACE="Arial,Helvetica"> or anything. We'll -leave locking issues for a later tutorial.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</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"> switch (this->peer ().recv (_rdbuf, -_rdbuf_len))</FONT> -<BR><FONT FACE="Arial,Helvetica"> {</FONT> -<BR><FONT FACE="Arial,Helvetica"> case -1:</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_ERROR_RETURN -((LM_ERROR, "(%P|%t) %p bad read\n", "client"), -1);</FONT> -<BR><FONT FACE="Arial,Helvetica"> case 0:</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_ERROR_RETURN -((LM_ERROR, "(%P|%t) closing daemon (fd = %d)\n", this->get_handle ()), --1);</FONT> -<BR><FONT FACE="Arial,Helvetica"> default:</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_DEBUG -((LM_DEBUG, "(%P|%t) from client: %s", _rdbuf));</FONT> -<BR><FONT FACE="Arial,Helvetica"> }</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> return 0;</FONT> -<BR><FONT FACE="Arial,Helvetica">}</FONT> - -<P> -<HR WIDTH="100%"> - -<P>Ok, now we've gone and changed handle_input() so that it knows when -to do work and when to enqueue itself. 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 deleted file mode 100644 index 4c6905ebf33..00000000000 --- a/docs/tutorials/007/page07.html +++ /dev/null @@ -1,197 +0,0 @@ -<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. The first is <A HREF="thread_pool.h">thread_pool.h</A> -where we declare our Thread_Pool object. 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"> In order to implement a thread -pool, we have to have an object that can create</FONT> -<BR><FONT FACE="Arial,Helvetica"> a thread. The ACE_Task<> -is the basis for doing just such a thing.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</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"> We need a forward reference -for ACE_Event_Handler so that our enqueue() method</FONT> -<BR><FONT FACE="Arial,Helvetica"> can accept a pointer to one.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</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"> Although we modified the -rest of our program to make use of the thread pool</FONT> -<BR><FONT FACE="Arial,Helvetica"> implementation, if you look -closely you'll see that the changes were rather</FONT> -<BR><FONT FACE="Arial,Helvetica"> minor. The "ACE way" -is generally to create a helper object that abstracts</FONT> -<BR><FONT FACE="Arial,Helvetica"> away the details not relevant -to your application. That's what I'm trying</FONT> -<BR><FONT FACE="Arial,Helvetica"> to do here by creating the -Thread_Pool object.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">class Thread_Pool : public ACE_Task<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"> -/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -Provide an enumeration for the default pool size. By doing this, -other objects</FONT> -<BR><FONT FACE="Arial,Helvetica"> -can use the value when they want a default.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -*/</FONT> -<BR><FONT FACE="Arial,Helvetica"> -enum size_t</FONT> -<BR><FONT FACE="Arial,Helvetica"> -{</FONT> -<BR><FONT FACE="Arial,Helvetica"> -default_pool_size_ = 5</FONT> -<BR><FONT FACE="Arial,Helvetica"> -};</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -// Basic constructor</FONT> -<BR><FONT FACE="Arial,Helvetica"> -Thread_Pool(void);</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -Opening the thread pool causes one or more threads to be activated. -When activated,</FONT> -<BR><FONT FACE="Arial,Helvetica"> -they all execute the svc() method declared below.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -*/</FONT> -<BR><FONT FACE="Arial,Helvetica"> -int open( int _pool_size = default_pool_size_ );</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -When you're done wit the thread pool, you have to have some way to shut -it down.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -This is what close() is for.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -*/</FONT> -<BR><FONT FACE="Arial,Helvetica"> -int close(void);</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -To use the thread pool, you have to put some unit of work into it. -Since we're</FONT> -<BR><FONT FACE="Arial,Helvetica"> -dealing with event handlers (or at least their derivatives), I've chosen -to provide</FONT> -<BR><FONT FACE="Arial,Helvetica"> -an enqueue() method that takes a pointer to an ACE_Event_Handler. -The handler's</FONT> -<BR><FONT FACE="Arial,Helvetica"> -handle_input() method will be called, so your object has to know when it -is being</FONT> -<BR><FONT FACE="Arial,Helvetica"> -called by the thread pool.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -*/</FONT> -<BR><FONT FACE="Arial,Helvetica"> -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"> -/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -Our svc() method will dequeue the enqueued event handler objects and invoke -the</FONT> -<BR><FONT FACE="Arial,Helvetica"> -handle_input() method on each. Since we're likely running in more -than one thread,</FONT> -<BR><FONT FACE="Arial,Helvetica"> -idle threads can take work from the queue while other threads are busy -executing</FONT> -<BR><FONT FACE="Arial,Helvetica"> -handle_input() on some object.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -*/</FONT> -<BR><FONT FACE="Arial,Helvetica"> -int svc(void);</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -Another handy ACE template is ACE_Atomic_Op<>. When parameterized, -this allows</FONT> -<BR><FONT FACE="Arial,Helvetica"> -is to have a thread-safe counting object. The typical arithmetic -operators are</FONT> -<BR><FONT FACE="Arial,Helvetica"> -all internally thread-safe so that you can share it across threads without -worrying</FONT> -<BR><FONT FACE="Arial,Helvetica"> -about any contention issues.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -*/</FONT> -<BR><FONT FACE="Arial,Helvetica"> -typedef ACE_Atomic_Op<ACE_Mutex,int> counter_t;</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -We use the atomic op to keep a count of the number of threads in which -our svc()</FONT> -<BR><FONT FACE="Arial,Helvetica"> -method is running. This is particularly important when we want to -close() it down!</FONT> -<BR><FONT FACE="Arial,Helvetica"> -*/</FONT> -<BR><FONT FACE="Arial,Helvetica"> -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. 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 deleted file mode 100644 index 094804e743d..00000000000 --- a/docs/tutorials/007/page08.html +++ /dev/null @@ -1,537 +0,0 @@ -<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%"> - -<P><FONT FACE="Arial,Helvetica">// $Id: thread_pool.cpp,v 1.1 1998/08/30 -23:47:15 schmidt 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"> We need this header so that -we can invoke handle_input() on the objects we dequeue.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">#include "ace/Event_Handler.h"</FONT> -<BR><FONT FACE="Arial,Helvetica"></FONT> <FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> All we do here is initialize -our active thread counter.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">Thread_Pool::Thread_Pool(void)</FONT> -<BR><FONT FACE="Arial,Helvetica"> : 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"> Our open() method is a thin -disguise around the ACE_Task<> activate() method. By</FONT> -<BR><FONT FACE="Arial,Helvetica"> hiding activate() in this -way, the users of Thread_Pool don't have to worry about</FONT> -<BR><FONT FACE="Arial,Helvetica"> the thread configuration -flags.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</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"> 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"> Closing the thread pool can -be a tricky exercise. I've decided to take an easy approach</FONT> -<BR><FONT FACE="Arial,Helvetica"> and simply enqueue a secret -message for each thread we have active.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">int Thread_Pool::close(void)</FONT> -<BR><FONT FACE="Arial,Helvetica">{</FONT> -<BR><FONT FACE="Arial,Helvetica"> -/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -Find out how many threads are currently active</FONT> -<BR><FONT FACE="Arial,Helvetica"> -*/</FONT> -<BR><FONT FACE="Arial,Helvetica"> -int counter = active_threads_.value();</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -For each one of the active threads, enqueue a "null" event handler. -Below, we'll</FONT> -<BR><FONT FACE="Arial,Helvetica"> -teach our svc() method that "null" means "shutdown".</FONT> -<BR><FONT FACE="Arial,Helvetica"> -*/</FONT> -<BR><FONT FACE="Arial,Helvetica"> -while( counter-- )</FONT> -<BR><FONT FACE="Arial,Helvetica"> -{</FONT> -<BR><FONT FACE="Arial,Helvetica"> -this->enqueue( 0 );</FONT> -<BR><FONT FACE="Arial,Helvetica"> -}</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -As each svc() method exits, it will decrement the active thread counter. -We just wait</FONT> -<BR><FONT FACE="Arial,Helvetica"> -here for it to reach zero. Since we don't know how long it will take, -we sleep for</FONT> -<BR><FONT FACE="Arial,Helvetica"> -a quarter-second or so between tries.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -*/</FONT> -<BR><FONT FACE="Arial,Helvetica"> -while( active_threads_.value() )</FONT> -<BR><FONT FACE="Arial,Helvetica"> -{</FONT> -<BR><FONT FACE="Arial,Helvetica"> -ACE_OS::sleep( ACE_Time_Value(0.25) );</FONT> -<BR><FONT FACE="Arial,Helvetica"> -}</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -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"> When an object wants to do -work in the pool, it should call the enqueue() method.</FONT> -<BR><FONT FACE="Arial,Helvetica"> We introduce the ACE_Message_Block -here but, unfortunately, we seriously missuse it.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</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"> -/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -An ACE_Message_Block is a chunk of data. You put them into an ACE_Message_Queue.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -ACE_Task<> has an ACE_Message_Queue built in. In fact, the parameter -to ACE_Task<></FONT> -<BR><FONT FACE="Arial,Helvetica"> -is passed directly to ACE_Message_Queue. If you look back at our -header file you'll</FONT> -<BR><FONT FACE="Arial,Helvetica"> -see that we used ACE_MT_SYNCH as the parameter indicating that we want -MultiThread</FONT> -<BR><FONT FACE="Arial,Helvetica"> -Synch safety. This allows us to safely put ACE_Message_Block objects -into the</FONT> -<BR><FONT FACE="Arial,Helvetica"> -message queue in one thread and take them out in another.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -*/</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -An ACE_Message_Block wants to have char* data. We don't have that. -We could</FONT> -<BR><FONT FACE="Arial,Helvetica"> -cast our ACE_Event_Handler* directly to a char* but I wanted to be more -explicit.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -Since casting pointers around is a dangerous thing, I've gone out of my -way here</FONT> -<BR><FONT FACE="Arial,Helvetica"> -to be very clear about what we're doing.</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -First: Cast the handler pointer to a void pointer. You can't -do any useful work</FONT> -<BR><FONT FACE="Arial,Helvetica"> -on a void pointer, so this is a clear message that we're making the</FONT> -<BR><FONT FACE="Arial,Helvetica"> -pointer unusable.</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -Next: Cast the void pointer to a char pointer that the ACE_Message_Block -will accept.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -*/</FONT> -<BR><FONT FACE="Arial,Helvetica"> -void * v_data = (void*)_handler;</FONT> -<BR><FONT FACE="Arial,Helvetica"> -char * c_data = (char*)v_data;</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -Construct a new ACE_Message_Block. For efficiency, you might want -to preallocate a</FONT> -<BR><FONT FACE="Arial,Helvetica"> -stack of these and reuse them. For simplicity, I'll just create what -I need as I need it.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -*/</FONT> -<BR><FONT FACE="Arial,Helvetica"> -ACE_Message_Block * mb = new ACE_Message_Block( c_data );</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -Our putq() method is a wrapper around one of the enqueue methods of the -ACE_Message_Queue</FONT> -<BR><FONT FACE="Arial,Helvetica"> -that we own. Like all good methods, it returns -1 if it fails for -some reason.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -*/</FONT> -<BR><FONT FACE="Arial,Helvetica"> -if( this->putq(mb) == -1 )</FONT> -<BR><FONT FACE="Arial,Helvetica"> -{</FONT> -<BR><FONT FACE="Arial,Helvetica"> -/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -Another trait of the ACE_Message_Block objects is that they are reference -counted.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -Since they're designed to be passed around between various objects in several -threads</FONT> -<BR><FONT FACE="Arial,Helvetica"> -we can't just delete them whenever we feel like it. The release() -method is similar</FONT> -<BR><FONT FACE="Arial,Helvetica"> -to the destroy() method we've used elsewhere. It watches the reference -count and will</FONT> -<BR><FONT FACE="Arial,Helvetica"> -delete the object when possible.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -*/</FONT> -<BR><FONT FACE="Arial,Helvetica"> -mb->release();</FONT> -<BR><FONT FACE="Arial,Helvetica"> -return(-1);</FONT> -<BR><FONT FACE="Arial,Helvetica"> -}</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -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"> The "guard" concept is very -powerful and used throughout multi-threaded applications.</FONT> -<BR><FONT FACE="Arial,Helvetica"> A guard normally does some -operation on an object at construction and the "opposite"</FONT> -<BR><FONT FACE="Arial,Helvetica"> operation at destruction. -For instance, when you guard a mutex (lock) object, the guard</FONT> -<BR><FONT FACE="Arial,Helvetica"> will acquire the lock on -construction and release it on destruction. In this way, your</FONT> -<BR><FONT FACE="Arial,Helvetica"> 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"> Guards aren't only useful -for locks however. In this application I've created two guard</FONT> -<BR><FONT FACE="Arial,Helvetica"> objects for quite a different -purpose.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> The Counter_Guard is constructed -with a reference to the thread pool's active thread</FONT> -<BR><FONT FACE="Arial,Helvetica"> counter. The guard -increments the counter when it is created and decrements it at</FONT> -<BR><FONT FACE="Arial,Helvetica"> destruction. By creating -one of these in svc(), I know that the counter will be decremented</FONT> -<BR><FONT FACE="Arial,Helvetica"> no matter how or where svc() -returns.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</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"> -Counter_Guard( Thread_Pool::counter_t & _counter )</FONT> -<BR><FONT FACE="Arial,Helvetica"> -: counter_(_counter)</FONT> -<BR><FONT FACE="Arial,Helvetica"> -{</FONT> -<BR><FONT FACE="Arial,Helvetica"> -++counter_;</FONT> -<BR><FONT FACE="Arial,Helvetica"> -}</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -~Counter_Guard(void)</FONT> -<BR><FONT FACE="Arial,Helvetica"> -{</FONT> -<BR><FONT FACE="Arial,Helvetica"> ---counter_;</FONT> -<BR><FONT FACE="Arial,Helvetica"> -}</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">protected:</FONT> -<BR><FONT FACE="Arial,Helvetica"> -Thread_Pool::counter_t & counter_;</FONT> -<BR><FONT FACE="Arial,Helvetica">};</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> My Message_Block_Guard is -also a little non-traditional. It doesn't do anything in the</FONT> -<BR><FONT FACE="Arial,Helvetica"> constructor but it's destructor -ensures that the message block's release() method is called.</FONT> -<BR><FONT FACE="Arial,Helvetica"> 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"> */</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"> -Message_Block_Guard( ACE_Message_Block * & _mb )</FONT> -<BR><FONT FACE="Arial,Helvetica"> -: mb_(_mb)</FONT> -<BR><FONT FACE="Arial,Helvetica"> -{</FONT> -<BR><FONT FACE="Arial,Helvetica"> -}</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -~Message_Block_Guard( void )</FONT> -<BR><FONT FACE="Arial,Helvetica"> -{</FONT> -<BR><FONT FACE="Arial,Helvetica"> -mb_->release();</FONT> -<BR><FONT FACE="Arial,Helvetica"> -}</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">protected:</FONT> -<BR><FONT FACE="Arial,Helvetica"> -ACE_Message_Block * & mb_;</FONT> -<BR><FONT FACE="Arial,Helvetica">};</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Now we come to the svc() -method. As I said, this is being executed in each thread of the</FONT> -<BR><FONT FACE="Arial,Helvetica"> Thread_Pool. Here, -we pull messages off of our built-in ACE_Message_Queue and cause them</FONT> -<BR><FONT FACE="Arial,Helvetica"> to do work.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">int Thread_Pool::svc(void)</FONT> -<BR><FONT FACE="Arial,Helvetica">{</FONT> -<BR><FONT FACE="Arial,Helvetica"> -/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -The getq() method takes a reference to a pointer. So... we need a -pointer to give it</FONT> -<BR><FONT FACE="Arial,Helvetica"> -a reference to.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -*/</FONT> -<BR><FONT FACE="Arial,Helvetica"> -ACE_Message_Block * mb;</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -Create the guard for our active thread counter object. No matter -where we choose to</FONT> -<BR><FONT FACE="Arial,Helvetica"> -return() from svc(), we no know that the counter will be decremented.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -*/</FONT> -<BR><FONT FACE="Arial,Helvetica"> -Counter_Guard counter_guard(active_threads_);</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -Get messages from the queue until we have a failure. There's no real -good reason</FONT> -<BR><FONT FACE="Arial,Helvetica"> -for failure so if it happens, we leave immediately.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -*/</FONT> -<BR><FONT FACE="Arial,Helvetica"> -while( this->getq(mb) != -1 )</FONT> -<BR><FONT FACE="Arial,Helvetica"> -{</FONT> -<BR><FONT FACE="Arial,Helvetica"> -/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -A successful getq() will cause "mb" to point to a valid refernce-counted</FONT> -<BR><FONT FACE="Arial,Helvetica"> -ACE_Message_Block. We use our guard object here so that we're sure -to call</FONT> -<BR><FONT FACE="Arial,Helvetica"> -the release() method of that message block and reduce it's reference count.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -Once the count reaches zero, it will be deleted.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -*/</FONT> -<BR><FONT FACE="Arial,Helvetica"> -Message_Block_Guard message_block_guard(mb);</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -As noted before, the ACE_Message_Block stores it's data as a char*. -We pull that</FONT> -<BR><FONT FACE="Arial,Helvetica"> -out here and later turn it into an ACE_Event_Handler*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -*/</FONT> -<BR><FONT FACE="Arial,Helvetica"> -char * c_data = mb->base();</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -We've chosen to use a "null" value as an indication to leave. If -the data we got</FONT> -<BR><FONT FACE="Arial,Helvetica"> -from the queue is not null then we have some work to do.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -*/</FONT> -<BR><FONT FACE="Arial,Helvetica"> -if( c_data )</FONT> -<BR><FONT FACE="Arial,Helvetica"> -{</FONT> -<BR><FONT FACE="Arial,Helvetica"> -/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -Once again, we go to great lengths to emphasize the fact that we're casting -pointers</FONT> -<BR><FONT FACE="Arial,Helvetica"> -around in rather impolite ways. We could have cast the char* directly -to an</FONT> -<BR><FONT FACE="Arial,Helvetica"> -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"> -(Note: The correct way to use an ACE_Message_Block is to write data -into it.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -What I should have done was create a message block big enough to hold an</FONT> -<BR><FONT FACE="Arial,Helvetica"> -event handler pointer and then written the pointer value into the block. -When</FONT> -<BR><FONT FACE="Arial,Helvetica"> -we got here, I would have to read that data back into a pointer. -While politically</FONT> -<BR><FONT FACE="Arial,Helvetica"> -correct, it is also a lot of work. If you're careful you can get -away with casting</FONT> -<BR><FONT FACE="Arial,Helvetica"> -pointers around.)</FONT> -<BR><FONT FACE="Arial,Helvetica"> -*/</FONT> -<BR><FONT FACE="Arial,Helvetica"> -void * v_data = (void*)c_data;</FONT> -<BR><FONT FACE="Arial,Helvetica"> </FONT> -<BR><FONT FACE="Arial,Helvetica"> -ACE_Event_Handler * handler = (ACE_Event_Handler*)v_data;</FONT> -<BR><FONT FACE="Arial,Helvetica"> </FONT> -<BR><FONT FACE="Arial,Helvetica"> -/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -Now that we finally have an event handler pointer, invoke it's handle_input() -method.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -Since we don't know it's handle, we just give it a default. That's -OK because we</FONT> -<BR><FONT FACE="Arial,Helvetica"> -know that we're not using the handle in the method anyway.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -*/</FONT> -<BR><FONT FACE="Arial,Helvetica"> -if( handler->handle_input(ACE_INVALID_HANDLE) == -1 )</FONT> -<BR><FONT FACE="Arial,Helvetica"> -{</FONT> -<BR><FONT FACE="Arial,Helvetica"> -/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -Tell the handler that it's time to go home. The "normal" method for -shutting</FONT> -<BR><FONT FACE="Arial,Helvetica"> -down a handler whose handler failed is to invoke handle_close(). -This will</FONT> -<BR><FONT FACE="Arial,Helvetica"> -take care of cleaning it up for us.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -Notice how we use the handler's get_handle() method to populate it's "handle"</FONT> -<BR><FONT FACE="Arial,Helvetica"> -parameter. Convenient isn't it?</FONT> -<BR><FONT FACE="Arial,Helvetica"> -*/</FONT> -<BR><FONT FACE="Arial,Helvetica"> -handler->handle_close(handler->get_handle(),0);</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -Also notice that we don't exit the svc() method here! The first time -I did</FONT> -<BR><FONT FACE="Arial,Helvetica"> -this, I was exiting. After a few clients disconnect you have an empty</FONT> -<BR><FONT FACE="Arial,Helvetica"> -thread pool. Hard to do any more work after that...</FONT> -<BR><FONT FACE="Arial,Helvetica"> -*/</FONT> -<BR><FONT FACE="Arial,Helvetica"> -}</FONT> -<BR><FONT FACE="Arial,Helvetica"> -}</FONT> -<BR><FONT FACE="Arial,Helvetica"> -else</FONT> -<BR><FONT FACE="Arial,Helvetica"> -{</FONT> -<BR><FONT FACE="Arial,Helvetica"> -/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -If we get here, we were given a message block with "null" data. That -is our</FONT> -<BR><FONT FACE="Arial,Helvetica"> -signal to leave, so we return(0) to leave gracefully.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -*/</FONT> -<BR><FONT FACE="Arial,Helvetica"> -return(0); -// Ok, shutdown request</FONT> -<BR><FONT FACE="Arial,Helvetica"> -}</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -// message_block_guard goes out of scope here</FONT> -<BR><FONT FACE="Arial,Helvetica"> -// and releases the message_block instance.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -}</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -return(0);</FONT> -<BR><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 deleted file mode 100644 index af87b79444c..00000000000 --- a/docs/tutorials/007/page09.html +++ /dev/null @@ -1,64 +0,0 @@ -<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. As with Tutorial 6, we really didn't -have to change much to introduce a new threading strategy. Most of -the work was in creating the Thread_Pool object itself. Everything -else was just minor housekeeping. - -<P>There is a fourth common thread strategy: thread-per-request. -It's not one of my favorites, so I wasn't planning to go into it. -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_pool.cpp</A></LI> - -<LI> -<A HREF="fix.Makefile">fix.Makefile</A></LI> -</UL> - - -<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 deleted file mode 100644 index 55fb69c58ef..00000000000 --- a/docs/tutorials/007/server.cpp +++ /dev/null @@ -1,119 +0,0 @@ -// $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; -} - -#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION) -template class ACE_Acceptor <Client_Handler, ACE_SOCK_ACCEPTOR>; -template class ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH>; -template class ACE_Guard<ACE_Mutex>; -template class ACE_Atomic_Op<ACE_Mutex, int>; -#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA) -#pragma instantiate ACE_Acceptor <Client_Handler, ACE_SOCK_ACCEPTOR> -#pragma instantiate ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH> -#pragma instantiate ACE_Guard<ACE_Mutex> -#pragma instantiate ACE_Atomic_Op<ACE_Mutex, int> -#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */ diff --git a/docs/tutorials/007/thread_pool.cpp b/docs/tutorials/007/thread_pool.cpp deleted file mode 100644 index 0719243df84..00000000000 --- a/docs/tutorials/007/thread_pool.cpp +++ /dev/null @@ -1,275 +0,0 @@ - -// $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,_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 ) - { - /* - Tell the handler that it's time to go home. The "normal" method for shutting - down a handler whose handler failed is to invoke handle_close(). This will - take care of cleaning it up for us. - Notice how we use the handler's get_handle() method to populate it's "handle" - parameter. Convenient isn't it? - */ - handler->handle_close(handler->get_handle(),0); - - /* - Also notice that we don't exit the svc() method here! The first time I did - this, I was exiting. After a few clients disconnect you have an empty - thread pool. Hard to do any more work after that... - */ - } - } - 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 deleted file mode 100644 index ebf2e162ce4..00000000000 --- a/docs/tutorials/007/thread_pool.h +++ /dev/null @@ -1,107 +0,0 @@ - -// $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: - - typedef ACE_Task<ACE_MT_SYNCH> inherited; - - /* - 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_ ); - - /* - Some compilers will complain that our open() above attempts to - override a virtual function in the baseclass. We have no - intention of overriding that method but in order to keep the - compiler quiet we have to add this method as a pass-thru to the - baseclass method. - */ - virtual int open(void * _void_data) - { return inherited::open(_void_data); } - - /* - 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 ); - - /* - Just like open() we have to provide a bogus method that will - invoke the baseclass close() to keep some compilers quiet. - */ - virtual int close( u_long flags ) - { return inherited::close(flags); } - - /* - 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 ); - - /* - 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; - -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); - - /* - 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 diff --git a/docs/tutorials/008/Makefile b/docs/tutorials/008/Makefile deleted file mode 100644 index 0b92cbfcc8c..00000000000 --- a/docs/tutorials/008/Makefile +++ /dev/null @@ -1,61 +0,0 @@ -#---------------------------------------------------------------------------- -# $Id$ -#---------------------------------------------------------------------------- - -#---------------------------------------------------------------------------- -# Local macros -#---------------------------------------------------------------------------- - -BIN = server directed_client broadcast_client - -FILES = - -BUILD = $(VBIN) - -HDR = *.h - -#---------------------------------------------------------------------------- -# Include macros and targets -#---------------------------------------------------------------------------- - -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 -#---------------------------------------------------------------------------- - -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 - -Depend : depend - perl ../fix.Makefile - -.depend : # - touch .depend - -#---------------------------------------------------------------------------- -# 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/008/broadcast_client.cpp b/docs/tutorials/008/broadcast_client.cpp deleted file mode 100644 index 2f754806d03..00000000000 --- a/docs/tutorials/008/broadcast_client.cpp +++ /dev/null @@ -1,72 +0,0 @@ - -// $Id$ - -#include "ace/SOCK_Dgram_Bcast.h" -#include "ace/INET_Addr.h" - -static const u_short PORT = ACE_DEFAULT_SERVER_PORT; - -int main(int argc,char *argv[] ) -{ - ACE_INET_Addr local((u_short)0); - - /* - Instead of creating the ACE_SOCK_Dgram we created last time, - we'll create an ACE_SOCK_Dgram_Bcast. "Bcast" means, of course, - "Broadcast". This ACE object is clever enough to go out to the - OS and find all of the network interfaces. When you send() - on a Dgram_Bcast, it will send the datagram out on all of those - interfaces. This is quiet handy if you do it on a multi-homed - host that plays router... - */ - ACE_SOCK_Dgram_Bcast dgram; - - if( dgram.open(local) == -1 ) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "datagram open"),-1); - } - - char buf[512]; - - sprintf(buf, "Hello World!"); - - /* - The only other difference between us and the directed client - is that we don't specify a host to receive the datagram. - Instead, we use the magic value "INADDR_BROADCAST". All hosts - are obliged to respond to datagrams directed to this address - the same as they would to datagrams sent to their hostname. - - Remember, the Dgram_Bcast will send a datagram to all interfaces - on the host. That's true even if the address is for a specific - host (and the host address makes sense for the interface). - The real power is in using an INADDR_BROADCAST addressed datagram - against all interfaces. - */ - - ACE_INET_Addr remote(PORT,INADDR_BROADCAST); - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Sending (%s) to the server.\n",buf)); - - if( dgram.send(buf,strlen(buf)+1,remote) == -1 ) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "send"),-1); - } - - if( dgram.recv(buf,sizeof(buf),remote) == -1 ) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "recv"),-1); - } - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) The server said: %s\n",buf)); - - /* - Using the "remote" object instance, find out where the server lives. - We could then save this address and use directed datagrams to chat - with the server for a while. - */ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) The server can be found at: (%s:%d)\n", - remote.get_host_name(), PORT )); - - return(0); -} diff --git a/docs/tutorials/008/directed_client.cpp b/docs/tutorials/008/directed_client.cpp deleted file mode 100644 index 7fac216dbc3..00000000000 --- a/docs/tutorials/008/directed_client.cpp +++ /dev/null @@ -1,112 +0,0 @@ - -// $Id$ - -#include "ace/SOCK_Dgram.h" -#include "ace/INET_Addr.h" - -/* - Once again, we use the default server port. In a "real" system, - the server's port (or ports) would be published in some way so - that clients would know where to "look". We could even add entries - to the operating system's services file and use a service name - instead of a number. We'll come back to that in some other tutorial - though. For now, let's stay simple. - */ -static const u_short PORT = ACE_DEFAULT_SERVER_PORT; - -/* - Our goal here is to develop a client that can send a datagram to - a server running on a known host. We'll use a command-line argument - to specify the hostname instead of hard-coding it. - */ -int main(int argc,char *argv[] ) -{ - /* - All datagrams have to have a point of origin. Since we intend to - transmit instead of receive, we initialize an address with zero - and let the OS choose a port for us. We could have chosen our - own value between 1025 and 65535 as long as it isn't already in use. - */ - ACE_INET_Addr local((u_short)0); - - /* - And here is our datagram object. - */ - ACE_SOCK_Dgram dgram; - - /* - Notice that this looks a lot like the server application. There's - no difference in creating server datagrams an client datagrams. - You can even use a zero-constructed address for your server datagram - as long as you tell the client where you're listening (eg -- by writting - into a file or some such). - */ - if( dgram.open(local) == -1 ) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "datagram open"),-1); - } - - /* - Yep. We've seen this before too... - */ - char buf[512]; - - /* - Ok, now we're doing something different. - */ - sprintf(buf, "Hello World!"); - - /* - Just like sending a telegram, we have to address our datagram. - Here, we create an address object at the desired port on the - chosen host. To keep us from crashing, we'll provide a default - host name if we aren't given one. - */ - ACE_INET_Addr remote(PORT, argc > 1 ? argv[1] : "localhost" ); - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Sending (%s) to the server.\n",buf)); - /* - Now we send our buffer of stuff to the remote address. This is - just exactly what the server did after receiving a client message. - Datagrams are rather orthogonal that way: they don't generally make - much of a fuss about being either client or server. - */ - if( dgram.send(buf,strlen(buf)+1,remote) == -1 ) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "send"),-1); - } - - /* - Now we've turned around and put ourselves into "server mode" by - invoking the recv() method. We now our server is going to send - us something, so we hang out here and wait for it. Because we - know datagrams are unreliable, there is a chance that the server - will respond but we won't hear. You might consider providing a - timeout on the recv() in that case. If recv() fails due to timeout - it will return -1 and you can then resend your query and attempt - the recv() again. - - Like the server application, we have to give the recv() an - uninitialized addr object so that we can find out who is talking - back to us. - */ - if( dgram.recv(buf,sizeof(buf),remote) == -1 ) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "recv"),-1); - } - - /* - Find out what the server had to say. - */ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) The server said: %s\n",buf)); - - /* - Using the "remote" object instance, find out where the server lives. - We could then save this address and use directed datagrams to chat - with the server for a while. - */ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) The server can be found at: (%s:%d)\n", - remote.get_host_name(), PORT )); - - return(0); -} diff --git a/docs/tutorials/008/page01.html b/docs/tutorials/008/page01.html deleted file mode 100644 index ebe24e9ecc8..00000000000 --- a/docs/tutorials/008/page01.html +++ /dev/null @@ -1,60 +0,0 @@ -<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"> - <TITLE>ACE Tutorial 008</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 008</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Sending and receiving datagrams</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> - -<P>In a lot of IPC programming, the clients know where the servers -are. A mail client, for instance, has a configuration file that says -where the mail host is. Your web browser has a "location" field that -you type into to give it a destination. - -<P>What if you have written a server application and then you execute it -on several systems in your network? All of the instances are probably -more or less equal to the client's point of view, so you don't want to -"configure" the clients to a single server each. Likewise, you -want the ability to add and remove servers at any time so you can't just -give the clients a list to choose from. - -<P>So... how do the clients know where the servers are? - -<P>Let 'em ask! - -<P>Datagrams are great for this. You can toss a datagram out onto -the network and any servers listening at the correct port will* hear it. -Like ACE_SOCK_Stream that we've seen before, you can get the peer address -from a datagram. With that, the server can send a response -back to the client. The client, in turn, can pull the peer address -out and know exactly where the server lives. - -<P>In this tutorial we'll develop three applications: a server listening -for datagrams, a client that can send to a known host and a client that -can send to the entire (sub)network. In the next tutorial, we'll -expand on this to make the server a bit more prudish. -<BR> - -<P><FONT SIZE=-1>* Actually, the servers <I>might</I> hear the datagram. -Datagrams are rather unreliable. (Sort of like some operating systems -I know.) Still, if the network traffic isn't too bad, they generally -get through. Your clients can always send out more queries if there -aren't any responses in a timely fashion.</FONT> - -<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/008/page02.html b/docs/tutorials/008/page02.html deleted file mode 100644 index 85b8c083d88..00000000000 --- a/docs/tutorials/008/page02.html +++ /dev/null @@ -1,237 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="GENERATOR" CONTENT="Mozilla/4.05 [en] (WinNT; I) [Netscape]"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 008</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 008</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Sending and receiving datagrams</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> - -<P>The first thing we want to look at is <A HREF="server.cpp">server.cpp</A>. -This is a pretty simple application that listens for datagrams at a known -port and sends back a response. In order to implement a true "discovery" -mechanism, the server will have to be a little bit more picky about who -it responds to. We'll tackle that issue in the next tutorial though... - -<P> -<HR WIDTH="100%"> - -<P><TT>/*</TT> -<BR><TT> Our datagram server will, of course, need to create -a datagram.</TT> -<BR><TT> We'll also need an address object so that we know -where to listen.</TT> -<BR><TT> */</TT> -<BR><TT>#include "ace/SOCK_Dgram.h"</TT> -<BR><TT>#include "ace/INET_Addr.h"</TT> - -<P><TT>/*</TT> -<BR><TT> Use the typical TCP/IP port address for receiving -datagrams.</TT> -<BR><TT> */</TT> -<BR><TT>static const u_short PORT = ACE_DEFAULT_SERVER_PORT;</TT> - -<P><TT>int main(int,char**)</TT> -<BR><TT>{</TT> -<BR><TT> /*</TT> -<BR><TT> This is where we'll listen -for datagrams coming from the</TT> -<BR><TT> clients. We'll give -this address to the open() method</TT> -<BR><TT> below to enable the listener.</TT> -<BR><TT> */</TT> -<BR><TT> ACE_INET_Addr local(PORT);</TT> - -<P><TT> /*</TT> -<BR><TT> A simply constructed datagram -that we'll listen with.</TT> -<BR><TT> */</TT> -<BR><TT> ACE_SOCK_Dgram dgram;</TT> - -<P><TT> /*</TT> -<BR><TT> Like most ACE objects, the -datagram has to be opened before</TT> -<BR><TT> it can be uses. Of course, --1 on failure.</TT> - -<P><TT> A datagram will fail to open -if there is already a datagram</TT> -<BR><TT> listening at the port we've -chosen. It *is* OK to open</TT> -<BR><TT> a datagram at a port where -there is an ACE_SOCK_Stream</TT> -<BR><TT> though. This is because -datagrams are UDP and SOCK_Stream</TT> -<BR><TT> is TCP and the two don't cross -paths.</TT> -<BR><TT> */</TT> -<BR><TT> if( dgram.open(local) == -1 )</TT> -<BR><TT> {</TT> -<BR><TT> ACE_ERROR_RETURN ((LM_ERROR, -"%p\n", "open"),-1);</TT> -<BR><TT> }</TT> - -<P><TT> /*</TT> -<BR><TT> Create a simple buffer to -receive the data. You generally need</TT> -<BR><TT> to provide a buffer big enough -for the largest datagram you</TT> -<BR><TT> expect to receive. Some -platforms will let you read a little</TT> -<BR><TT> and then some more later but -other platforms will throw out</TT> -<BR><TT> whatever part of the datagram -you don't get with the first</TT> -<BR><TT> read. (This is on a -per-datagram basis BTW.) The theoretical</TT> -<BR><TT> limit on a datagram is about -64k. The realistic limit (because</TT> -<BR><TT> of routers & such) is -much smaller. Choose your buffer size</TT> -<BR><TT> based on your application's -needs.</TT> -<BR><TT> */</TT> -<BR><TT> char buf[512];</TT> - -<P><TT> /*</TT> -<BR><TT> Unlike ACE_SOCK_Stream, datagrams -are unconnected. That is,</TT> -<BR><TT> there is no "virtual circuit" -between server and client.</TT> -<BR><TT> Because of this, the server -has to provide a placeholder</TT> -<BR><TT> for the OS to fill in the -source (client) address information</TT> -<BR><TT> on the recv. You can -initialize this INET_Addr to anything,</TT> -<BR><TT> it will be overwritten when -the data arrives.</TT> -<BR><TT> */</TT> -<BR><TT> ACE_INET_Addr remote;</TT> - -<P><TT> ACE_DEBUG ((LM_DEBUG, "(%P|%t) starting up server -daemon\n"));</TT> - -<P><TT> /*</TT> -<BR><TT> Receive datagrams as long -as we're able.</TT> -<BR><TT> */</TT> -<BR><TT> while( dgram.recv(buf,sizeof(buf),remote) != --1 )</TT> -<BR><TT> {</TT> -<BR><TT> /*</TT> -<BR><TT> Display -a brief message about our progress. Notice how we</TT> -<BR><TT> use -the 'remote' object to display the address of the client.</TT> -<BR><TT> With -an ACE_SOCK_Stream we used get_remote_addr() to get the</TT> -<BR><TT> address -the socket is connected to. Because datagrams are</TT> -<BR><TT> unconnected, -we use the addr object provided to recv().</TT> -<BR><TT> */</TT> -<BR><TT> ACE_DEBUG ((LM_DEBUG, -"(%P|%t) Data (%s) from client (%s)\n", buf, remote.get_host_name()));</TT> - -<P><TT> /*</TT> -<BR><TT> To -respond to the client's query, we have to become a client</TT> -<BR><TT> ourselves. -To do so, we need an anonymous local address from</TT> -<BR><TT> which -we'll send the response and a datagram in which to send</TT> -<BR><TT> it. -(An anonymous address is simply one where we let the OS</TT> -<BR><TT> choose -a port for us. We really don't care what it is.O</TT> -<BR><TT> */</TT> -<BR><TT> ACE_INET_Addr -local((u_short)0);</TT> -<BR><TT> ACE_SOCK_Dgram client;</TT> - -<P><TT> /*</TT> -<BR><TT> Open -up our response datagram as always.</TT> -<BR><TT> */</TT> -<BR><TT> if( client.open(local) -== -1 )</TT> -<BR><TT> {</TT> -<BR><TT> -ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "client open"),-1);</TT> -<BR><TT> -return(0);</TT> -<BR><TT> }</TT> - -<P><TT> /*</TT> -<BR><TT> Build -a witty response...</TT> -<BR><TT> */</TT> -<BR><TT> sprintf(buf,"I am here");</TT> - -<P><TT> /*</TT> -<BR><TT> and -send it to the client. Notice the symetry with the recv()</TT> -<BR><TT> method. -Again, the unconnected nature of datagrams forces</TT> -<BR><TT> us -to specify an address object with each read/write operation.</TT> -<BR><TT> In -the case of read (recv()) that's where the OS stuffs the</TT> -<BR><TT> address -of the datagram sender. In the case of write (send())</TT> -<BR><TT> that -we're doing here, the address is where we want the network</TT> -<BR><TT> to -deliver the data.</TT> - -<P><TT> Of -course, we're assuming that the client will be listening</TT> -<BR><TT> for -our reply...</TT> -<BR><TT> */</TT> -<BR><TT> if( client.send(buf,strlen(buf)+1,remote) -== -1 )</TT> -<BR><TT> {</TT> -<BR><TT> -ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "send"),-1);</TT> -<BR><TT> -return(0);</TT> -<BR><TT> }</TT> -<BR><TT> }</TT> - -<P><TT> return(0);</TT> -<BR><TT>}</TT> - -<P> -<HR WIDTH="100%"> - -<P>And that's really all there is to it. Obviously there is some -room for improvement. The most blatant is the somewhat small buffer -size for receiving the datagram. I've never been able to get a solid -answer on datagram sizes. The theoretical limit is just under 64k -but you have to deal with fragmentation. Some readings indicate that -8k is a reasonable size, others go much smaller. My general rule -of thumb is to keep datagrams relatively small (eg -- under 8k or so) and -test a lot. If you find that your routers are fragmenting your larger -datagrams, back off to something smaller. Of course, if you must -send 100k and can only do so 1k at a time, you'll have to worry about retransmissions -& reordering. At that point, you might consider going to TCP. -Remember: datagrams are unreliable! Don't try to make 'em do -something they werent' designed for! - -<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/008/page03.html b/docs/tutorials/008/page03.html deleted file mode 100644 index b1faf3b7287..00000000000 --- a/docs/tutorials/008/page03.html +++ /dev/null @@ -1,187 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="GENERATOR" CONTENT="Mozilla/4.05 [en] (WinNT; I) [Netscape]"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 008</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 008</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Sending and receiving datagrams</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> - -<P>In <A HREF="directed_client.cpp">directed_client.cpp</A> we create a -client that knows how to send a datagram to a server on a known host. -This is a good thing if you know where the server lives and want to have -a conversation. The Unix <I>talk</I> utilitiy, for instance, -could be written this way. - -<P> -<HR WIDTH="100%"> - -<P><TT>#include "ace/SOCK_Dgram.h"</TT> -<BR><TT>#include "ace/INET_Addr.h"</TT> - -<P><TT>/*</TT> -<BR><TT> Once again, we use the default server port. -In a "real" system,</TT> -<BR><TT> the server's port (or ports) would be published in -some way so</TT> -<BR><TT> that clients would know where to "look". We -could even add entries</TT> -<BR><TT> to the operating system's services file and use a -service name</TT> -<BR><TT> instead of a number. We'll come back to that -in some other tutorial</TT> -<BR><TT> though. For now, let's stay simple.</TT> -<BR><TT> */</TT> -<BR><TT>static const u_short PORT = ACE_DEFAULT_SERVER_PORT;</TT> - -<P><TT>/*</TT> -<BR><TT> Our goal here is to develop a client that can send -a datagram to</TT> -<BR><TT> a server running on a known host. We'll use -a command-line argument</TT> -<BR><TT> to specify the hostname instead of hard-coding it.</TT> -<BR><TT> */</TT> -<BR><TT>int main(int argc,char *argv[] )</TT> -<BR><TT>{</TT> -<BR><TT> /*</TT> -<BR><TT> All -datagrams have to have a point of origin. Since we intend to</TT> -<BR><TT> transmit -instead of receive, we initialize an address with zero</TT> -<BR><TT> and -let the OS choose a port for us. We could have chosen our</TT> -<BR><TT> own -value between 1025 and 65535 as long as it isn't already in use.</TT> -<BR><TT> */</TT> -<BR><TT> ACE_INET_Addr -local((u_short)0);</TT> - -<P><TT> /*</TT> -<BR><TT> And -here is our datagram object.</TT> -<BR><TT> */</TT> -<BR><TT> ACE_SOCK_Dgram dgram;</TT> -<BR><TT> </TT> -<BR><TT> /*</TT> -<BR><TT> Notice -that this looks a lot like the server application. There's</TT> -<BR><TT> no -difference in creating server datagrams an client datagrams.</TT> -<BR><TT> You -can even use a zero-constructed address for your server datagram</TT> -<BR><TT> as -long as you tell the client where you're listening (eg -- by writting</TT> -<BR><TT> into -a file or some such).</TT> -<BR><TT> */</TT> -<BR><TT> if( dgram.open(local) -== -1 )</TT> -<BR><TT> {</TT> -<BR><TT> -ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "datagram open"),-1);</TT> -<BR><TT> }</TT> - -<P><TT> /*</TT> -<BR><TT> Yep. -We've seen this before too...</TT> -<BR><TT> */</TT> -<BR><TT> char buf[512];</TT> - -<P><TT> /*</TT> -<BR><TT> Ok, -now we're doing something different.</TT> -<BR><TT> */</TT> -<BR><TT> sprintf(buf, "Hello -World!");</TT> - -<P><TT> /*</TT> -<BR><TT> Just -like sending a telegram, we have to address our datagram.</TT> -<BR><TT> Here, -we create an address object at the desired port on the</TT> -<BR><TT> chosen -host. To keep us from crashing, we'll provide a default</TT> -<BR><TT> host -name if we aren't given one.</TT> -<BR><TT> */</TT> -<BR><TT> ACE_INET_Addr -remote(PORT, argc > 1 ? argv[1] : "localhost" );</TT> - -<P><TT> ACE_DEBUG ((LM_DEBUG, -"(%P|%t) Sending (%s) to the server.\n",buf));</TT> -<BR><TT> /*</TT> -<BR><TT> -Now we send our buffer of stuff to the remote address. This is</TT> -<BR><TT> -just exactly what the server did after receiving a client message.</TT> -<BR><TT> -Datagrams are rather orthogonal that way: they don't generally make</TT> -<BR><TT> -much of a fuss about being either client or server.</TT> -<BR><TT> */</TT> -<BR><TT> if( dgram.send(buf,strlen(buf)+1,remote) -== -1 )</TT> -<BR><TT> {</TT> -<BR><TT> -ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "send"),-1);</TT> -<BR><TT> }</TT> - -<P><TT> /*</TT> -<BR><TT> Now -we've turned around and put ourselves into "server mode" by</TT> -<BR><TT> invoking -the recv() method. We now our server is going to send</TT> -<BR><TT> us -something, so we hang out here and wait for it. Because we</TT> -<BR><TT> know -datagrams are unreliable, there is a chance that the server</TT> -<BR><TT> will -respond but we won't hear. You might consider providing a</TT> -<BR><TT> timeout -on the recv() in that case. If recv() fails due to timeout</TT> -<BR><TT> it -will return -1 and you can then resend your query and attempt</TT> -<BR><TT> the -recv() again.</TT> -<BR><TT> */</TT> -<BR><TT> if( dgram.recv(buf,sizeof(buf),remote) -== -1 )</TT> -<BR><TT> {</TT> -<BR><TT> -ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "recv"),-1);</TT> -<BR><TT> }</TT> - -<P><TT> /*</TT> -<BR><TT> Find -out what the server had to say.</TT> -<BR><TT> */</TT> -<BR><TT> ACE_DEBUG ((LM_DEBUG, -"(%P|%t) The server said: %s\n",buf));</TT> - -<P><TT> return(0);</TT> -<BR><TT>}</TT> - -<P> -<HR WIDTH="100%"> - -<P>That's all neat and good but the point of what we're doing here is not -to talk to a server we know about but to discover servers we don't know -about. Now, you could send a directed datagram to every possible -host address on your network but that's not a very nice thing to do. -On the next page, we'll find out the right approach... - -<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/008/page04.html b/docs/tutorials/008/page04.html deleted file mode 100644 index 4a634b56a4b..00000000000 --- a/docs/tutorials/008/page04.html +++ /dev/null @@ -1,156 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="GENERATOR" CONTENT="Mozilla/4.05 [en] (WinNT; I) [Netscape]"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 008</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 008</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Sending and receiving datagrams</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> -<BR> -<BR> In <A HREF="broadcast_client.cpp">broadcast_client.cpp</A> we -find out how to send a single datagram to every host on our (sub)network. -I have to say <I>(sub)network</I> because broadcast datagrams typically -are not passed through routers. So, if your network admin has divided -up your network into subnets, your broadcasts will likey only stay on the -subnet you're a part of. - -<P>I've only commented the parts that are different from the directed_client. - -<P> -<HR WIDTH="100%"> - -<P><TT>#include "ace/SOCK_Dgram_Bcast.h"</TT> -<BR><TT>#include "ace/INET_Addr.h"</TT> - -<P><TT>static const u_short PORT = ACE_DEFAULT_SERVER_PORT;</TT> - -<P><TT>int main(int argc,char *argv[] )</TT> -<BR><TT>{</TT> -<BR><TT> ACE_INET_Addr -local((u_short)0);</TT> - -<P><TT> /*</TT> -<BR><TT> Instead -of creating the ACE_SOCK_Dgram we created last time,</TT> -<BR><TT> we'll -create an ACE_SOCK_Dgram_Bcast. "Bcast" means, of course,</TT> -<BR><TT> "Broadcast". -This ACE object is clever enough to go out to the</TT> -<BR><TT> OS -and find all of the network interfaces. When you send()</TT> -<BR><TT> on -a Dgram_Bcast, it will send the datagram out on all of those</TT> -<BR><TT> interfaces. -This is quiet handy if you do it on a multi-homed</TT> -<BR><TT> host -that plays router...</TT> -<BR><TT> */</TT> -<BR><TT> ACE_SOCK_Dgram_Bcast -dgram;</TT> - -<P><TT> if( dgram.open(local) -== -1 )</TT> -<BR><TT> {</TT> -<BR><TT> -ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "datagram open"),-1);</TT> -<BR><TT> }</TT> - -<P><TT> char buf[512];</TT> - -<P><TT> sprintf(buf, "Hello World!");</TT> - -<P><TT> /*</TT> -<BR><TT> The -only other difference between us and the directed client</TT> -<BR><TT> is -that we don't specify a host to receive the datagram.</TT> -<BR><TT> Instead, -we use the magic value "INADDR_BROADCAST". All hosts</TT> -<BR><TT> are -obliged to respond to datagrams directed to this address</TT> -<BR><TT> the -same as they would to datagrams sent to their hostname.</TT> - -<P><TT> Remember, -the Dgram_Bcast will send a datagram to all interfaces</TT> -<BR><TT> on -the host. That's true even if the address is for a specific</TT> -<BR><TT> host -(and the host address makes sense for the interface).</TT> -<BR><TT> The -real power is in using an INADDR_BROADCAST addressed datagram</TT> -<BR><TT> against -all interfaces.</TT> -<BR><TT> */</TT> -<BR><TT> ACE_INET_Addr -remote(PORT,INADDR_BROADCAST);</TT> - -<P><TT> ACE_DEBUG ((LM_DEBUG, -"(%P|%t) Sending (%s) to the server.\n",buf));</TT> -<BR><TT> </TT> -<BR><TT> if( dgram.send(buf,strlen(buf)+1,remote) -== -1 )</TT> -<BR><TT> {</TT> -<BR><TT> -ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "send"),-1);</TT> -<BR><TT> }</TT> - -<P><TT> if( dgram.recv(buf,sizeof(buf),remote) -== -1 )</TT> -<BR><TT> {</TT> -<BR><TT> -ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "recv"),-1);</TT> -<BR><TT> }</TT> - -<P><TT> ACE_DEBUG ((LM_DEBUG, -"(%P|%t) The server said: %s\n",buf));</TT> - -<P><TT> /*</TT> -<BR><TT> Using -the <I>remote</I> object instance, find out where the server lives.</TT> -<BR><TT> We -could then save this address and use directed datagrams to chat</TT> -<BR><TT> with -the server for a while.</TT> -<BR><TT> */</TT> -<BR><TT> ACE_DEBUG ((LM_DEBUG, -"(%P|%t) The server can be found at: (%s:%d)\n",</TT> -<BR><TT> -remote.get_host_addr(), PORT ));</TT> -<BR><TT> </TT> -<BR><TT> return(0);</TT> -<BR><TT>}</TT> - -<P> -<HR WIDTH="100%"> - -<P> About that subnet thing: -<BLOCKQUOTE>If you run this client on a host that has multiple network -interfaces, the broadcast will go to all of those (sub)networks. -What do you do, though, if you need to get past a router? My advice -is to write a server that will run on hosts on both sides of your router. -When a server on one side of the router receives a broadcast, it would -send a directed datagram to it's counterpart on the other side of the router. -The counterpart would then re-broadcast the original datagram on that sub-net. -Cheap, simple and effective.</BLOCKQUOTE> -One final word of warning: -<BLOCKQUOTE>When creating your broadcast datagrams you may see something -like this: <I>ACE_SOCK_Dgram_Bcast::mk_broadcast: Broadcast is not -enable for this interface.: Unknown error</I>. There are some interfaces -(ppp, slip) that don't support broadcast datagrams. That's what you're -seeing here.</BLOCKQUOTE> - -<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/008/page05.html b/docs/tutorials/008/page05.html deleted file mode 100644 index f8c4603668a..00000000000 --- a/docs/tutorials/008/page05.html +++ /dev/null @@ -1,43 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="GENERATOR" CONTENT="Mozilla/4.05 [en] (WinNT; I) [Netscape]"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 008</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 008</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Sending and receiving datagrams</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> -<BR> -<BR>That's it for this tutorial. In the next one we'll add some intelligence -to the data put into the datagrams. By doing so, we'll be able to -classify our clients and servers into groups. By combining the data -content and the server's port we can get fairly fine-grained control over -who talks to who. - -<P>For you convenience: -<UL> -<LI> -<A HREF="server.cpp">server.cpp</A></LI> - -<LI> -<A HREF="directed_client.cpp">directed_client.cpp</A></LI> - -<LI> -<A HREF="broadcast_client.cpp">broadcast_client.cpp</A></LI> - -<LI> -<A HREF="Makefile">Makefile</A></LI> -</UL> - -<HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial Index</A>]</CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/008/server.cpp b/docs/tutorials/008/server.cpp deleted file mode 100644 index e702b1b93bb..00000000000 --- a/docs/tutorials/008/server.cpp +++ /dev/null @@ -1,128 +0,0 @@ - -// $Id$ - -/* - Our datagram server will, of course, need to create a datagram. - We'll also need an address object so that we know where to listen. - */ -#include "ace/SOCK_Dgram.h" -#include "ace/INET_Addr.h" - -/* - Use the typical TCP/IP port address for receiving datagrams. - */ -static const u_short PORT = ACE_DEFAULT_SERVER_PORT; - -int main(int,char**) -{ - /* - This is where we'll listen for datagrams coming from the - clients. We'll give this address to the open() method - below to enable the listener. - */ - ACE_INET_Addr local(PORT); - - /* - A simply constructed datagram that we'll listen with. - */ - ACE_SOCK_Dgram dgram; - - /* - Like most ACE objects, the datagram has to be opened before - it can be uses. Of course, -1 on failure. - - A datagram will fail to open if there is already a datagram - listening at the port we've chosen. It *is* OK to open - a datagram at a port where there is an ACE_SOCK_Stream - though. This is because datagrams are UDP and SOCK_Stream - is TCP and the two don't cross paths. - */ - if( dgram.open(local) == -1 ) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "open"),-1); - } - - /* - Create a simple buffer to receive the data. You generally need - to provide a buffer big enough for the largest datagram you - expect to receive. Some platforms will let you read a little - and then some more later but other platforms will throw out - whatever part of the datagram you don't get with the first - read. (This is on a per-datagram basis BTW.) The theoretical - limit on a datagram is about 64k. The realistic limit (because - of routers & such) is much smaller. Choose your buffer size - based on your application's needs. - */ - char buf[512]; - - /* - Unlike ACE_SOCK_Stream, datagrams are unconnected. That is, - there is no "virtual circuit" between server and client. - Because of this, the server has to provide a placeholder - for the OS to fill in the source (client) address information - on the recv. You can initialize this INET_Addr to anything, - it will be overwritten when the data arrives. - */ - ACE_INET_Addr remote; - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) starting up server daemon\n")); - - /* - Receive datagrams as long as we're able. - */ - while( dgram.recv(buf,sizeof(buf),remote) != -1 ) - { - /* - Display a brief message about our progress. Notice how we - use the 'remote' object to display the address of the client. - With an ACE_SOCK_Stream we used get_remote_addr() to get the - address the socket is connected to. Because datagrams are - unconnected, we use the addr object provided to recv(). - */ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Data (%s) from client (%s)\n", buf, remote.get_host_name())); - - /* - To respond to the client's query, we have to become a client - ourselves. To do so, we need an anonymous local address from - which we'll send the response and a datagram in which to send - it. (An anonymous address is simply one where we let the OS - choose a port for us. We really don't care what it is.O - */ - ACE_INET_Addr local((u_short)0); - ACE_SOCK_Dgram client; - - /* - Open up our response datagram as always. - */ - if( client.open(local) == -1 ) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "client open"),-1); - return(0); - } - - /* - Build a witty response... - */ - sprintf(buf,"I am here"); - - /* - and send it to the client. Notice the symetry with the recv() - method. Again, the unconnected nature of datagrams forces - us to specify an address object with each read/write operation. - In the case of read (recv()) that's where the OS stuffs the - address of the datagram sender. In the case of write (send()) - that we're doing here, the address is where we want the network - to deliver the data. - - Of course, we're assuming that the client will be listening - for our reply... - */ - if( client.send(buf,strlen(buf)+1,remote) == -1 ) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "send"),-1); - return(0); - } - } - - return(0); -} diff --git a/docs/tutorials/009/Makefile b/docs/tutorials/009/Makefile deleted file mode 100644 index 553c77d6251..00000000000 --- a/docs/tutorials/009/Makefile +++ /dev/null @@ -1,61 +0,0 @@ -#---------------------------------------------------------------------------- -# $Id$ -#---------------------------------------------------------------------------- - -#---------------------------------------------------------------------------- -# Local macros -#---------------------------------------------------------------------------- - -BIN = server directed_client broadcast_client - -FILES = - -BUILD = $(VBIN) - -HDR = *.h - -#---------------------------------------------------------------------------- -# Include macros and targets -#---------------------------------------------------------------------------- - -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 -#---------------------------------------------------------------------------- - -Indent : # - for i in $(SRC) $(HDR) ; do \ - indent -npsl -bli0 -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 - -Depend : depend - perl ../fix.Makefile - -.depend : # - touch .depend - -#---------------------------------------------------------------------------- -# 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/009/broadcast_client.cpp b/docs/tutorials/009/broadcast_client.cpp deleted file mode 100644 index 76ff454d066..00000000000 --- a/docs/tutorials/009/broadcast_client.cpp +++ /dev/null @@ -1,39 +0,0 @@ - -// $Id$ - -#include "ace/SOCK_Dgram_Bcast.h" -#include "ace/INET_Addr.h" - -static const u_short PORT = ACE_DEFAULT_SERVER_PORT; - -int main (int argc, char *argv[]) -{ - ACE_INET_Addr local ((u_short) 0); - ACE_INET_Addr remote (PORT, INADDR_BROADCAST); - ACE_SOCK_Dgram_Bcast dgram; - - if (dgram.open (local) == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "open"), -1); - } - - char buf[512]; - - sprintf (buf, argc > 1 ? argv[1] : "Hello World!"); - - if (dgram.send (buf, strlen (buf) + 1, remote) == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "send"), -1); - } - - ACE_Time_Value timeout (2, 0); - if (dgram.recv (buf, sizeof (buf), remote, 0, &timeout) == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "recv"), -1); - } - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) The server at (%s) said (%s)\n", - remote.get_host_name (), buf)); - - return (0); -} diff --git a/docs/tutorials/009/directed_client.cpp b/docs/tutorials/009/directed_client.cpp deleted file mode 100644 index 7156286bec1..00000000000 --- a/docs/tutorials/009/directed_client.cpp +++ /dev/null @@ -1,52 +0,0 @@ - -// $Id$ - -#include "ace/SOCK_Dgram.h" -#include "ace/INET_Addr.h" - -static const u_short PORT = ACE_DEFAULT_SERVER_PORT; - -int main (int argc, char *argv[]) -{ - ACE_INET_Addr local ((u_short) 0); - ACE_INET_Addr remote (PORT, argc > 1 ? argv[1] : "localhost"); - ACE_SOCK_Dgram dgram; - - if (dgram.open (local) == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "open"), -1); - } - - char buf[512]; - - /* - In order to conform to the "protocol" requried by the server, - we allow the user to specify a signature. A default matching - the server's default is also available. - */ - sprintf (buf, argc > 2 ? argv[2] : "Hello World!"); - - if (dgram.send (buf, strlen (buf) + 1, remote) == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "send"), -1); - } - - /* - Because we may have sent a signature that the server doesn't - honor, we have to have some way to get out of the recv(). - Most ACE objects that have potential for infinite blocking - give you the option of providing a timeout. recv() is no - exception. Here, we construct an ACE_Time_Value representing - two seconds and no micro-seconds. If recv() fails to get - a response within the two seconds, it will return -1. - */ - ACE_Time_Value timeout (2, 0); - if (dgram.recv (buf, sizeof (buf), remote, 0, &timeout) == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "recv"), -1); - } - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) The server said (%s)\n", buf)); - - return (0); -} diff --git a/docs/tutorials/009/page01.html b/docs/tutorials/009/page01.html deleted file mode 100644 index 77bacc3d4cc..00000000000 --- a/docs/tutorials/009/page01.html +++ /dev/null @@ -1,52 +0,0 @@ -<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"> - <TITLE>ACE Tutorial 009</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 009</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Sending and receiving datagrams again</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> - -<P>In our previous tutorial, we created a datagram listener and a couple -of clients that would send it datagrams. That server would respond -to any datagram sent to the TCP/IP port at which the server was listening. -What we really want to do, however, is to have the server only respond -to clients that meet some criteria. - -<P>Why is this important? - -<P>Imagine you're writting a distributed system that will have many server -applications. Each of those will probably listen at different (and -well-known) TCP/IP addresses so that clients can find each server -without confusion. However... In a large system you might have -several <I>versions</I> of the same server running at the same time*. -You probably don't want those servers running at different addresses since -that breaks the well-known address requirement. - -<P>By creating a datagram listener similar to the last tutorial, a client -can send broadcast datagrams to locate all of the servers listening at -the well-known address. By adding a thin protocol layer into -the datagram contents, the servers can be selective about which clients -they respond to. Thus, if each client sends its version signature -in the broadcast, then the servers can choose to respond only to clients -with matching versions. - -<P><FONT SIZE=-1>*Note: I'm making the assumption that your multiple -server versions will be running on different hosts since you can only have -one server listening at the well-known address on a given host.</FONT> - -<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/009/page02.html b/docs/tutorials/009/page02.html deleted file mode 100644 index e2997a16409..00000000000 --- a/docs/tutorials/009/page02.html +++ /dev/null @@ -1,130 +0,0 @@ -<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"> - <TITLE>ACE Tutorial 009</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 009</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Sending and receiving datagrams again</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> - -<P>Let's take a look at our new <A HREF="server.cpp">server.cpp</A> where -we add in just a bit of code to examine the datagram contents before responding. - -<P> -<HR WIDTH="100%"><TT></TT> - -<P><TT>/*</TT> -<BR><TT> The actual datagram operations here are exactly the -same as those used in</TT> -<BR><TT> the previous tutorial. What we've added is some -logic that will prevent</TT> -<BR><TT> this server from responding to just any old datagram. -I'll limit my</TT> -<BR><TT> comments to those pieces of code.</TT> -<BR><TT> */</TT><TT></TT> - -<P><TT>#include "ace/SOCK_Dgram.h"</TT> -<BR><TT>#include "ace/INET_Addr.h"</TT><TT></TT> - -<P><TT>static const u_short PORT = ACE_DEFAULT_SERVER_PORT;</TT><TT></TT> - -<P><TT>/*</TT> -<BR><TT> In order to be more selective, our server will be -started with a</TT> -<BR><TT> "signature". If none is given, we'll use the -one here instead.</TT> -<BR><TT> */</TT> -<BR><TT>static const char *default_signature = "Hello World!";</TT><TT></TT> - -<P><TT>int main (int argc, char *argv[])</TT> -<BR><TT>{</TT> -<BR><TT> ACE_INET_Addr local (PORT);</TT> -<BR><TT> ACE_SOCK_Dgram dgram;</TT><TT></TT> - -<P><TT> if (dgram.open (local) == -1)</TT> -<BR><TT> {</TT> -<BR><TT> ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "open"), --1);</TT> -<BR><TT> }</TT><TT></TT> - -<P><TT> char buf[512];</TT> -<BR><TT> ACE_INET_Addr remote;</TT><TT></TT> - -<P><TT> while (dgram.recv (buf, sizeof (buf), remote) != -1)</TT> -<BR><TT> {</TT> -<BR><TT> /*</TT> -<BR><TT> What did the client say?</TT> -<BR><TT> */</TT> -<BR><TT> ACE_DEBUG ((LM_DEBUG, "(%P|%t) Received (%s) -from (%s)\n", buf, remote.get_host_name ()));</TT><TT></TT> - -<P><TT> /*</TT> -<BR><TT> Use a simple string-op to -decide if the client is one of our own. Of</TT> -<BR><TT> course, you could have sent -numeric values or even a struct of data. For</TT> -<BR><TT> this simple exercise, however, -strings are just fine.</TT> -<BR><TT> */</TT> -<BR><TT> if (ACE_OS::strcmp (buf, argc > 1 ? argv[1] -: default_signature))</TT> -<BR><TT> {</TT> -<BR><TT> /*</TT> -<BR><TT> If the client -didn't say something we like then log it and move on.</TT> -<BR><TT> */</TT> -<BR><TT> ACE_DEBUG ((LM_DEBUG,</TT> -<BR><TT> -"(%P|%t) Client query does not match our signature (%s). Response -not sent.\n",</TT> -<BR><TT> -argc > 1 ? argv[1] : default_signature));</TT> -<BR><TT> }</TT> -<BR><TT> else</TT> -<BR><TT> {</TT> -<BR><TT> /*</TT> -<BR><TT> As before, we -respond to the client's query.</TT> -<BR><TT> */</TT><TT></TT> - -<P><TT> ACE_INET_Addr local ((u_short) 0);</TT> -<BR><TT> ACE_SOCK_Dgram client;</TT> -<BR><TT> if (client.open (local) == -1)</TT> -<BR><TT> {</TT> -<BR><TT> ACE_ERROR_RETURN -((LM_ERROR, "%p\n", "response open"), -1);</TT> -<BR><TT> }</TT><TT></TT> - -<P><TT> sprintf (buf, "I am here");</TT> -<BR><TT> if (client.send (buf, strlen (buf) -+ 1, remote) == -1)</TT> -<BR><TT> {</TT> -<BR><TT> ACE_ERROR_RETURN -((LM_ERROR, "%p\n", "response send"), -1);</TT> -<BR><TT> }</TT> -<BR><TT> }</TT> -<BR><TT> }</TT><TT></TT> - -<P><TT> return (0);</TT> -<BR><TT>}</TT><TT></TT> - -<P> -<HR WIDTH="100%"> - -<P>Let's move on and see what changes the clients require... - -<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/009/page03.html b/docs/tutorials/009/page03.html deleted file mode 100644 index 447bf38d497..00000000000 --- a/docs/tutorials/009/page03.html +++ /dev/null @@ -1,100 +0,0 @@ -<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"> - <TITLE>ACE Tutorial 009</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 009</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Sending and receiving datagrams again</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> - -<P>Our new <A HREF="directed_client.cpp">directed_client.cpp</A> -is very much like our previous one. The primary difference is the -addition of a timeout to the recv() call so that we can exit somewhat gracefully -if the server doesn't like what we have to say. - -<P> -<HR WIDTH="100%"><TT></TT> - -<P><TT>#include "ace/SOCK_Dgram.h"</TT> -<BR><TT>#include "ace/INET_Addr.h"</TT><TT></TT> - -<P><TT>static const u_short PORT = ACE_DEFAULT_SERVER_PORT;</TT><TT></TT> - -<P><TT>int main (int argc, char *argv[])</TT> -<BR><TT>{</TT> -<BR><TT> ACE_INET_Addr local ((u_short) 0);</TT> -<BR><TT> ACE_INET_Addr remote (PORT, argc > 1 ? argv[1] : "localhost");</TT> -<BR><TT> ACE_SOCK_Dgram dgram;</TT><TT></TT> - -<P><TT> if (dgram.open (local) == -1)</TT> -<BR><TT> {</TT> -<BR><TT> ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "open"), --1);</TT> -<BR><TT> }</TT><TT></TT> - -<P><TT> char buf[512];</TT><TT></TT> - -<P><TT> /*</TT> -<BR><TT> In order to conform to the "protocol" -requried by the server,</TT> -<BR><TT> we allow the user to specify a signature. -A default matching</TT> -<BR><TT> the server's default is also available.</TT> -<BR><TT> */</TT> -<BR><TT> sprintf (buf, argc > 2 ? argv[2] : "Hello World!");</TT><TT></TT> - -<P><TT> if (dgram.send (buf, strlen (buf) + 1, remote) == -1)</TT> -<BR><TT> {</TT> -<BR><TT> ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "send"), --1);</TT> -<BR><TT> }</TT><TT></TT> - -<P><TT> /*</TT> -<BR><TT> Because we may have sent a signature that -the server doesn't</TT> -<BR><TT> honor, we have to have some way to get -out of the recv().</TT> -<BR><TT> Most ACE objects that have potential for -infinite blocking</TT> -<BR><TT> give you the option of providing a timeout. -recv() is no</TT> -<BR><TT> exception. Here, we construct an -ACE_Time_Value representing</TT> -<BR><TT> two seconds and no micro-seconds. -If recv() fails to get</TT> -<BR><TT> a response within the two seconds, it -will return -1.</TT> -<BR><TT> */</TT> -<BR><TT> ACE_Time_Value timeout (2, 0);</TT> -<BR><TT> if (dgram.recv (buf, sizeof (buf), remote, 0, &timeout) -== -1)</TT> -<BR><TT> {</TT> -<BR><TT> ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "recv"), --1);</TT> -<BR><TT> }</TT><TT></TT> - -<P><TT> ACE_DEBUG ((LM_DEBUG, "(%P|%t) The server said (%s)\n", buf));</TT><TT></TT> - -<P><TT> return (0);</TT> -<BR><TT>}</TT> - -<P> -<HR WIDTH="100%"> - -<P>On the next page, we see that the directed_client gets similar upgrades. - -<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/009/page04.html b/docs/tutorials/009/page04.html deleted file mode 100644 index e1875503b8c..00000000000 --- a/docs/tutorials/009/page04.html +++ /dev/null @@ -1,74 +0,0 @@ -<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"> - <TITLE>ACE Tutorial 009</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 009</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Sending and receiving datagrams again</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> - -<P>As you can see in <A HREF="broadcast_client.cpp">broadcast_client.cpp</A>, -there isn't enough difference to even comment on! Look back to the -Tutorial 8 version of this file. The only difference is the addition -of the timeout variable passed to recv(). - -<P> -<HR WIDTH="100%"><TT></TT> - -<P><TT>#include "ace/SOCK_Dgram_Bcast.h"</TT> -<BR><TT>#include "ace/INET_Addr.h"</TT><TT></TT> - -<P><TT>static const u_short PORT = ACE_DEFAULT_SERVER_PORT;</TT><TT></TT> - -<P><TT>int main (int argc, char *argv[])</TT> -<BR><TT>{</TT> -<BR><TT> ACE_INET_Addr local ((u_short) 0);</TT> -<BR><TT> ACE_INET_Addr remote (PORT, INADDR_BROADCAST);</TT> -<BR><TT> ACE_SOCK_Dgram_Bcast dgram;</TT><TT></TT> - -<P><TT> if (dgram.open (local) == -1)</TT> -<BR><TT> {</TT> -<BR><TT> ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "open"), --1);</TT> -<BR><TT> }</TT><TT></TT> - -<P><TT> char buf[512];</TT><TT></TT> - -<P><TT> sprintf (buf, argc > 1 ? argv[1] : "Hello World!");</TT><TT></TT> - -<P><TT> if (dgram.send (buf, strlen (buf) + 1, remote) == -1)</TT> -<BR><TT> {</TT> -<BR><TT> ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "send"), --1);</TT> -<BR><TT> }</TT><TT></TT> - -<P><TT> ACE_Time_Value timeout (2, 0);</TT> -<BR><TT> if (dgram.recv (buf, sizeof (buf), remote, 0, &timeout) -== -1)</TT> -<BR><TT> {</TT> -<BR><TT> ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "recv"), --1);</TT> -<BR><TT> }</TT><TT></TT> - -<P><TT> ACE_DEBUG ((LM_DEBUG, "(%P|%t) The server at (%s) said (%s)\n",</TT> -<BR><TT> -remote.get_host_name (), buf));</TT><TT></TT> - -<P><TT> return (0);</TT> -<BR><TT>}</TT> - -<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/009/page05.html b/docs/tutorials/009/page05.html deleted file mode 100644 index 771e113e961..00000000000 --- a/docs/tutorials/009/page05.html +++ /dev/null @@ -1,50 +0,0 @@ -<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"> - <TITLE>ACE Tutorial 009</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 009</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Sending and receiving datagrams again</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> - -<P>In this tutorial we've expanded on Tutorial 8 to provide a more discriminating -server application. The changes to the clients were trivial, amounting -to not much more than the addition of a timeout when reading a server's -potential response. The server change was a bit more since it had -to compare the clients' query with it's own signature. - -<P>In a "real" system, the signatures you swap would probably include version -information. You could even use a major/minor scheme where an exact -match isn't necessary. Another upgrade might be to have a set of -signatures at one or both ends of the conversation. The level of -service provided by the server would be determined by the signature pair -match. - -<P>Here's the final file list: -<UL> -<LI> -<A HREF="Makefile">Makefile</A></LI> - -<LI> -<A HREF="server.cpp">server.cpp</A></LI> - -<LI> -<A HREF="directed_client.cpp">directed_client.cpp</A></LI> - -<LI> -<A HREF="broadcast_client.cpp">broadcast_client.cpp</A></LI> -</UL> - -<HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial Index</A>]</CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/009/server.cpp b/docs/tutorials/009/server.cpp deleted file mode 100644 index f73c7fd4ad3..00000000000 --- a/docs/tutorials/009/server.cpp +++ /dev/null @@ -1,78 +0,0 @@ - -// $Id$ - -/* - The actual datagram operations here are exactly the same as those used in - the previous tutorial. What we've added is some logic that will prevent - this server from responding to just any old datagram. I'll limit my - comments to those pieces of code. - */ - -#include "ace/SOCK_Dgram.h" -#include "ace/INET_Addr.h" - -static const u_short PORT = ACE_DEFAULT_SERVER_PORT; - -/* - In order to be more selective, our server will be started with a - "signature". If none is given, we'll use the one here instead. - */ -static const char *default_signature = "Hello World!"; - -int main (int argc, char *argv[]) -{ - ACE_INET_Addr local (PORT); - ACE_SOCK_Dgram dgram; - - if (dgram.open (local) == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "open"), -1); - } - - char buf[512]; - ACE_INET_Addr remote; - - while (dgram.recv (buf, sizeof (buf), remote) != -1) - { - /* - What did the client say? - */ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Received (%s) from (%s)\n", buf, remote.get_host_name ())); - - /* - Use a simple string-op to decide if the client is one of our own. Of - course, you could have sent numeric values or even a struct of data. For - this simple exercise, however, strings are just fine. - */ - if (ACE_OS::strcmp (buf, argc > 1 ? argv[1] : default_signature)) - { - /* - If the client didn't say something we like then log it and move on. - */ - ACE_DEBUG ((LM_DEBUG, - "(%P|%t) Client query does not match our signature (%s). Response not sent.\n", - argc > 1 ? argv[1] : default_signature)); - } - else - { - /* - As before, we respond to the client's query. - */ - - ACE_INET_Addr local ((u_short) 0); - ACE_SOCK_Dgram client; - if (client.open (local) == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "response open"), -1); - } - - sprintf (buf, "I am here"); - if (client.send (buf, strlen (buf) + 1, remote) == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "response send"), -1); - } - } - } - - return (0); -} diff --git a/docs/tutorials/010/Makefile b/docs/tutorials/010/Makefile deleted file mode 100644 index ed236e37bde..00000000000 --- a/docs/tutorials/010/Makefile +++ /dev/null @@ -1,60 +0,0 @@ - -# $Id$ - -#---------------------------------------------------------------------------- -# Local macros -#---------------------------------------------------------------------------- - -BIN = message_queue - -FILES = -FILES += task - -BUILD = $(VBIN) - -SRC = $(addsuffix .cpp,$(BIN)) $(addsuffix .cpp,$(FILES)) - -HDR = *.h - -#---------------------------------------------------------------------------- -# Include macros and targets -#---------------------------------------------------------------------------- - -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 -#---------------------------------------------------------------------------- - -Indent : # - for i in $(SRC) $(HDR) ; do \ - indent -npsl -l80 -fca -fc1 -cli0 -cdb -ts2 -bl -bli0 < $$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/' \ - -e 's/ / /g' \ - > $$i~ ;\ - mv $$i~ $$i ;\ - done - -Depend : depend - perl ../007/fix.Makefile - -.depend : # - touch .depend - -#---------------------------------------------------------------------------- -# Dependencies -#---------------------------------------------------------------------------- - -include .depend diff --git a/docs/tutorials/010/block.h b/docs/tutorials/010/block.h deleted file mode 100644 index 662c3c1e536..00000000000 --- a/docs/tutorials/010/block.h +++ /dev/null @@ -1,52 +0,0 @@ - -// $Id$ - -#ifndef BLOCK_H -#define BLOCK_H - -#include "ace/Message_Block.h" - -/* - This simple ACE_Message_Block derivative will inform us of it's construction - and destruction. We'll use this to assure ourselves that we don't have any - memory leaks. In a real application, of course, this isn't necessary. - */ -class Block : public ACE_Message_Block -{ -public: - Block (void) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Block ctor 0x%x\n", (void *) this)); - } - - Block (size_t size) - : ACE_Message_Block (size) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Block ctor 0x%x\n", (void *) this)); - } - - virtual ~ Block (void) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Block dtor 0x%x\n", (void *) this)); - } -}; - -#endif - - - - - - - - - - - - - - - - - - diff --git a/docs/tutorials/010/message_queue.cpp b/docs/tutorials/010/message_queue.cpp deleted file mode 100644 index c52273a134b..00000000000 --- a/docs/tutorials/010/message_queue.cpp +++ /dev/null @@ -1,93 +0,0 @@ - -// $Id$ - -/* - To illustrate the ACE_Message_Queue, we use a derivative of ACE_Task<>. We - also derive from ACE_Message_Block to show that we don't have memory leaks. - */ -#include "task.h" -#include "block.h" - -int run_test( int iterations, int threads ) -{ - /* - Create and open an instance of our Task object. I've overridden the - open() method to make it look more like other ACE objects. - */ - Task task; - - if (task.open (threads) == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "open"), -1); - } - - /* - Give the threads a moment to open. This isn't really necessary but if we - don't we find that all of our blocks are constructed and enqueued before - any of the threads get created. Basically, the sleep() makes the output - look more interesting. - */ - ACE_OS::sleep (ACE_Time_Value (1)); - - int i; - for (i = 0; i < iterations; ++i) - { - /* - Create a new message block to hold our data. Here, we ask for a block - that has 128 bytes of data space. - */ - Block *message = new Block (128); - - /* - Grab the "write pointer". This is a pointer into the data area where we - can write our data. After writting the data you have to increment the - wr_ptr() so that subsequent writes won't clobber what you've put there. - */ - ACE_OS::sprintf (message->wr_ptr (), "This is message %d.", i); - message->wr_ptr (strlen (message->rd_ptr ())); - - /* - Put the message block into the queue. One of the threads in the Task - object will pick up the block and "do work" on it. - */ - if (task.putq (message) == -1) - { - break; - } - } - - /* - Once we're done, we have to signal the Task objects to shut down. There - are several choices including: - Send a message of zero length - Send a - message with a special content I don't like these choices because they're - likely to interfere with application logic. Instead, I use the message - type feature to send a message of type "hangup". The default type is - MB_DATA, so when the tasks get a MB_HANGUP type, they know to go away. - */ - Block *message = new Block (); - message->msg_type (ACE_Message_Block::MB_HANGUP); - task.putq (message); - - /* - Wait for the threads in our task object to go away. - */ - task.wait (); - - return(0); -} - -int main (int argc, char *argv[]) -{ - /* - Set the number of iterations through our putq() loop and the number of - threads to use in our Task<> derivative. - */ - int iterations = argc > 1 ? atoi (argv[1]) : 9; - int threads = argc > 2 ? atoi (argv[2]) : 2; - - (void)run_test(iterations,threads); - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Application exiting\n")); - - exit(0); -} diff --git a/docs/tutorials/010/page01.html b/docs/tutorials/010/page01.html deleted file mode 100644 index 23f267b2565..00000000000 --- a/docs/tutorials/010/page01.html +++ /dev/null @@ -1,36 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 010</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 010</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Passing chunks of data through an ACE_Message_Queue</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> -<P> -In an earlier tutorial we briefly introduced ACE_Message_Queue. In this -tutorial we'll go into a bit more detail. -<P> -ACE_Message_Queue is modeled after Unix System V IPC mechanisms. The basic -idea is that you put a block of data into one end of the Queue and take it -out of the other end. Your basic FIFO in other words. The SysV mechanism -works great for passing these blocks of data between processes on the same -host but it's a bit overkill for moving blocks between threads. You could -use a pipe, socket or similar mechanism but that still has more overhead than -we really want just for moving data between threads. Process-global memory -is a good technique but then you need a way to signal the "listening" threads. -The ACE_Message_Queue is a better approach: Create blocks of data and enqueue -them in one thread while another thread (or threads) dequeue and perform work. -<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/010/page02.html b/docs/tutorials/010/page02.html deleted file mode 100644 index 29d61e61aec..00000000000 --- a/docs/tutorials/010/page02.html +++ /dev/null @@ -1,132 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 010</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 010</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Passing chunks of data through an ACE_Message_Queue</FONT></B></CENTER> - - -<HR WIDTH="100%"> -<P> - -We'll look first at <A HREF="message_queue.cpp">main()</A>. -<P> - -<HR WIDTH="100%"> -<PRE> -/* - To illustrate the ACE_Message_Queue, we use a derivative of ACE_Task<>. We - also derive from ACE_Message_Block to show that we don't have memory leaks. - */ -#include "task.h" -#include "block.h" - -int run_test( int iterations, int threads ) -{ - /* - Create and open an instance of our Task object. I've overridden the - open() method to make it look more like other ACE objects. - */ - Task task; - - if (task.open (threads) == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "open"), -1); - } - - /* - Give the threads a moment to open. This isn't really necessary but if we - don't we find that all of our blocks are constructed and enqueued before - any of the threads get created. Basically, the sleep() makes the output - look more interesting. - */ - ACE_OS::sleep (ACE_Time_Value (1)); - - int i; - for (i = 0; i < iterations; ++i) - { - /* - Create a new message block to hold our data. Here, we ask for a block - that has 128 bytes of data space. - */ - Block *message = new Block (128); - - /* - Grab the "write pointer". This is a pointer into the data area where we - can write our data. After writting the data you have to increment the - wr_ptr() so that subsequent writes won't clobber what you've put there. - */ - ACE_OS::sprintf (message->wr_ptr (), "This is message %d.", i); - message->wr_ptr (strlen (message->rd_ptr ())); - - /* - Put the message block into the queue. One of the threads in the Task - object will pick up the block and "do work" on it. - */ - if (task.putq (message) == -1) - { - break; - } - } - - /* - Once we're done, we have to signal the Task objects to shut down. There - are several choices including: - Send a message of zero length - Send a - message with a special content I don't like these choices because they're - likely to interfere with application logic. Instead, I use the message - type feature to send a message of type "hangup". The default type is - MB_DATA, so when the tasks get a MB_HANGUP type, they know to go away. - */ - Block *message = new Block (); - message->msg_type (ACE_Message_Block::MB_HANGUP); - task.putq (message); - - /* - Wait for the threads in our task object to go away. - */ - task.wait (); - - return(0); -} - -int main (int argc, char *argv[]) -{ - /* - Set the number of iterations through our putq() loop and the number of - threads to use in our Task<> derivative. - */ - int iterations = argc > 1 ? atoi (argv[1]) : 9; - int threads = argc > 2 ? atoi (argv[2]) : 2; - - (void)run_test(iterations,threads); - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Application exiting\n")); - - exit(0); -} -</PRE> -<HR WIDTH="100%"> -<P> -This looks a lot like our thread-pool server and it even does some things -better. In particular, I've scoped the Task object so that it's destructor -will have a chance to get called before the application exits. -Notice how we write actual data into the message block though. In the thread-pool -server we just provided a pointer. Writting the data is actually a more correct -way of doing things since you don't get into strange pointer casting situations. -What if you want to put complex objects into the message block though? We'll do -that in the next tutorial, let's stick with the basics first. -<P> -On the next page we'll take a look at our Block object... -<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/010/page03.html b/docs/tutorials/010/page03.html deleted file mode 100644 index 9c35bf18a86..00000000000 --- a/docs/tutorials/010/page03.html +++ /dev/null @@ -1,65 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 010</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 010</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Passing chunks of data through an ACE_Message_Queue</FONT></B></CENTER> - - -<HR WIDTH="100%"> -<P> - -Our <A HREF="block.h">Block</A> object is a very simple derivative -of the ACE_Message_Block. The only reason I created it was to prove -that the message blocks to, indeed, get freed when we're done with 'em. -<P> - -<HR WIDTH="100%"> -<PRE> - -#include "ace/Message_Block.h" - -/* - This simple ACE_Message_Block derivative will inform us of it's construction - and destruction. We'll use this to assure ourselves that we don't have any - memory leaks. In a real application, of course, this isn't necessary. - */ -class Block : public ACE_Message_Block -{ -public: - Block (void) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Block ctor 0x%x\n", (void *) this)); - } - - Block (size_t size) - : ACE_Message_Block (size) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Block ctor 0x%x\n", (void *) this)); - } - - virtual ~ Block (void) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Block dtor 0x%x\n", (void *) this)); - } -}; - -</PRE> -<HR WIDTH="100%"> -<P> -Ok, nothing really magic there. Some folks just feel a little uncomfortable -not doing an explicit <i>delete</i> on objects they've <i>new</i>'d so I -wanted to show you that the memory really does get cleaned up. -<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/010/page04.html b/docs/tutorials/010/page04.html deleted file mode 100644 index 1a22e793475..00000000000 --- a/docs/tutorials/010/page04.html +++ /dev/null @@ -1,84 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 010</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 010</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Passing chunks of data through an ACE_Message_Queue</FONT></B></CENTER> - - -<HR WIDTH="100%"> -<P> - -Our <A HREF="task.h">Task</A> object executes in one or more threads -and reads from the message queue it contains. -<P> - -<HR WIDTH="100%"> -<PRE> - -#include "ace/Task.h" - -/* - Like the thread-pool server tutorial, we'll derive from ACE_Task<>. - Our goal here is to show off the ACE_Message_Queue and the best way - to do that is to use one to pass data between threads. The easiest - way to create threads is with ACE_Task<> - */ -class Task : public ACE_Task < ACE_MT_SYNCH > -{ -public: - - typedef ACE_Task < ACE_MT_SYNCH > inherited; - - /* - The constructor/destructor are simple but take care of some - necessary housekeeping. - */ - Task (void); - ~Task (void); - - /* - To make our Task<> derivative look more like other ACE objects - I've added an open() method. It will take care of activate()ing - the object. - */ - int open (int threads = 1); - - /* - Our worker method - */ - int svc (void); - - /* - All we'll do here is print a message to the user. - */ - int close (u_long flags = 0); - -protected: - /* - Just to be clever, I'll use an ACE_Barrier to cause the threads - to sync in svc() before doing any real work. - */ - ACE_Barrier *barrier_; -}; -</PRE> -<HR WIDTH="100%"> -<P> -The only thing here that we didn't see in the thread-pool server is the -ACE_Barrier. The application logic really doesn't need it but it is a -handy way to synchronize the threads at the beginning of svc(). In testing -I found that if I didn't sync svc(), the first thread to get activated would -tend to get all of the messages before the other threads came alive. -<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/010/page05.html b/docs/tutorials/010/page05.html deleted file mode 100644 index 653cb496cb2..00000000000 --- a/docs/tutorials/010/page05.html +++ /dev/null @@ -1,168 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 010</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 010</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Passing chunks of data through an ACE_Message_Queue</FONT></B></CENTER> - - -<HR WIDTH="100%"> -<P> - -Our <A HREF="task.cpp">Task</A> object definition: -<P> - -<HR WIDTH="100%"> -<PRE> - -#include "task.h" -#include "block.h" - -/* - Set our housekeeping pointer to NULL and tell the user we exist. - */ -Task::Task (void) -: barrier_ (0) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Task ctor 0x%x\n", (void *) this)); -} - -/* - Take care of cleanup & tell the user we're going away. -*/ -Task::~Task (void) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Task dtor 0x%x\n", (void *) this)); - - /* - Get our shutdown notification out of the queue and release it. - */ - ACE_Message_Block * message; - this->getq(message); - message->release(); - - delete barrier_; -} - -/* - Open the object to do work. We create the Barrier object and tell - it how many threads we'll be using. Next, we activate the Task - into the number of requested threads. -*/ -int Task::open (int threads) -{ - barrier_ = new ACE_Barrier (threads); - return this->activate (THR_NEW_LWP, threads); -} - -/* - Tell the user we're closing and invoke the baseclass' close() to - take care of things. -*/ -int Task::close (u_long flags) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Task close 0x%x\n", (void *) this)); - return inherited::close (flags); -} - -/* - Our svc() method waits for work on the queue and then processes that work. - */ -int Task::svc (void) -{ - /* - This will cause all of the threads to wait on this line until all - have invoked this method. The net result is that no thread in the - Task will get a shot at the queue until all of the threads are active. - There's no real need to do this but it's an easy intro into the use - of ACE_Barrier. - */ - this->barrier_->wait (); - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Task 0x%x starts in thread %d\n", (void *) this, ACE_Thread::self ())); - - /* - Remember that get() needs a reference to a pointer. To save stack - thrashing we'll go ahead and create a pointer outside of the almost- - infinite loop. - */ - ACE_Message_Block *message; - while (1) - { - /* - Get a message from the queue. - */ - if (this->getq (message) == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "getq"), -1); - } - - /* - If we got the shutdown request, we need to go away. - */ - if (message->msg_type () == ACE_Message_Block::MB_HANGUP) - { - /* - Forward the request to any peer threads. - */ - this->putq (message); - - /* - Leave the infinite loop so that the thread exits. - */ - break; - } - - /* - The message queue stores char* data. We use rd_ptr() to get to - the beginning of the data. - */ - const char *cp = message->rd_ptr (); - - /* - Move the rd_ptr() past the data we read. This isn't real useful - here since we won't be reading any more from the block but it's - a good habit to get into. - */ - message->rd_ptr( strlen(cp) ); - - /* - Display the block's address and data to the user. - */ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Block 0x%x contains (%s)\n", (void *) message, cp)); - - /* - Pretend that it takes a while to process the data. - */ - ACE_OS::sleep (ACE_Time_Value (0, 5000)); - - /* - Release the message block. Notice that we never delete a message block. - Blocks are reference counted & the release() method will take care of - the delete when there are no more references to the data. - */ - message->release (); - } - - return (0); -} -</PRE> -<HR WIDTH="100%"> -<P> -This is all pretty straight-forward too. One gottcha we avoided was a memory leak -due to our shutdown message. Notice that svc() enqueues that block without bothering -to see if there are any more threads to dequeue it. Thats why our dtor can call getq() -without worrying about blocking infinitely: it knows the message block will be there. -<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/010/page06.html b/docs/tutorials/010/page06.html deleted file mode 100644 index c84e923f3f5..00000000000 --- a/docs/tutorials/010/page06.html +++ /dev/null @@ -1,64 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 010</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 010</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Passing chunks of data through an ACE_Message_Queue</FONT></B></CENTER> - - -<HR WIDTH="100%"> -<P> - -Since I added Block just to give us output, let's take a look at that output. - -<P> -<HR WIDTH="100%"> -<PRE> -[jcej@chiroptera 010]$./message_queue 4 2 -(8910|1024) Task ctor 0xbffff9c4 -(8910|2050) Task 0xbffff9c4 starts in thread 2050 -(8910|1025) Task 0xbffff9c4 starts in thread 1025 -(8910|1024) Block ctor 0x8052398 -(8910|1024) Block ctor 0x8052488 -(8910|1024) Block ctor 0x8052578 -(8910|1024) Block ctor 0x8052668 -(8910|1024) Block ctor 0x8052758 -(8910|1025) Block 0x8052398 contains (This is message 0.) -(8910|2050) Block 0x8052488 contains (This is message 1.) -(8910|1025) Block dtor 0x8052398 -(8910|1025) Block 0x8052578 contains (This is message 2.) -(8910|2050) Block dtor 0x8052488 -(8910|2050) Block 0x8052668 contains (This is message 3.) -(8910|1025) Block dtor 0x8052578 -(8910|1025) Task close 0xbffff9c4 -(8910|2050) Block dtor 0x8052668 -(8910|2050) Task close 0xbffff9c4 -(8910|1024) Task dtor 0xbffff9c4 -(8910|1024) Block dtor 0x8052758 -(8910|1024) Application exiting -[jcej@chiroptera 010]$ -</PRE> -<HR WIDTH="100%"> -<P> -Notice that each <i>Block ctor</i> has a corresponding <i>Block dtor</i>. -We've proven the point that all memory gets cleaned up. We also see that -both threads get to do some work and that both close as expected. -<P> -It's also worth mentioning that it's just an accident that all of the blocks -are created and enqueued before any are processed. Run the test on a multi-processor -or with more iterations and you'll see some get processed before all are created. -<P> -<HR WIDTH="100%"> - - -<CENTER>[<A HREF="..">Tutorial Index</A>][<A HREF="page07.html">Continue -This Tutorial</A>]</CENTER> -</CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/010/page07.html b/docs/tutorials/010/page07.html deleted file mode 100644 index c9cdaa28ee5..00000000000 --- a/docs/tutorials/010/page07.html +++ /dev/null @@ -1,36 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 010</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 010</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Passing chunks of data through an ACE_Message_Queue</FONT></B></CENTER> - - -<HR WIDTH="100%"> -<P> - -That's it for Tutorial 10. There are some esoteric changes between the thread-pool server -and this application but it's basically the same. In the next tutorial I'll modify this just -a bit to move non-trivial data through the queue. -<P> - -<UL> -<LI><A HREF="Makefile">Makefile</A> -<LI><A HREF="block.h">block.h</A> -<LI><A HREF="message_queue.cpp">message_queue.cpp</A> -<LI><A HREF="task.cpp">task.cpp</A> -<LI><A HREF="task.h">task.h</A> -</UL> -<HR WIDTH="100%"> - - -<CENTER>[<A HREF="..">Tutorial Index</A>]</CENTER> - -</BODY> -</HTML> - diff --git a/docs/tutorials/010/task.cpp b/docs/tutorials/010/task.cpp deleted file mode 100644 index 84f70cae0ee..00000000000 --- a/docs/tutorials/010/task.cpp +++ /dev/null @@ -1,134 +0,0 @@ - -// $Id$ - -#include "task.h" -#include "block.h" - -/* - Set our housekeeping pointer to NULL and tell the user we exist. - */ -Task::Task (void) -: barrier_ (0) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Task ctor 0x%x\n", (void *) this)); -} - -/* - Take care of cleanup & tell the user we're going away. -*/ -Task::~Task (void) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Task dtor 0x%x\n", (void *) this)); - - /* - Get our shutdown notification out of the queue and release it. - */ - ACE_Message_Block * message; - this->getq(message); - message->release(); - - delete barrier_; -} - -/* - Open the object to do work. We create the Barrier object and tell - it how many threads we'll be using. Next, we activate the Task - into the number of requested threads. -*/ -int Task::open (int threads) -{ - barrier_ = new ACE_Barrier (threads); - return this->activate (THR_NEW_LWP, threads); -} - -/* - Tell the user we're closing and invoke the baseclass' close() to - take care of things. -*/ -int Task::close (u_long flags) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Task close 0x%x\n", (void *) this)); - return inherited::close (flags); -} - -/* - Our svc() method waits for work on the queue and then processes that work. - */ -int Task::svc (void) -{ - /* - This will cause all of the threads to wait on this line until all - have invoked this method. The net result is that no thread in the - Task will get a shot at the queue until all of the threads are active. - There's no real need to do this but it's an easy intro into the use - of ACE_Barrier. - */ - this->barrier_->wait (); - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Task 0x%x starts in thread %d\n", (void *) this, ACE_Thread::self ())); - - /* - Remember that get() needs a reference to a pointer. To save stack - thrashing we'll go ahead and create a pointer outside of the almost- - infinite loop. - */ - ACE_Message_Block *message; - while (1) - { - /* - Get a message from the queue. - */ - if (this->getq (message) == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "getq"), -1); - } - - /* - If we got the shutdown request, we need to go away. - */ - if (message->msg_type () == ACE_Message_Block::MB_HANGUP) - { - /* - Forward the request to any peer threads. - */ - this->putq (message); - - /* - Leave the infinite loop so that the thread exits. - */ - break; - } - - /* - The message queue stores char* data. We use rd_ptr() to get to - the beginning of the data. - */ - const char *cp = message->rd_ptr (); - - /* - Move the rd_ptr() past the data we read. This isn't real useful - here since we won't be reading any more from the block but it's - a good habit to get into. - */ - message->rd_ptr( strlen(cp) ); - - /* - Display the block's address and data to the user. - */ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Block 0x%x contains (%s)\n", (void *) message, cp)); - - /* - Pretend that it takes a while to process the data. - */ - ACE_OS::sleep (ACE_Time_Value (0, 5000)); - - /* - Release the message block. Notice that we never delete a message block. - Blocks are reference counted & the release() method will take care of - the delete when there are no more references to the data. - */ - message->release (); - } - - return (0); -} diff --git a/docs/tutorials/010/task.h b/docs/tutorials/010/task.h deleted file mode 100644 index 9f242c124dd..00000000000 --- a/docs/tutorials/010/task.h +++ /dev/null @@ -1,53 +0,0 @@ - -// $Id$ - -#ifndef TASK_H -#define TASK_H - -#include "ace/Task.h" - -/* - Like the thread-pool server tutorial, we'll derive from ACE_Task<>. - Our goal here is to show off the ACE_Message_Queue and the best way - to do that is to use one to pass data between threads. The easiest - way to create threads is with ACE_Task<> - */ -class Task : public ACE_Task < ACE_MT_SYNCH > -{ -public: - - typedef ACE_Task < ACE_MT_SYNCH > inherited; - - /* - The constructor/destructor are simple but take care of some - necessary housekeeping. - */ - Task (void); - ~Task (void); - - /* - To make our Task<> derivative look more like other ACE objects - I've added an open() method. It will take care of activate()ing - the object. - */ - int open (int threads = 1); - - /* - Our worker method - */ - int svc (void); - - /* - All we'll do here is print a message to the user. - */ - int close (u_long flags = 0); - -protected: - /* - Just to be clever, I'll use an ACE_Barrier to cause the threads - to sync in svc() before doing any real work. - */ - ACE_Barrier *barrier_; -}; - -#endif diff --git a/docs/tutorials/011/Makefile b/docs/tutorials/011/Makefile deleted file mode 100644 index ed236e37bde..00000000000 --- a/docs/tutorials/011/Makefile +++ /dev/null @@ -1,60 +0,0 @@ - -# $Id$ - -#---------------------------------------------------------------------------- -# Local macros -#---------------------------------------------------------------------------- - -BIN = message_queue - -FILES = -FILES += task - -BUILD = $(VBIN) - -SRC = $(addsuffix .cpp,$(BIN)) $(addsuffix .cpp,$(FILES)) - -HDR = *.h - -#---------------------------------------------------------------------------- -# Include macros and targets -#---------------------------------------------------------------------------- - -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 -#---------------------------------------------------------------------------- - -Indent : # - for i in $(SRC) $(HDR) ; do \ - indent -npsl -l80 -fca -fc1 -cli0 -cdb -ts2 -bl -bli0 < $$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/' \ - -e 's/ / /g' \ - > $$i~ ;\ - mv $$i~ $$i ;\ - done - -Depend : depend - perl ../007/fix.Makefile - -.depend : # - touch .depend - -#---------------------------------------------------------------------------- -# Dependencies -#---------------------------------------------------------------------------- - -include .depend diff --git a/docs/tutorials/011/block.h b/docs/tutorials/011/block.h deleted file mode 100644 index bfd49d723f7..00000000000 --- a/docs/tutorials/011/block.h +++ /dev/null @@ -1,29 +0,0 @@ - -// $Id$ - -#ifndef BLOCK_H -#define BLOCK_H - -#include "ace/Message_Block.h" - -class Block : public ACE_Message_Block -{ -public: - Block (void) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Block ctor 0x%x\n", (void *) this)); - } - - Block (size_t size) - : ACE_Message_Block (size) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Block ctor 0x%x\n", (void *) this)); - } - - virtual ~ Block (void) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Block dtor 0x%x\n", (void *) this)); - } -}; - -#endif diff --git a/docs/tutorials/011/data.h b/docs/tutorials/011/data.h deleted file mode 100644 index 998b4d009ec..00000000000 --- a/docs/tutorials/011/data.h +++ /dev/null @@ -1,60 +0,0 @@ - -// $Id$ - -#ifndef DATA_H -#define DATA_H - -class DataBase -{ -public: - DataBase (void) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) DataBase ctor 0x%x\n", (void *) this)); - } - virtual ~ DataBase (void) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) DataBase dtor 0x%x\n", (void *) this)); - } - - void who_am_i (void) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) DataBase instance 0x%x\n", (void *) this)); - } - - virtual void what_am_i (void) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) I am a DataBase object\n")); - } - -}; - -class Data : public DataBase -{ -public: - Data (void) - : message_ (-1) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Data ctor 0x%x\n", (void *) this)); - } - - Data (int message) - : message_ (message) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Data ctor 0x%x for message %d\n", (void *) this, message_)); - } - virtual ~ Data (void) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Data dtor 0x%x\n", (void *) this)); - } - - void what_am_i (void) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) I am a Data object for message %d\n", message_)); - } - -protected: - int message_; - -}; - -#endif diff --git a/docs/tutorials/011/message_queue.cpp b/docs/tutorials/011/message_queue.cpp deleted file mode 100644 index 533ecec2f37..00000000000 --- a/docs/tutorials/011/message_queue.cpp +++ /dev/null @@ -1,79 +0,0 @@ - -// $Id$ - -/* - Most of this is the same as the previous tutorial, so I'll just point out - the differences. - */ -#include "task.h" -#include "block.h" -#include "data.h" - -int run_test (int iterations, int threads) -{ - Task task; - - if (task.open (threads) == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "open"), -1); - } - -ACE_OS::sleep (ACE_Time_Value (1)); - - int i; - for (i = 0; i < iterations; ++i) - { - /* - Construct a Data object that we'll put into the Queue. - */ - Data data (i); - - /* - Create a block large enough for our Data object as well as a text - message. - */ - Block *message = new Block (sizeof (data) + 128); - - /* - As before, put a text message into the block. - */ - ACE_OS::sprintf (message->wr_ptr (), "This is message %d.", i); - message->wr_ptr (strlen (message->rd_ptr ())); - - *(message->wr_ptr ()) = 0; // Null-terminate the string we just wrote - - message->wr_ptr (1); // Move beyond the NULL - - /* - To copy arbitrary data into a message block, we use the copy() method. - Since it wants a 'const char*', we have to cast our Data pointer. - */ - message->copy ((const char *) &data, sizeof (data)); - message->wr_ptr (sizeof (data)); - - if (task.putq (message) == -1) - { - break; - } - } - - Block *message = new Block (); -message->msg_type (ACE_Message_Block::MB_HANGUP); - task.putq (message); - - task.wait (); - - return (0); -} - -int main (int argc, char *argv[]) -{ - int iterations = argc > 1 ? atoi (argv[1]) : 4; - int threads = argc > 2 ? atoi (argv[2]) : 2; - - (void) run_test (iterations, threads); - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Application exiting\n")); - - exit (0); -} diff --git a/docs/tutorials/011/page01.html b/docs/tutorials/011/page01.html deleted file mode 100644 index bb61f2dbe34..00000000000 --- a/docs/tutorials/011/page01.html +++ /dev/null @@ -1,30 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 011</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 011</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Passing non-trivial data through an ACE_Message_Queue</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> -<P> -In the previous tutorial we learned how to put text into a message queue. -While that may be useful, it isn't very exciting or realistic. In most -cases you'll need to move complex data structures between your threads. -<P> -In this tutorial I'll expand the previous by moving not only a text string -but also a more complex object. In the next tutorial I'll change things -again so that we move the complex object a bit more efficiently. -<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/011/page02.html b/docs/tutorials/011/page02.html deleted file mode 100644 index 3423236c2ac..00000000000 --- a/docs/tutorials/011/page02.html +++ /dev/null @@ -1,111 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 011</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 011</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Passing non-trivial data through an ACE_Message_Queue</FONT></B></CENTER> - - -<HR WIDTH="100%"> -<P> - -We'll look first at <A HREF="message_queue.cpp">main()</A>. A large part of this is -the same as before, so I've only commented the changes. -<P> - -<HR WIDTH="100%"> -<P> -<PRE> -#include "task.h" -#include "block.h" -#include "data.h" - -int run_test (int iterations, int threads) -{ - Task task; - - if (task.open (threads) == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "open"), -1); - } - - ACE_OS::sleep (ACE_Time_Value (1)); - - int i; - for (i = 0; i < iterations; ++i) - { - /* - Construct a Data object that we'll put into the Queue. - */ - Data data (i); - - /* - Create a block large enough for our Data object as well - as a text message. - */ - Block *message = new Block (sizeof (data) + 128); - - /* - As before, put a text message into the block. - */ - ACE_OS::sprintf (message->wr_ptr (), "This is message %d.", i); - message->wr_ptr (strlen (message->rd_ptr ())); - - *(message->wr_ptr()) = 0; // Null-terminate the string we just wrote - message->wr_ptr(1); // Move beyond the NULL - - /* - To copy arbitrary data into a message block, we use the copy() method. - Since it wants a 'const char*', we have to cast our Data pointer. - */ - message->copy ((const char *) &data, sizeof (data)); - message->wr_ptr (sizeof (data)); - - if (task.putq (message) == -1) - { - break; - } - } - - Block *message = new Block (); - message->msg_type (ACE_Message_Block::MB_HANGUP); - task.putq (message); - - task.wait (); - - return (0); -} - -int main (int argc, char *argv[]) -{ - int iterations = argc > 1 ? atoi (argv[1]) : 4; - int threads = argc > 2 ? atoi (argv[2]) : 2; - - (void) run_test (iterations, threads); - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Application exiting\n")); - - exit (0); -} -</PRE> - -<HR WIDTH="100%"> -<P> -The new trick here is the use of copy() to copy our abstract data object -into the message block memory. Notice that it's OK to let the Data object -go out of scope at that point since we've got a separate copy. If you've -got something with a non-trivial ctor/dtor then this won't work. We'll address -that in the next tutorial. -<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/011/page03.html b/docs/tutorials/011/page03.html deleted file mode 100644 index 690bf01ce0c..00000000000 --- a/docs/tutorials/011/page03.html +++ /dev/null @@ -1,136 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 011</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 011</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Passing non-trivial data through an ACE_Message_Queue</FONT></B></CENTER> - - -<HR WIDTH="100%"> -<P> - -Our <A HREF="task.cpp">Task</A> object definition. As with message_queue.cpp, -I've only commented the changes. -<P> - -<HR WIDTH="100%"> -<PRE> - -#include "task.h" -#include "block.h" -#include "data.h" - -Task::Task (void) -: barrier_ (0) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Task ctor 0x%x\n", (void *) this)); -} - -Task::~Task (void) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Task dtor 0x%x\n", (void *) this)); - - ACE_Message_Block *message; - this->getq (message); - message->release (); - - delete barrier_; -} - -int Task::open (int threads) -{ - barrier_ = new ACE_Barrier (threads); - return this->activate (THR_NEW_LWP, threads); -} -int Task::close (u_long flags) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Task close 0x%x\n", (void *) this)); - return inherited::close (flags); -} - -int Task::svc (void) -{ - this->barrier_->wait (); - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Task 0x%x starts in thread %d\n", (void *) this, ACE_Thread::self ())); - - ACE_Message_Block *message; - while (1) - { - if (this->getq (message) == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "getq"), -1); - } - - if (message->msg_type () == ACE_Message_Block::MB_HANGUP) - { - this->putq (message); - - break; - } - - const char *cp = message->rd_ptr (); - message->rd_ptr (strlen (cp) + 1); // Don't forget to skip the NULL we - // inserted - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Block 0x%x contains (%s)\n", (void *) message, cp)); - - /* - Create a Data object into which we can extract the message block - contents. - */ - Data data; - /* - Use the rd_ptr() to access the message block data. Note that we've - already moved it past the text string in the block. - */ - ACE_OS::memmove ((char *) &data, message->rd_ptr (), sizeof (data)); - message->rd_ptr (sizeof (data)); // Move the rd_ptr() beyond the data. - - /* - Invoke a couple of method calls on the object we constructed. - */ - data.who_am_i (); - data.what_am_i (); - - /* - An alternate approach: - - Data * data; - data = (Data *)message->rd_ptr(); - data->who_am_i(); - data->what_am_i(); - message->rd_ptr(sizeof(Data)); - - Even though this cuts down on the number of copies & constructions, I'm - not real fond of it. You can get into trouble in a hurry by treating - memory blocks as multiple data types... - */ - - - ACE_OS::sleep (ACE_Time_Value (0, 5000)); - - message->release (); - } - - return (0); -} -</PRE> -<HR WIDTH="100%"> -<P> -Notice how we had to create a temporary Data object to copy the stuff out -of the message block? Again, if there were non-trivial ctor/dtors involved -then this wouldn't work at all. -<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/011/page04.html b/docs/tutorials/011/page04.html deleted file mode 100644 index 9e701d4216f..00000000000 --- a/docs/tutorials/011/page04.html +++ /dev/null @@ -1,91 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 011</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 011</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Passing non-trivial data through an ACE_Message_Queue</FONT></B></CENTER> - - -<HR WIDTH="100%"> -<P> - -Before we go further, let's look at this <A HREF="data.h">Data</A> object -that's causing all the fuss. - -<P> -<HR WIDTH="100%"> -<PRE> - -class DataBase -{ -public: - DataBase (void) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) DataBase ctor 0x%x\n", (void *) this)); - } - virtual ~ DataBase (void) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) DataBase dtor 0x%x\n", (void *) this)); - } - - void who_am_i (void) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) DataBase instance 0x%x\n", (void *) this)); - } - - virtual void what_am_i (void) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) I am a DataBase object\n")); - } - -}; - -class Data : public DataBase -{ -public: - Data (void) - : message_ (-1) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Data ctor 0x%x\n", (void *) this)); - } - - Data (int message) - : message_ (message) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Data ctor 0x%x for message %d\n", (void *) this, message_)); - } - virtual ~ Data (void) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Data dtor 0x%x\n", (void *) this)); - } - - void what_am_i (void) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) I am a Data object for message %d\n", message_)); - } - -protected: - int message_; - -}; - -</PRE> -<HR WIDTH="100%"> -<P> -Ok, no mysterious magic on this one. Just a simple object and derivative -that report their existence. -<P> -<HR WIDTH="100%"> - - -<CENTER>[<A HREF="..">Tutorial Index</A>][<A HREF="page05.html">Continue -This Tutorial</A>]</CENTER> -</CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/011/page05.html b/docs/tutorials/011/page05.html deleted file mode 100644 index 813050f8a1e..00000000000 --- a/docs/tutorials/011/page05.html +++ /dev/null @@ -1,99 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 011</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 011</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Passing non-trivial data through an ACE_Message_Queue</FONT></B></CENTER> - - -<HR WIDTH="100%"> -<P> - -Let's take a look at this new program's output: - -<P> -<HR WIDTH="100%"> -<PRE> -[jcej@chiroptera 011]$./message_queue 4 2 -(12108|1024) Task ctor 0xbffff9c8 -(12108|2050) Task 0xbffff9c8 starts in thread 2050 -(12108|1025) Task 0xbffff9c8 starts in thread 1025 -(12108|1024) DataBase ctor 0xbffff9c0 -(12108|1024) Data ctor 0xbffff9c0 for message 0 -(12108|1024) Block ctor 0x8052d08 -(12108|1024) Data dtor 0xbffff9c0 -(12108|1024) DataBase dtor 0xbffff9c0 -(12108|1024) DataBase ctor 0xbffff9c0 -(12108|1024) Data ctor 0xbffff9c0 for message 1 -(12108|1024) Block ctor 0x8052e00 -(12108|1024) Data dtor 0xbffff9c0 -(12108|1024) DataBase dtor 0xbffff9c0 -(12108|1024) DataBase ctor 0xbffff9c0 -(12108|1024) Data ctor 0xbffff9c0 for message 2 -(12108|1024) Block ctor 0x8052ef8 -(12108|1024) Data dtor 0xbffff9c0 -(12108|1024) DataBase dtor 0xbffff9c0 -(12108|1024) DataBase ctor 0xbffff9c0 -(12108|1024) Data ctor 0xbffff9c0 for message 3 -(12108|1024) Block ctor 0x8052ff0 -(12108|1024) Data dtor 0xbffff9c0 -(12108|1024) DataBase dtor 0xbffff9c0 -(12108|1024) Block ctor 0x80530e8 -(12108|1025) Block 0x8052d08 contains (This is message 0.) -(12108|1025) DataBase ctor 0xbf9ffe20 -(12108|1025) Data ctor 0xbf9ffe20 -(12108|1025) DataBase instance 0xbf9ffe20 -(12108|1025) I am a Data object for message 0 -(12108|1025) Block dtor 0x8052d08 -(12108|1025) Data dtor 0xbf9ffe20 -(12108|1025) DataBase dtor 0xbf9ffe20 -(12108|1025) Block 0x8052e00 contains (This is message 1.) -(12108|1025) DataBase ctor 0xbf9ffe20 -(12108|1025) Data ctor 0xbf9ffe20 -(12108|1025) DataBase instance 0xbf9ffe20 -(12108|1025) I am a Data object for message 1 -(12108|1025) Block dtor 0x8052e00 -(12108|1025) Data dtor 0xbf9ffe20 -(12108|1025) DataBase dtor 0xbf9ffe20 -(12108|1025) Block 0x8052ef8 contains (This is message 2.) -(12108|1025) DataBase ctor 0xbf9ffe20 -(12108|1025) Data ctor 0xbf9ffe20 -(12108|1025) DataBase instance 0xbf9ffe20 -(12108|1025) I am a Data object for message 2 -(12108|1025) Block dtor 0x8052ef8 -(12108|1025) Data dtor 0xbf9ffe20 -(12108|1025) DataBase dtor 0xbf9ffe20 -(12108|1025) Block 0x8052ff0 contains (This is message 3.) -(12108|1025) DataBase ctor 0xbf9ffe20 -(12108|1025) Data ctor 0xbf9ffe20 -(12108|1025) DataBase instance 0xbf9ffe20 -(12108|1025) I am a Data object for message 3 -(12108|2050) Task close 0xbffff9c8 -(12108|1025) Block dtor 0x8052ff0 -(12108|1025) Data dtor 0xbf9ffe20 -(12108|1025) DataBase dtor 0xbf9ffe20 -(12108|1025) Task close 0xbffff9c8 -(12108|1024) Task dtor 0xbffff9c8 -(12108|1024) Block dtor 0x80530e8 -(12108|1024) Application exiting -[jcej@chiroptera 011]$ -</PRE> -<HR WIDTH="100%"> -<P> -Other than being more verbose because of the Data object, this shows us -the same thing we've seen before. -<P> -<HR WIDTH="100%"> - - -<CENTER>[<A HREF="..">Tutorial Index</A>][<A HREF="page06.html">Continue -This Tutorial</A>]</CENTER> -</CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/011/page06.html b/docs/tutorials/011/page06.html deleted file mode 100644 index bde7f86e04c..00000000000 --- a/docs/tutorials/011/page06.html +++ /dev/null @@ -1,38 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 011</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 011</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Passing non-trivial data through an ACE_Message_Queue</FONT></B></CENTER> - - -<HR WIDTH="100%"> -<P> -So, this time we stuffed an object into the message queue instead of just text -data. Each time required two object constructions (and subsequent destructions) -and two "deep" copy operations on the object. There might actually be times when -this is OK for your application but I prefer to keep those things down to a -minimum. In the next tutorial I'll show you a way to do that. -<P> - -<UL> -<LI><A HREF="Makefile">Makefile</A> -<LI><A HREF="block.h">block.h</A> -<LI><A HREF="data.h">data.h</A> -<LI><A HREF="message_queue.cpp">message_queue.cpp</A> -<LI><A HREF="task.cpp">task.cpp</A> -<LI><A HREF="task.h">task.h</A> -</UL> -<HR WIDTH="100%"> - - -<CENTER>[<A HREF="..">Tutorial Index</A>]</CENTER> - -</BODY> -</HTML> - diff --git a/docs/tutorials/011/task.cpp b/docs/tutorials/011/task.cpp deleted file mode 100644 index a7215191481..00000000000 --- a/docs/tutorials/011/task.cpp +++ /dev/null @@ -1,102 +0,0 @@ - -// $Id$ - -#include "task.h" -#include "block.h" -#include "data.h" - -Task::Task (void) -: barrier_ (0) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Task ctor 0x%x\n", (void *) this)); -} - -Task::~Task (void) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Task dtor 0x%x\n", (void *) this)); - - ACE_Message_Block *message; - this->getq (message); - message->release (); - - delete barrier_; -} - -int Task::open (int threads) -{ - barrier_ = new ACE_Barrier (threads); - return this->activate (THR_NEW_LWP, threads); -} -int Task::close (u_long flags) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Task close 0x%x\n", (void *) this)); - return inherited::close (flags); -} - -int Task::svc (void) -{ - this->barrier_->wait (); - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Task 0x%x starts in thread %d\n", (void *) this, ACE_Thread::self ())); - - ACE_Message_Block *message; - while (1) - { - if (this->getq (message) == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "getq"), -1); - } - - if (message->msg_type () == ACE_Message_Block::MB_HANGUP) - { - this->putq (message); - - break; - } - - const char *cp = message->rd_ptr (); - message->rd_ptr (strlen (cp) + 1); // Don't forget to skip the NULL we - // inserted - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Block 0x%x contains (%s)\n", (void *) message, cp)); - - /* - Create a Data object into which we can extract the message block - contents. - */ - Data data; - /* - Use the rd_ptr() to access the message block data. Note that we've - already moved it past the text string in the block. - */ - ACE_OS::memmove ((char *) &data, message->rd_ptr (), sizeof (data)); - message->rd_ptr (sizeof (data)); // Move the rd_ptr() beyond the data. - - /* - Invoke a couple of method calls on the object we constructed. - */ - data.who_am_i (); - data.what_am_i (); - - /* - An alternate approach: - - Data * data; - data = (Data *)message->rd_ptr(); - data->who_am_i(); - data->what_am_i(); - message->rd_ptr(sizeof(Data)); - - Even though this cuts down on the number of copies & constructions, I'm - not real fond of it. You can get into trouble in a hurry by treating - memory blocks as multiple data types... - */ - - - ACE_OS::sleep (ACE_Time_Value (0, 5000)); - - message->release (); - } - - return (0); -} diff --git a/docs/tutorials/011/task.h b/docs/tutorials/011/task.h deleted file mode 100644 index 436326c68a0..00000000000 --- a/docs/tutorials/011/task.h +++ /dev/null @@ -1,28 +0,0 @@ - -// $Id$ - -#ifndef TASK_H -#define TASK_H - -#include "ace/Task.h" - -class Task : public ACE_Task < ACE_MT_SYNCH > -{ -public: - - typedef ACE_Task < ACE_MT_SYNCH > inherited; - - Task (void); - ~Task (void); - - int open (int threads = 1); - - int svc (void); - - int close (u_long flags = 0); - -protected: - ACE_Barrier * barrier_; -}; - -#endif diff --git a/docs/tutorials/012/Makefile b/docs/tutorials/012/Makefile deleted file mode 100644 index ed236e37bde..00000000000 --- a/docs/tutorials/012/Makefile +++ /dev/null @@ -1,60 +0,0 @@ - -# $Id$ - -#---------------------------------------------------------------------------- -# Local macros -#---------------------------------------------------------------------------- - -BIN = message_queue - -FILES = -FILES += task - -BUILD = $(VBIN) - -SRC = $(addsuffix .cpp,$(BIN)) $(addsuffix .cpp,$(FILES)) - -HDR = *.h - -#---------------------------------------------------------------------------- -# Include macros and targets -#---------------------------------------------------------------------------- - -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 -#---------------------------------------------------------------------------- - -Indent : # - for i in $(SRC) $(HDR) ; do \ - indent -npsl -l80 -fca -fc1 -cli0 -cdb -ts2 -bl -bli0 < $$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/' \ - -e 's/ / /g' \ - > $$i~ ;\ - mv $$i~ $$i ;\ - done - -Depend : depend - perl ../007/fix.Makefile - -.depend : # - touch .depend - -#---------------------------------------------------------------------------- -# Dependencies -#---------------------------------------------------------------------------- - -include .depend diff --git a/docs/tutorials/012/data.h b/docs/tutorials/012/data.h deleted file mode 100644 index 3c656608425..00000000000 --- a/docs/tutorials/012/data.h +++ /dev/null @@ -1,128 +0,0 @@ - -// $Id$ - -#ifndef DATA_H -#define DATA_H - -#include "ace/Message_Block.h" - -/* - We'll start by defining a basic unit of work that can be put into - the message queue. The threads in the pool will expect to find one - of these in each message block and will invoke a method or two. -*/ -class Unit_Of_Work -{ -public: - Unit_Of_Work (void) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Unit_Of_Work ctor 0x%x\n", (void *) this)); - } - virtual ~ Unit_Of_Work (void) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Unit_Of_Work dtor 0x%x\n", (void *) this)); - } - - void who_am_i (void) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Unit_Of_Work instance 0x%x\n", (void *) this)); - } - - virtual void what_am_i (void) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) I am a Unit_Of_Work object\n")); - } - -}; - -/* - Now, we specialize the Unit_Of_Work object to do something - different. By overriding the virtual methods, we can do whatever - "real work" is needed but the thread pool doesn't have to know the specifics. -*/ -class Work : public Unit_Of_Work -{ -public: - Work (void) - : message_ (-1) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Work ctor 0x%x\n", (void *) this)); - } - - Work (int message) - : message_ (message) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Work ctor 0x%x for message %d\n", (void *) this, message_)); - } - virtual ~ Work (void) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Work dtor 0x%x\n", (void *) this)); - } - - void what_am_i (void) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) I am a Work object for message %d\n", message_)); - } - -protected: - int message_; - -}; - -/* - We derive a Message_Block from ACE_Message_Block and teach it about - our Unit_Of_Work object. When our task's svc() method pulls a block - out of the queue, it can then invoke the virtual methods of the work - object safely. In this implementation we've also retained the - original ACE_Message_Block functionallity so that we can use the - underlying ACE_Data_Block objects to store data other than our - Unit_Of_Work. -*/ -class Message_Block : public ACE_Message_Block -{ -public: - typedef ACE_Message_Block inherited; - - /* - Construct our underlying ACE_Message_Block with the requested - data size and initialize our Unit_Of_Work pointer with the - given object instance. Note that this Message_Block instance - now assumes ownership of the Unit_Of_Work and will delete it - when the Message_Block is deleted. - */ - Message_Block( size_t size, Unit_Of_Work * _data ) - : inherited(size), data_(_data) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Message_Block ctor 0x%x for 0x%x\n", (void *) this, data_)); - } - - ~Message_Block(void) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Message_Block dtor 0x%x for 0x%x\n", (void *) this, data_)); - delete data_; - } - - /* - Return the Unit_Of_Work so that the task can invoke methods on - it. - */ - Unit_Of_Work * data(void) - { - return this->data_; - } - -protected: - Unit_Of_Work * data_; - - /* - Disallow these very dangerous operations. - If we were to copy a Message_Block object then the data_ - pointer would get copied and we would eventually end up - deleting the same object multiple times! That's not good. By - preventing the copy, we can avoid this. - */ - Message_Block &operator= (const Message_Block &); - Message_Block (const Message_Block &); -}; - -#endif diff --git a/docs/tutorials/012/message_queue.cpp b/docs/tutorials/012/message_queue.cpp deleted file mode 100644 index b4fee1be01b..00000000000 --- a/docs/tutorials/012/message_queue.cpp +++ /dev/null @@ -1,96 +0,0 @@ - -// $Id$ - -#include "data.h" -#include "task.h" - -/* - I want to be sure that our Task object gets destructed correctly, so - I'll do most of the application 'work' in run_test() instead of - main() -*/ -int run_test (int iterations, int threads) -{ - /* - Create the Task which is our thread pool for doing work - */ - Task task; - - if (task.open (threads) == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "open"), -1); - } - - /* - Give the Task a chance to enter it's svc() method. This isn't - really necessary and you probably wouldn't do it in a real - application but it makes the output more interesting. - */ - ACE_OS::sleep (ACE_Time_Value (1)); - - for (int i = 0; i < iterations; ++i) - { - /* - Construct a Work object that we'll put into the Queue. Give it - the iteration number so that it can identify itself in the output. - */ - Work * data = new Work(i); - - /* - Create a block that contains our Work object but also has - enough room for a text message. - */ - Message_Block *message = new Message_Block (128, data); - - /* - As before, put a text message into the block. - */ - ACE_OS::sprintf (message->wr_ptr (), "This is message %d.", i); - message->wr_ptr (strlen (message->rd_ptr ())+1); - - /* - Add the work to our thread pool - */ - if (task.putq (message) == -1) - { - break; - } - } - - /* - Insert a HANGUP message block to tell the thread pool to shut - itself down. - */ - Message_Block *message = new Message_Block (0,0); - message->msg_type (ACE_Message_Block::MB_HANGUP); - task.putq (message); - - /* - Wait for the all threads of the Task to exit. It is rather rude - to let the Task go out of scope without doing this first. - */ - task.wait (); - - return (0); -} - -int main (int argc, char *argv[]) -{ - /* - Give the user a chance to override the default number of - iterations and pool threads. - */ - int iterations = argc > 1 ? atoi (argv[1]) : 4; - int threads = argc > 2 ? atoi (argv[2]) : 2; - - /* - Use the function above to do the actual test. As I said, this - lets us see the Task go out of scope and destruct before our - "exiting" message below. - */ - (void) run_test (iterations, threads); - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Application exiting\n")); - - exit (0); -} diff --git a/docs/tutorials/012/page01.html b/docs/tutorials/012/page01.html deleted file mode 100644 index a799f932016..00000000000 --- a/docs/tutorials/012/page01.html +++ /dev/null @@ -1,32 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 012</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 012</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Passing classes through ACE_Message_Queue</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> -<P> -Last time around we put an object into a message queue by using the -copy() method to create a duplicate of the object. That's probably OK -for simple objects that aren't very large. However, if you have an -object that contains pointers or tons of data then that approach is -going to cause problems. -<P> -What we'll do in this tutorial is specialize the ACE_Message_Block -object so that it can carry our data more efficiently. As you'll see, -this isn't very difficult at all. -<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/012/page02.html b/docs/tutorials/012/page02.html deleted file mode 100644 index 9647dd84a83..00000000000 --- a/docs/tutorials/012/page02.html +++ /dev/null @@ -1,104 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 012</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 012</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Passing classes through ACE_Message_Queue</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> -<P> -We normally start by looking at main() and work our way out from -there. This time, I want to start by showing you the ACE_Message_Block -derivative but before that, I have to introduce you to the Work object -and it's baseclass Unit_Of_Work -<P> -<HR WIDTH="100%"> -<PRE> - -/* - We'll start by defining a basic unit of work that can be put into - the message queue. The threads in the pool will expect to find one - of these in each message block and will invoke a method or two. -*/ -class Unit_Of_Work -{ -public: - Unit_Of_Work (void) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Unit_Of_Work ctor 0x%x\n", (void *) this)); - } - virtual ~ Unit_Of_Work (void) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Unit_Of_Work dtor 0x%x\n", (void *) this)); - } - - void who_am_i (void) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Unit_Of_Work instance 0x%x\n", (void *) this)); - } - - virtual void what_am_i (void) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) I am a Unit_Of_Work object\n")); - } - -}; - -/* - Now, we specialize the Unit_Of_Work object to do something - different. By overriding the virtual method, we can do whatever - "real work" is needed but the thread pool doesn't have to know the specifics. -*/ -class Work : public Unit_Of_Work -{ -public: - Work (void) - : message_ (-1) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Work ctor 0x%x\n", (void *) this)); - } - - Work (int message) - : message_ (message) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Work ctor 0x%x for message %d\n", (void *) this, message_)); - } - virtual ~ Work (void) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Work dtor 0x%x\n", (void *) this)); - } - - void what_am_i (void) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) I am a Work object for message %d\n", message_)); - } - -protected: - int message_; - -}; -</PRE> -<HR WIDTH="100%"> -<P> -This is basically the same as the <i>DataBase</i> in the previous -tutorial but I've changed the name to be more generic. The feeling is -that a <i>Data</i> object would be a C struct but an <i>Work</i> -object would be a class with methods. -<P> -Now that you know what we'll be putting into the queue, lets go to the -next page where I specialize the ACE_Message_Block. -<P> -<HR WIDTH="100%"> -<P> -<CENTER>[<A HREF="..">Tutorial Index</A>] [<A HREF="page03.html">Continue -This Tutorial</A>]</CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/012/page03.html b/docs/tutorials/012/page03.html deleted file mode 100644 index c0a94ee30a1..00000000000 --- a/docs/tutorials/012/page03.html +++ /dev/null @@ -1,100 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 012</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 012</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Passing classes through ACE_Message_Queue</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> -<P> -In the previous tutorial we moved our complex data into the queue by -copy()ing it directly into the message block's data area. I hope that -most readers got a queasy feeling when I did that. It just isn't a -good idea... -<P> -A better idea would be to teach the message queue about our data types -(or at least a baseclass) so that it can more efficiently handle things: -<P> -<HR WIDTH="100%"> -<PRE> -/* - We derive a Message_Block from ACE_Message_Block and teach it about - our Unit_Of_Work object. When our task's svc() method pulls a block - out of the queue, it can then invoke the virtual methods of the work - object safely. In this implementation we've also retained the - original ACE_Message_Block functionallity so that we can use the - underlying ACE_Data_Block objects to store data other than our - Unit_Of_Work. -*/ -class Message_Block : public ACE_Message_Block -{ -public: - typedef ACE_Message_Block inherited; - - /* - Construct our underlying ACE_Message_Block with the requested - data size and initialize our Unit_Of_Work pointer with the - given object instance. Note that this Message_Block instance - now assumes ownership of the Unit_Of_Work and will delete it - when the Message_Block is deleted. - */ - Message_Block( size_t size, Unit_Of_Work * _data ) - : inherited(size), data_(_data) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Message_Block ctor 0x%x for 0x%x\n", (void *) this, data_)); - } - - ~Message_Block(void) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Message_Block dtor 0x%x for 0x%x\n", (void *) this, data_)); - delete data_; - } - - /* - Return the Unit_Of_Work so that the task can invoke methods on - it. - */ - Unit_Of_Work * data(void) - { - return this->data_; - } - -protected: - Unit_Of_Work * data_; - - /* - Disallow these very dangerous operations. - If we were to copy a Message_Block object then the data_ - pointer would get copied and we would eventually end up - deleting the same object multiple times! That's not good. By - preventing the copy, we can avoid this. - */ - Message_Block &operator= (const Message_Block &); - Message_Block (const Message_Block &); -}; -</PRE> -<HR WIDTH="100%"> -<P> -Ok, this looks pretty good. We just construct our specialized -Message_Block instead of the generic ACE_Message_Block and let it -carry our data along. When our application is done with the message -block and release()es it, we know that our work object will also be -taken care of. -<P> -Let's now go to main() and see what we had to change there to use this -specialization. -<P> -<HR WIDTH="100%"> -<P> -<CENTER>[<A HREF="..">Tutorial Index</A>] [<A HREF="page04.html">Continue -This Tutorial</A>]</CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/012/page04.html b/docs/tutorials/012/page04.html deleted file mode 100644 index 34e51c643ee..00000000000 --- a/docs/tutorials/012/page04.html +++ /dev/null @@ -1,124 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 012</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 012</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Passing classes through ACE_Message_Queue</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> -<P> -Ok, finally we get to main(). Sorry for the diversion but it was -important to lay some of that groundwork before getting here. -<P> -<HR WIDTH="100%"> -<PRE> -/* - I want to be sure that our Task object gets destructed correctly, so - I'll do most of the application 'work' in run_test() instead of - main() -*/ -int run_test (int iterations, int threads) -{ - /* - Create the Task which is our thread pool for doing work - */ - Task task; - - if (task.open (threads) == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "open"), -1); - } - - /* - Give the Task a chance to enter it's svc() method. This isn't - really necessary and you probably wouldn't do it in a real - application but it makes the output more interesting. - */ - ACE_OS::sleep (ACE_Time_Value (1)); - - for (int i = 0; i < iterations; ++i) - { - /* - Construct a Work object that we'll put into the Queue. Give it - the iteration number so that it can identify itself in the output. - */ - Work * data = new Work(i); - - /* - Create a block that contains our Work object but also has - enough room for a text message. - */ - Message_Block *message = new Message_Block (128, data); - - /* - As before, put a text message into the block. - */ - ACE_OS::sprintf (message->wr_ptr (), "This is message %d.", i); - message->wr_ptr (strlen (message->rd_ptr ())+1); - - /* - Add the work to our thread pool - */ - if (task.putq (message) == -1) - { - break; - } - } - - /* - Insert a HANGUP message block to tell the thread pool to shut - itself down. - */ - Message_Block *message = new Message_Block (0,0); - message->msg_type (ACE_Message_Block::MB_HANGUP); - task.putq (message); - - /* - Wait for the all threads of the Task to exit. It is rather rude - to let the Task go out of scope without doing this first. - */ - task.wait (); - - return (0); -} - -int main (int argc, char *argv[]) -{ - /* - Give the user a chance to override the default number of - iterations and pool threads. - */ - int iterations = argc > 1 ? atoi (argv[1]) : 4; - int threads = argc > 2 ? atoi (argv[2]) : 2; - - /* - Use the function above to do the actual test. As I said, this - lets us see the Task go out of scope and destruct before our - "exiting" message below. - */ - (void) run_test (iterations, threads); - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Application exiting\n")); - - exit (0); -} -</PRE> -<HR WIDTH="100%"> -<P> -That certainly looks cleaner than the previous approach! If you -blink, you'll miss the part where the Work object goes into the Queue. -<P> -<HR WIDTH="100%"> -<P> -<CENTER>[<A HREF="..">Tutorial Index</A>] [<A HREF="page05.html">Continue -This Tutorial</A>]</CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/012/page05.html b/docs/tutorials/012/page05.html deleted file mode 100644 index 89c3e6f8da0..00000000000 --- a/docs/tutorials/012/page05.html +++ /dev/null @@ -1,211 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 012</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 012</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Passing classes through ACE_Message_Queue</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> -<P> -The Task is the only object we've not been through yet. I'll go ahead -and show both the header and cpp on this one page since the header -isn't very large. -<P> -<HR WIDTH="100%"> -<PRE> - -/* - This is our basic thread-pool Task. We have a choice of pool size - on the open() and the usual svc() and close() methods. - - A new addition is the ACE_Barrier object. This will allow the - synchronization of our svc() methods so that they all start at the - "same" time. The normal case may allow one thread to start working - earlier than others. There's no real harm in it but you can get - better "work by thread" statistics if they start out together. -*/ -class Task : public ACE_Task < ACE_MT_SYNCH > -{ -public: - - typedef ACE_Task < ACE_MT_SYNCH > inherited; - - Task (void); - ~Task (void); - - int open (int threads = 1); - - int svc (void); - - int close (u_long flags = 0); - -protected: - ACE_Barrier * barrier_; -}; -</PRE> -<HR WIDTH="50%"> -<PRE> -/* - Boring default constructor. Be sure our barrier_ is initialized in - case we get destructed before opened. -*/ -Task::Task (void) -: barrier_ (0) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Task ctor 0x%x\n", (void *) this)); -} - -/* - You'll see in the svc() method that when we get a shutdown request, - we always putq() it back into our message queue. The last thread in - the pool will do this also and result in there always being one - shutdown request left in the queue when we get here. Just to be - polite, we'll go ahead and get that message and release it. - - We also delete the barrier_ object we used to synch the svc() - methods. -*/ -Task::~Task (void) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Task dtor 0x%x\n", (void *) this)); - - ACE_Message_Block *message; - this->getq (message); - message->release (); - - delete barrier_; -} - -/* - The ACE_Barrier needs to know how many threads it will be working - for. For that reason, we have to put off it's construction until we - get here. We then pass the thread count through to our base class' - activate(). -*/ -int Task::open (int threads) -{ - barrier_ = new ACE_Barrier (threads); - return this->activate (THR_NEW_LWP, threads); -} - -/* - We don't really do anything here but I wanted to provide a message - in the output. -*/ -int Task::close (u_long flags) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Task close 0x%x\n", (void *) this)); - return inherited::close (flags); -} - -/* - Now the svc() method where everything interesting happens. -*/ -int Task::svc (void) -{ - /* - All of the threads will block here until the last thread - arrives. They will all then be free to begin doing work. - */ - this->barrier_->wait (); - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Task 0x%x starts in thread %u\n", (void *) this, ACE_Thread::self ())); - - // Where we getq() the message - ACE_Message_Block *message; - // What we really put into the queue is a Message_Block, so we'll - // cast the 'message' to 'message_block' after getting it. I'm - // going through some extra steps here just to be explicit - Message_Block * message_block; - // The baseclass of the work object we put into the queue. Notice - // that we can use this and not bother with the Work object at all. - Unit_Of_Work * unit_of_work; - - while (1) - { - // Get the message... - if (this->getq (message) == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "getq"), -1); - } - - // Is it a shutdown request? - if (message->msg_type () == ACE_Message_Block::MB_HANGUP) - { - // Send the shutdown to all of our pool peers - this->putq (message); - break; - } - - // Cast the pointer to our specialized Message_Block. We could - // have done this at the getq() call but I wanted to be explicit - // about what we're doing here - message_block = (Message_Block*)message; - - /* - Since we left alone the ACE_Data_Block used by the - Message_Block we have chosen to use it to send arbitrary data - as well. - */ - const char *cp = message_block->rd_ptr (); - // Don't forget to skip the NULL we inserted - message_block->rd_ptr (strlen (cp) + 1); - - /* - Get the Unit_Of_Work pointer out of our specialized - Message_Block. Since the methods of interest are virtual, we - don't have to know what kind of work we're to do. - */ - unit_of_work = message_block->data(); - - /* - Invoke a couple of method calls on the object we constructed. - */ - unit_of_work->who_am_i (); - unit_of_work->what_am_i (); - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Block 0x%x contains (%s)\n", (void *) message, cp)); - - /* - Pretend that the work takes a little time to process. This - prevents one thread from getting all of the action. In a real - system you wouldn't need to do this since the work really - would take time to complete. - */ - ACE_OS::sleep (ACE_Time_Value (0, 5000)); - - /* - Release the message block and allow the unit of work to also go - away. - */ - message->release (); - } - - return (0); -} -</PRE> -<HR WIDTH="100%"> -<P> -Like main() this is actually simpler than the previous tutorial. It's -much cleaner to carry around a pointer to the object we're working -with than to try copying data. -<P> -The only complication is the new ACE_Barrier. It's a pretty simple -object that makes it easy for you to synch threads in this way. You -could do some fancy tricks with mutexes, counters & semaphores but why -bother when the Barrier already exists. -<P> -<HR WIDTH="100%"> -<P> -<CENTER>[<A HREF="..">Tutorial Index</A>] [<A HREF="page06.html">Continue -This Tutorial</A>]</CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/012/page06.html b/docs/tutorials/012/page06.html deleted file mode 100644 index f3f858d14c1..00000000000 --- a/docs/tutorials/012/page06.html +++ /dev/null @@ -1,33 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 012</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 012</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Passing classes through ACE_Message_Queue</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> -<P> -Once again, we come to the end of a tutorial. By creating a simple -specialization of ACE_Message_Block, we've been able to remove a lot -of complexity and erorr potential from our previous implementation. -<UL> -<LI><A HREF="Makefile">Makefile</A> -<LI><A HREF="message_queue.cpp">message_queue.cpp</A> -<LI><A HREF="data.h">data.h</A> -<LI><A HREF="task.h">task.h</A> -<LI><A HREF="task.cpp">task.cpp</A> -</UL> -<P> -<HR WIDTH="100%"> -<P> -<CENTER>[<A HREF="..">Tutorial Index</A>]</CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/012/task.cpp b/docs/tutorials/012/task.cpp deleted file mode 100644 index 5c7a382db16..00000000000 --- a/docs/tutorials/012/task.cpp +++ /dev/null @@ -1,144 +0,0 @@ - -// $Id$ - -#include "task.h" -#include "data.h" - -/* - Boring default constructor. Be sure our barrier_ is initialized in - case we get destructed before opened. -*/ -Task::Task (void) -: barrier_ (0) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Task ctor 0x%x\n", (void *) this)); -} - -/* - You'll see in the svc() method that when we get a shutdown request, - we always putq() it back into our message queue. The last thread in - the pool will do this also and result in there always being one - shutdown request left in the queue when we get here. Just to be - polite, we'll go ahead and get that message and release it. - - We also delete the barrier_ object we used to synch the svc() - methods. -*/ -Task::~Task (void) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Task dtor 0x%x\n", (void *) this)); - - ACE_Message_Block *message; - this->getq (message); - message->release (); - - delete barrier_; -} - -/* - The ACE_Barrier needs to know how many threads it will be working - for. For that reason, we have to put off it's construction until we - get here. We then pass the thread count through to our base class' - activate(). -*/ -int Task::open (int threads) -{ - barrier_ = new ACE_Barrier (threads); - return this->activate (THR_NEW_LWP, threads); -} - -/* - We don't really do anything here but I wanted to provide a message - in the output. -*/ -int Task::close (u_long flags) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Task close 0x%x\n", (void *) this)); - return inherited::close (flags); -} - -/* - Now the svc() method where everything interesting happens. -*/ -int Task::svc (void) -{ - /* - All of the threads will block here until the last thread - arrives. They will all then be free to begin doing work. - */ - this->barrier_->wait (); - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Task 0x%x starts in thread %u\n", (void *) this, ACE_Thread::self ())); - - // Where we getq() the message - ACE_Message_Block *message; - // What we really put into the queue is a Message_Block, so we'll - // cast the 'message' to 'message_block' after getting it. I'm - // going through some extra steps here just to be explicit - Message_Block * message_block; - // The baseclass of the work object we put into the queue. Notice - // that we can use this and not bother with the Work object at all. - Unit_Of_Work * unit_of_work; - - while (1) - { - // Get the message... - if (this->getq (message) == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "getq"), -1); - } - - // Is it a shutdown request? - if (message->msg_type () == ACE_Message_Block::MB_HANGUP) - { - // Send the shutdown to all of our pool peers - this->putq (message); - break; - } - - // Cast the pointer to our specialized Message_Block. We could - // have done this at the getq() call but I wanted to be explicit - // about what we're doing here - message_block = (Message_Block*)message; - - /* - Since we left alone the ACE_Data_Block used by the - Message_Block we have chosen to use it to send arbitrary data - as well. - */ - const char *cp = message_block->rd_ptr (); - // Don't forget to skip the NULL we inserted - message_block->rd_ptr (strlen (cp) + 1); - - /* - Get the Unit_Of_Work pointer out of our specialized - Message_Block. Since the methods of interest are virtual, we - don't have to know what kind of work we're to do. - */ - unit_of_work = message_block->data(); - - /* - Invoke a couple of method calls on the object we constructed. - */ - unit_of_work->who_am_i (); - unit_of_work->what_am_i (); - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Block 0x%x contains (%s)\n", (void *) message, cp)); - - /* - Pretend that the work takes a little time to process. This - prevents one thread from getting all of the action. In a real - system you wouldn't need to do this since the work really - would take time to complete. - */ - ACE_OS::sleep (ACE_Time_Value (0, 5000)); - - /* - Release the message block and allow the unit of work to also go - away. - */ - message->release (); - } - - return (0); -} diff --git a/docs/tutorials/012/task.h b/docs/tutorials/012/task.h deleted file mode 100644 index 52dcf022b3e..00000000000 --- a/docs/tutorials/012/task.h +++ /dev/null @@ -1,38 +0,0 @@ - -// $Id$ - -#ifndef TASK_H -#define TASK_H - -#include "ace/Task.h" - -/* - This is our basic thread-pool Task. We have a choice of pool size - on the open() and the usual svc() and close() methods. - - A new addition is the ACE_Barrier object. This will allow the - synchronization of our svc() methods so that they all start at the - "same" time. The normal case may allow one thread to start working - earlier than others. There's no real harm in it but you can get - better "work by thread" statistics if they start out together. -*/ -class Task : public ACE_Task < ACE_MT_SYNCH > -{ -public: - - typedef ACE_Task < ACE_MT_SYNCH > inherited; - - Task (void); - ~Task (void); - - int open (int threads = 1); - - int svc (void); - - int close (u_long flags = 0); - -protected: - ACE_Barrier * barrier_; -}; - -#endif diff --git a/docs/tutorials/013/Makefile b/docs/tutorials/013/Makefile deleted file mode 100644 index 9b6fc0b3633..00000000000 --- a/docs/tutorials/013/Makefile +++ /dev/null @@ -1,60 +0,0 @@ - -# $Id$ - -#---------------------------------------------------------------------------- -# Local macros -#---------------------------------------------------------------------------- - -BIN = message_queue - -FILES = task block work mld - -BUILD = $(VBIN) - -SRC = $(addsuffix .cpp,$(BIN)) -SRC += $(addsuffix .cpp,$(FILES)) - -HDR = *.h - -#---------------------------------------------------------------------------- -# Include macros and targets -#---------------------------------------------------------------------------- - -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 -#---------------------------------------------------------------------------- - -Indent : # - for i in $(SRC) $(HDR) ; do \ - indent -npsl -l80 -fca -fc1 -cli0 -cdb -ts2 -bl -bli0 < $$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/' \ - -e 's/ / /g' \ - > $$i~ ;\ - mv $$i~ $$i ;\ - done - -Depend : depend - perl ../007/fix.Makefile - -.depend : # - touch .depend - -#---------------------------------------------------------------------------- -# Dependencies -#---------------------------------------------------------------------------- - -include .depend diff --git a/docs/tutorials/013/block.cpp b/docs/tutorials/013/block.cpp deleted file mode 100644 index 5d997510244..00000000000 --- a/docs/tutorials/013/block.cpp +++ /dev/null @@ -1,98 +0,0 @@ - -// $Id$ - -#include "block.h" - -/* - Construct a Dat_Block to contain a unit of work. Note the careful - construction of the baseclass to set the block type and the locking - strategy. - */ -Data_Block::Data_Block (Unit_Of_Work * _data) -: inherited (0, ACE_Message_Block::MB_DATA, 0, 0, new Lock (), 0, 0) -,data_ (_data) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) 0x%x Data_Block ctor for 0x%x\n", (void *) this, (void *) data_)); -} - -/* - The Lock object created in the constructor is stored in the baseclass and - available through the locking_strategy() method. We can cast it's value to - our Lock object and invoke the destroy() to indicate that we want it to go - away when the lock is released. - */ -Data_Block::~Data_Block (void) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) 0x%x Data_Block dtor for 0x%x\n", (void *) this, (void *) data_)); - ((Lock *) locking_strategy ())->destroy (); - delete data_; -} - -/* - Return the data - */ -Unit_Of_Work *Data_Block::data (void) -{ - return this->data_; -} - -Data_Block:: Lock::Lock (void) -:destroy_ (0) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) 0x%x Lock ctor\n", (void *) this)); -} - -Data_Block:: Lock::~Lock (void) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) 0x%x Lock dtor\n", (void *) this)); -} - -/* - Set our destroy_ flag so that the next lock release will cause us to be - deleted. - */ -int Data_Block::Lock::destroy (void) -{ - ++destroy_; - return (0); -} - -/* - Mutexes have acquire() and release() methods. We've overridden the latter - so that when the object we're protecting goes away, we can make ourselves go - away after the lock is released. - */ -int Data_Block::Lock::release (void) -{ - int rval = inherited::release (); - if (destroy_) - { - delete this; - } - return rval; -} - -/* - Create an baseclass unit of work when we instantiate a hangup message. - */ -Message_Block::Message_Block (void) -:inherited (new Data_Block (new Unit_Of_Work ())) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) 0x%x Message_Block ctor for shutdown\n", (void *) this)); - this->msg_type (MB_HANGUP); -} - -/* - Store the unit of work in a Data_Block and initialize the baseclass with - that data. - */ -Message_Block::Message_Block (Unit_Of_Work * _data) -:inherited (new Data_Block (_data)) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) 0x%x Message_Block ctor for 0x%x\n", (void *) this, (void *) _data)); -} - -Message_Block::~Message_Block (void) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) 0x%x Message_Block dtor\n", (void *) this)); -} diff --git a/docs/tutorials/013/block.h b/docs/tutorials/013/block.h deleted file mode 100644 index 40a31bd1b07..00000000000 --- a/docs/tutorials/013/block.h +++ /dev/null @@ -1,84 +0,0 @@ - -// $Id$ - -#ifndef BLOCK_H -#define BLOCK_H - -#include "ace/Message_Block.h" -#include "ace/Synch.h" -#include "mld.h" -#include "work.h" - -/* - In this Tutorial, we derive from ACE_Data_Block for our special data. With - the possiblilty that our Task object may forward the unit of work on to - another thread pool, we have to make sure that the data object doesn't go - out of scope unexpectedly. An ACE_Message_Block will be deleted as soon as - it's release() method is called but the ACE_Data_Blocks it uses are - reference counted and only delete when the last reference release()es the - block. We use that trait to simply our object memory management. - */ -class Data_Block : public ACE_Data_Block -{ -public: - typedef ACE_Data_Block inherited; - - // Create a data block with a unit of work to be done - Data_Block (Unit_Of_Work * _data); - - ~Data_Block (void); - - // Returns the work pointer - Unit_Of_Work *data (void); - -protected: - Unit_Of_Work * data_; - MLD; // Our memory leak detector - - // The ACE_Data_Block allows us to choose a locking strategy - // for making the reference counting thread-safe. The - // ACE_Lock_Adaptor<> template adapts the interface of a - // number of lock objects so thatthe ACE_Message_Block will - // have an interface it can use. - class Lock : public ACE_Lock_Adapter < ACE_Mutex > - { -public: - typedef ACE_Lock_Adapter < ACE_Mutex > inherited; - - Lock (void); - ~Lock (void); - - // When the Data_Block is destroyed, the Message_Block is - // holding a lock with this object. If we were to destroy - // the Lock with the Data_Block, we would have a - // segfault. Instead, the Data_Block invokes destroy() to - // mark the object as un-needed so that when the - // Message_Block invokes release() to drop the lock, the - // Lock can delete itself. - int destroy (void); - int release (void); -protected: - int destroy_; - MLD; - }; -}; - -/* - This simple derivative of ACE_Message_Block will construct our Data_Block - object to contain a unit of work. - */ -class Message_Block : public ACE_Message_Block -{ -public: - typedef ACE_Message_Block inherited; - - Message_Block (void); - Message_Block (Unit_Of_Work * _data); - - ~Message_Block (void); - -protected: - MLD; -}; - -#endif diff --git a/docs/tutorials/013/message_queue.cpp b/docs/tutorials/013/message_queue.cpp deleted file mode 100644 index 5128cbbfac4..00000000000 --- a/docs/tutorials/013/message_queue.cpp +++ /dev/null @@ -1,88 +0,0 @@ - -// $Id$ - -#include "mld.h" -#include "task.h" -#include "work.h" -#include "block.h" - -int run_test (int iterations, int threads, int subtasks) -{ - // Create a task with some subtasks. Each Task is a thread - // pool of 'threads' size. If a task has a subtask, it will - // forward the unit of work to the subtask when finished. See - // task.{h|cpp} for more details. - Task *task = new Task (subtasks); - - if (task->open (threads) == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "open"), -1); - } - - // Give the threads a chance to get ready. -ACE_OS::sleep (ACE_Time_Value (1)); - - for (int i = 0; i < iterations; ++i) - { - // Create a custom message block that can contain our Work object - Message_Block *message = new Message_Block (new Work (i)); - - // Put the "unit of work" into the message queue - if (task->putq (message) == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "putq"), -1); - } - } - - // The default constructor of our custom message block will - // insert a message telling our task to shutdown. - Message_Block *message = new Message_Block (); - - // Put the shutdown request into the thread pool - if (task->putq (message) == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "putq"), -1); - } - - // Wait for the task to shut down. Any subtasks will also be - // waited for. - task->wait (); - - // Delete our Task to prevent a memory leak - delete task; - - // Ask our memory leak detector if things are OK - if (MLD_COUNTER != 0) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Memory Leak!\n")); - } - - return (0); -} - -int main (int argc, char *argv[]) -{ - // Number of Work objects to put into the Task pool - int iterations = argc > 1 ? atoi (argv[1]) : 4; - // Number of threads for each Task - int threads = argc > 2 ? atoi (argv[2]) : 2; - // Number of tasks to chain after the primary task - int subtasks = argc > 3 ? atoi (argv[3]) : 1; - - (void) run_test (iterations, threads, subtasks); - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Application exiting\n")); - - exit (0); -} -#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION) -template class ACE_Guard < ACE_Mutex >; -template class ACE_Lock_Adapter < ACE_Mutex >; -template class ACE_Atomic_Op < ACE_Mutex, int >; -#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA) -#pragma instantiate ACE_Guard<ACE_Mutex>; -#pragma instantiate ACE_Lock_Adapter<ACE_Mutex>; -#pragma instantiate ACE_Atomic_Op<ACE_Mutex, int>; -#endif /* - ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION - */ diff --git a/docs/tutorials/013/mld.cpp b/docs/tutorials/013/mld.cpp deleted file mode 100644 index 64ffdf1b144..00000000000 --- a/docs/tutorials/013/mld.cpp +++ /dev/null @@ -1,23 +0,0 @@ - -// $Id$ - -#include "mld.h" - -ACE_Atomic_Op < ACE_Mutex, int >mld::counter_ (0); - -// Increment the counter when a new mld is created... -mld::mld (void) -{ - ++counter_; -} - -// and decrement it when the object is destructed. -mld::~mld (void) -{ - --counter_; -} - -int mld::value (void) -{ - return counter_.value (); -} diff --git a/docs/tutorials/013/mld.h b/docs/tutorials/013/mld.h deleted file mode 100644 index a9ee1de02b4..00000000000 --- a/docs/tutorials/013/mld.h +++ /dev/null @@ -1,44 +0,0 @@ - -// $Id$ - -#ifndef MLD_H -#define MLD_H - -#include "ace/Synch.h" -#include "ace/Singleton.h" - -/* - This is a cheap memory leak detector. Each class I want to watch over - contains an mld object. The mld object's ctor increments a global counter - while the dtor decrements it. If the counter is non-zero when the program - is ready to exit then there may be a leak. - */ - -class mld -{ -public: - mld (void); - ~mld (void); - - static int value (void); - -protected: - static ACE_Atomic_Op < ACE_Mutex, int >counter_; -}; - -// ================================================ - -/* - Just drop 'MLD' anywhere in your class definition to get cheap memory leak - detection for your class. - */ -#define MLD mld mld_ - -/* - Use 'MLD_COUNTER' in main() to see if things are OK. - */ -#define MLD_COUNTER mld::value() - -// ================================================ - -#endif diff --git a/docs/tutorials/013/page01.html b/docs/tutorials/013/page01.html deleted file mode 100644 index 217a2f9bf1d..00000000000 --- a/docs/tutorials/013/page01.html +++ /dev/null @@ -1,41 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 013</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 013</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Multiple thread pools</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> -<P> -My intent with this tutorial was to derive from ACE_Data_Block instead -of ACE_Message_Block so that we could leverage the reference counting -nature of that object. -<P> -Along the way, I sort of got distracted... What I ended up with is a -poor excuse for ACE_Stream that implements a simple state machine. -<P> -The application is built around a thread pool where the pool's svc() -method takes work units from the message queue for processing. As -each unit is taken from the queue, the process() method is invoked to -do some work. The twist is that after processing the message, we -enqueue it into another thread pool to do more work. This continues -through a chain of thread pools until the last where the unit's fini() -method is called for finishing up any outstanding work. -<P> -The chain of thread pools is uni-directional using a singly-linked -list of Task derivatives. Each pool has the same number of tasks in -order to keep things simple. -<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/013/page02.html b/docs/tutorials/013/page02.html deleted file mode 100644 index 785b0c86b75..00000000000 --- a/docs/tutorials/013/page02.html +++ /dev/null @@ -1,112 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 013</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 013</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Multiple thread pools</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> -<P> -We'll go back to our tradition of looking at main() first. The only -change here from our "normal" thread pool is the ability to specify -the number of subtasks for the pool. (Each subtask is another thread -pool in the chain. I suppose I should have named that better...) -I've still got the custom Message_Block so that, at this level, we -don't even know about custom Data_Blocks. -<P> -<HR WIDTH="100%"> -<PRE> -#include "mld.h" -#include "task.h" -#include "work.h" -#include "block.h" - -int run_test (int iterations, int threads, int subtasks) -{ - // Create a task with some subtasks. Each Task is a thread - // pool of 'threads' size. If a task has a subtask, it will - // forward the unit of work to the subtask when finished. See - // task.{h|cpp} for more details. - Task * task = new Task(subtasks); - - if (task->open (threads) == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "open"), -1); - } - - // Give the threads a chance to get ready. - ACE_OS::sleep (ACE_Time_Value (1)); - - for (int i = 0; i < iterations; ++i) - { - // Create a custom message block that can contain our Work object - Message_Block *message = new Message_Block( new Work(i) ); - - // Put the "unit of work" into the message queue - if (task->putq (message) == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "putq"), -1); - } - } - - // The default constructor of our custom message block will - // insert a message telling our task to shutdown. - Message_Block *message = new Message_Block( ); - - // Put the shutdown request into the thread pool - if (task->putq (message) == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "putq"), -1); - } - - // Wait for the task to shut down. Any subtasks will also be - // waited for. - task->wait (); - - // Delete our Task to prevent a memory leak - delete task; - - // Ask our memory leak detector if things are OK - if( MLD_COUNTER->value() != 0 ) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Memory Leak!\n")); - } - - return (0); -} - -int main (int argc, char *argv[]) -{ - // Number of Work objects to put into the Task pool - int iterations = argc > 1 ? atoi (argv[1]) : 4; - // Number of threads for each Task - int threads = argc > 2 ? atoi (argv[2]) : 2; - // Number of tasks to chain after the primary task - int subtasks = argc > 3 ? atoi(argv[3]) : 1; - - (void) run_test (iterations, threads, subtasks); - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Application exiting\n")); - - exit (0); -} -</PRE> -<HR WIDTH="100%"> -<P> -Nothing really surprising here... Just remember that your total -number of threads is ( ( 1 + subtasks ) * threads ). You probably -don't want to get too carried away with that! -<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/013/page03.html b/docs/tutorials/013/page03.html deleted file mode 100644 index 6a3fdd798e8..00000000000 --- a/docs/tutorials/013/page03.html +++ /dev/null @@ -1,108 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 013</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 013</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Multiple thread pools</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> -<P> -I did eventually create that ACE_Data_Block derivative that I wanted. -My purpose in doing so was to use the reference-counting -that is provided by ACE_Data_Block and ACE_Message_Block interactions. - When you're working with an object in a single -thread, it's generally not so difficult to manage it's lifetime. -That is, it doesn't tend to go out of scope or get destroyed unless -you do it on purpose. -<P> -On the other hand, if you're passing data between several threads, it -is easy to loose track of who "owns" the data at any one time. All -too frequently, data will be deleted by one thread while another is -still using it. Reference counting can prevent that. The rule of -thumb is that you increment the reference count of the object when you -hand it off to a new thread. You then decrement the count when you're -done with the object and let the object delete itself when there are -no more references. -<P> -To prove that all of that works correctly in the tutorial, I've -created a cheap Memory Leak Detector object. All mld instances -reference a thread-safe counter that is incremented when the mld is -constructed and decremented when destructed. I then insert an mld -into each of my dynamically created objects. If I get to the end of -main() and the counter isn't zero then I either didn't delete enough -or I deleted too many times. -<P> -Simple, cheap, effective. -<P> -<HR WIDTH="100%"> -<PRE> -#include "ace/Synch.h" -#include "ace/Singleton.h" - -/* - This is a cheap memory leak detector. Each class I want to watch - over contains an mld object. The mld object's ctor increments a - global counter while the dtor decrements it. If the counter is - non-zero when the program is ready to exit then there may be a leak. -*/ - -class mld -{ -public: - mld(void); - ~mld(void); - - static int value(void); - -protected: - static ACE_Atomic_Op<ACE_Mutex,int> counter_; -}; - - -/* - Just drop 'MLD' anywhere in your class definition to get cheap - memory leak detection for your class. - */ -#define MLD mld mld_ - -/* - Use 'MLD_COUNTER' in main() to see if things are OK. -*/ -#define MLD_COUNTER mld::value() - -<HR WIDTH="50%"> -<i>In the cpp file we have this:</i> - -ACE_Atomic_Op<ACE_Mutex,int> mld::counter_(0); - -// Increment the counter when a new mld is created... -mld::mld(void) -{ - ++counter_; -} - -// and decrement it when the object is destructed. -mld::~mld(void) -{ - --counter_; -} - -int mld::value(void) -{ - return counter_.value(); -} - -</PRE> -<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/013/page04.html b/docs/tutorials/013/page04.html deleted file mode 100644 index 4d7b714a025..00000000000 --- a/docs/tutorials/013/page04.html +++ /dev/null @@ -1,131 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 013</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 013</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Multiple thread pools</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> -<P> -Let's look now at the changes to our ACE_Message_Block derivative and -the new ACE_Data_Block derivative. -<P> -The important thing to remember is that the data block (not the -message block) is reference counted. When you instantiate a new -ACE_Message_Block, it will create one or more ACE_Data_Block objects -to contain the data you need. Optionally, you can provide it with a -pointer to a data block. -<P> -When you finish with a message block, you should use the release() -method to make it go away. Do not ever <em>delete</em> an instance of -a message block! When you invoke release(), the message block will -invoke release() on the data block(s) it contains. If the block's -reference count goes to zero as a result then the block will <em>delete</em> -itself. -<P> -To increment the reference count of a data block, use the -duplicate() method of the message block (or blocks) to get a new -message block referencing the same data block. This is very efficient -since the actual data is not copied. -<P> -<HR WIDTH="100%"> -<PRE> -/* - In this Tutorial, we derive from ACE_Data_Block for our special - data. With the possiblilty that our Task object may forward the - unit of work on to another thread pool, we have to make sure that - the data object doesn't go out of scope unexpectedly. An - ACE_Message_Block will be deleted as soon as it's release() method - is called but the ACE_Data_Blocks it uses are reference counted and - only delete when the last reference release()es the block. We use - that trait to simply our object memory management. - */ -class Data_Block : public ACE_Data_Block -{ -public: - typedef ACE_Data_Block inherited; - - // Create a data block with a unit of work to be done - Data_Block( Unit_Of_Work * _data ); - - ~Data_Block(void); - - // Returns the work pointer - Unit_Of_Work * data(void); - -protected: - Unit_Of_Work * data_; - MLD; // Our memory leak detector - - // The ACE_Data_Block allows us to choose a locking strategy - // for making the reference counting thread-safe. The - // ACE_Lock_Adaptor<> template adapts the interface of a - // number of lock objects so that the ACE_Message_Block will - // have an interface it can use. - class Lock : public ACE_Lock_Adapter<ACE_Mutex> - { - public: - typedef ACE_Lock_Adapter<ACE_Mutex> inherited; - - Lock(void); - ~Lock(void); - - // When the Data_Block is destroyed, the Message_Block is - // holding a lock with this object. If we were to destroy - // the Lock with the Data_Block, we would have a - // segfault. Instead, the Data_Block invokes destroy() to - // mark the object as un-needed so that when the - // Message_Block invokes release() to drop the lock, the - // Lock can delete itself. - int destroy(void); - int release(void); - protected: - int destroy_; - MLD; - }; -}; - -/* - This simple derivative of ACE_Message_Block will construct our - Data_Block object to contain a unit of work. - */ -class Message_Block : public ACE_Message_Block -{ -public: - typedef ACE_Message_Block inherited; - - Message_Block( void ); - Message_Block( Unit_Of_Work * _data ); - - ~Message_Block( void ); - -protected: - MLD; -}; -</PRE> -<HR WIDTH="100%"> -<P> -One of the most difficult parts of this to get right was the Lock -object. I didn't even have it in the beginning but I soon realized -that the reference counts were getting weird. A little careful -reading of the comments and the source informed me that some sort of -locking is necessary to keep the counter sane. The simplest thing at -that point was to use the ACE_Lock_Adaptor<> to adapt ACE_Mutex -appropriately. The next trick was to ensure that the lock object was -destroyed at the proper time to prevent both memory leaks and core -dumps. The finaly product may be a little bit intimidating at first -but it's really quite simple once you understand the motivation. -<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/013/page05.html b/docs/tutorials/013/page05.html deleted file mode 100644 index c258bfcd56a..00000000000 --- a/docs/tutorials/013/page05.html +++ /dev/null @@ -1,149 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 013</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 013</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Multiple thread pools</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> -<P> -On this page we have the code for the Data_Block and Message_Block -objects. As you probably suspect from the header on the previous -page, the complicated part is in the construction and destruction of -the Data_Block. -<P> -<HR WIDTH="100%"> -<PRE> -#include "block.h" - -/* - Construct a Dat_Block to contain a unit of work. Note the careful - construction of the baseclass to set the block type and the locking - strategy. - <i>Also notice that we don't use the data area of the baseclass at - all. If we wanted to, we could have taken a second ctor parameter to - allow us the use of that space.</i> - */ -Data_Block::Data_Block( Unit_Of_Work * _data ) - : inherited(0,ACE_Message_Block::MB_DATA,0,0,new Lock(),0,0) - ,data_(_data) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) 0x%x Data_Block ctor for 0x%x\n", (void *) this, (void*)data_)); -} - -/* - The Lock object created in the constructor is stored in the - baseclass and available through the locking_strategy() method. We - can cast it's value to our Lock object and invoke the destroy() to - indicate that we want it to go away when the lock is released. - <i>In other tutorials I've gone to quite a bit of trouble to avoid - the kind of cast you see here. If I had stuck to that form it might - look something like this: - ACE_Lock * ls = this->locking_stragety(); - Lock * my_lock = (Lock*)ls; - my_lock->destroy();</i> - */ -Data_Block::~Data_Block(void) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) 0x%x Data_Block dtor for 0x%x\n", (void *) this, (void*)data_)); - ((Lock*)locking_strategy())->destroy(); - delete data_; -} - -/* - Return the data -*/ -Unit_Of_Work * Data_Block::data(void) -{ - return this->data_; -} - -Data_Block::Lock::Lock(void) - : destroy_(0) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) 0x%x Lock ctor\n", (void *) this )); -} - -Data_Block::Lock::~Lock(void) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) 0x%x Lock dtor\n", (void *) this )); -} - -/* - Set our destroy_ flag so that the next lock release will cause us to - be deleted. -*/ -int Data_Block::Lock::destroy(void) -{ - ++destroy_; - return(0); -} - -/* - Mutexes have acquire() and release() methods. We've overridden the - latter so that when the object we're protecting goes away, we can - make ourselves go away after the lock is released. -*/ -int Data_Block::Lock::release(void) -{ - int rval = inherited::release(); - if( destroy_ ) - { - delete this; - } - return rval; -} - -/* - Create an baseclass unit of work when we instantiate a hangup message. -*/ -Message_Block::Message_Block( void ) - : inherited( new Data_Block( new Unit_Of_Work() ) ) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) 0x%x Message_Block ctor for shutdown\n", (void *) this )); - this->msg_type( MB_HANGUP ); -} - -/* - Store the unit of work in a Data_Block and initialize the baseclass - with that data. -*/ -Message_Block::Message_Block( Unit_Of_Work * _data ) - : inherited( new Data_Block(_data) ) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) 0x%x Message_Block ctor for 0x%x\n", (void *) this, (void*)_data)); -} - -Message_Block::~Message_Block( void ) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) 0x%x Message_Block dtor\n", (void *) this )); -} -</PRE> -<HR WIDTH="100%"> -<P> -I hope that wasn't too confusing. The locking strategy can be a bit -daunting at times. The worst problem is dealing with the fact -that the lock is held while the object being guarded by the lock is -being destroyed. But the only object that has a reference to the -(dynamically created) lock object is the very thing being deleted. We -would be in a world of hurt if the lock's release() method had not -been created virtual! By simply overridding that method we can get -ourselves out of a nasty situation. -<P> -The rest of the code is pretty cut and dried. We could have had the -hangup indicator create a data block with a null unit of work but it's -more orthgonal for the thread pool if we always have a valid pointer. -<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/013/page06.html b/docs/tutorials/013/page06.html deleted file mode 100644 index 972d5755e19..00000000000 --- a/docs/tutorials/013/page06.html +++ /dev/null @@ -1,286 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 013</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 013</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Multiple thread pools</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> -<P> -Let's take a look now at the new Task object. This will obviously be -different from the Tasks we've created before but I think you'll be -surprised at how relatively simple it actually is. -<P> -Remember that the goal of this tutorial was to use the reference -counting abilities of the ACE_Data_Block. The only way to show that -effectively is to have a data block passed between different threads. -A thread pool isn't really going to do that so, instead, our new Task -can be part of a chain of tasks. In that way, each Task can pass the -data on to another and satisfy our need for moving the ACE_Data_Block -around. -If we've done the reference counting correctly then none of our tasks -will be trying to work with deleted data and we won't have any memory -leaks at the end. -<P> -There's not much to the header, so I've included it and the cpp file -on this one page. -<P> -<HR WIDTH="100%"> -<PRE> - -#include "ace/Task.h" -#include "mld.h" - -/* - This is much like the Task we've used in the past for implementing a - thread pool. This time, however, I've made the Task an element in a - singly-linked list. As the svc() method finishes the process() on a - unit of work, it will enqueue that unit of work to the next_ Task if - there is one. If the Task does not have a next_ Task, it will - invoke the unit of work object's fini() method after invoking process(). - */ -class Task : public ACE_Task < ACE_MT_SYNCH > -{ -public: - - typedef ACE_Task < ACE_MT_SYNCH > inherited; - - // Construct ourselves and an optional number of subtasks - // chained beyond us. - Task ( int sub_tasks = 0 ); - ~Task (void); - - // Open the Task with the proper thread-pool size - int open (int threads = 1 ); - - // Take Unit_Of_Work objects from the thread pool and invoke - // their process() and/or fini() as appropriate. - int svc (void); - - // Shut down the thread pool and it's associated subtasks - int close (u_long flags = 0); - - // Wait for the pool and subtasks to close - int wait(void); - -protected: - ACE_Barrier * barrier_; - Task * next_; - MLD; -}; - -<HR WIDTH="50%"> - -#include "task.h" -#include "block.h" -#include "work.h" - -/* - Construct the Task with zero or more subtasks. If subtasks are requested, - we assign our next_ pointer to the first of those and let it worry about - any remaining subtasks. - */ -Task::Task (int sub_tasks) -: barrier_ (0) - ,next_ (0) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Task ctor 0x%x\n", (void *) this)); - if (sub_tasks) - { - next_ = new Task (--sub_tasks); - } -} - -/* - Delete our barrier object and any subtasks we may have. - */ -Task::~Task (void) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Task dtor 0x%x\n", (void *) this)); - - delete barrier_; - delete next_; -} - -/* - Open our thread pool with the requested number of threads. If subtasks are - enabled, they inherit the thread-pool size. Make sure that the subtasks can - be opened before we open our own threadpool. - */ -int Task::open (int threads) -{ - if (next_) - { - if (next_->open (threads) == -1) - { - return -1; - } - } - - barrier_ = new ACE_Barrier (threads); - return this->activate (THR_NEW_LWP, threads); -} - -/* - Close ourselves and any subtasks. This just prints a message so that we can - assure ourselves things are cleaned up correctly. - */ -int Task::close (u_long flags) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Task close 0x%x\n", (void *) this)); - if (next_) - { - next_->close (flags); - } - - return (0); -} - -/* - Wait for all of the threads in our pool to exit and then wait for any - subtasks. When called from the front of the task chain, this won't return - until all thread pools in the chain have exited. - */ -int Task::wait (void) -{ - inherited::wait (); - if (next_) - { - next_->wait (); - } - return (0); -} - -/* - Like the thread-pools before, this is where all of the work is done. - */ -int Task::svc (void) -{ - // Wait for all threads to get this far before continuing. - this->barrier_->wait (); - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Task 0x%x starts in thread %u\n", (void *) this, ACE_Thread::self ())); - - // getq() wants an ACE_Message_Block so we'll start out with one - // of those. We could do some casting (or even auto-casting) to - // avoid the extra variable but I prefer to be clear about our actions. - ACE_Message_Block *message; - - // What we really put into the queue was our Message_Block. - // After we get the message from the queue, we'll cast it to this - // so that we know how to work on it. - Message_Block *message_block; - - // And, of course, our Message_Block contains our Data_Block - // instead of the typical ACE_Data_Block - Data_Block *data_block; - - // Even though we put Work objects into the queue, we take them - // out using the baseclass pointer. This allows us to create new - // derivatives without having to change this svc() method. - Unit_Of_Work *work; - - while (1) - { - // Get the ACE_Message_Block - if (this->getq (message) == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "getq"), -1); - } - - // "Convert" it to our Message_Block - message_block = (Message_Block *) message; - - // Get the ACE_Data_Block and "convert" to Data_Block in one step. - data_block = (Data_Block *) (message_block->data_block ()); - - // Get the unit of work from the data block - work = data_block->data (); - - // Show the object's instance value and "type name" - work->who_am_i (); - work->what_am_i (); - - // If there is a hangup we need to tell our pool-peers as - // well as any subtasks. - if (message_block->msg_type () == ACE_Message_Block::MB_HANGUP) - { - // duplicate()ing the message block will increment the - // reference counts on the data blocks. This allows us - // to safely release() the message block. The rule of - // thumb is that if you pass a message block to a new - // owner, duplicate() it. Then you can release() when - // you're done and not worry about memory leaks. - if (this->putq (message_block->duplicate ()) == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "putq"), -1); - } - - // If we have a subtask, duplicate() the message block - // again and pass it to that task's queue - if (next_ && next_->putq (message_block->duplicate ()) == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "putq"), -1); - } - - // We're now done with our copy of the block, so we can - // release it. Our peers/subtasks have their own message - // block to access the shared data blocks. - message_block->release (); - - break; - } - - // If this isn't a hangup/shutdown message then we tell the - // unit of work to process() for a while. - work->process (); - - if (next_) - { - // If we have subtasks, we pass the block on to them. Notice - // that I don't bother to duplicate() the block since I won't - // release it in this case. I could have invoked - // duplicate() in the puq() and then release() - // afterwards. Either is acceptable. - if (next_->putq (message_block) == -1) - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "putq"), -1); - } - else - { - // If we don't have subtasks then invoke fini() to tell - // the unit of work that we won't be invoking process() - // any more. Then release() the block. This release() - // would not change if we duplicate()ed in the above conditional - work->fini (); - message_block->release (); - } - - // Pretend that the work takes some time... - ACE_OS::sleep (ACE_Time_Value (0, 250)); - } - - return (0); -} -</PRE> -<HR WIDTH="100%"> -<P> -So you see... it wasn't really that much more complicated. We really -just have to remember to pass to <i>next_</i> when we finish working -on the data. If your Unit_Of_Work derivative is going to implement a -state machine be sure that you also implement a fini() method -<em>or</em> ensure that your chain of subtasks is large enough for all -possible states. -<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/013/page07.html b/docs/tutorials/013/page07.html deleted file mode 100644 index f29609074e4..00000000000 --- a/docs/tutorials/013/page07.html +++ /dev/null @@ -1,244 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 013</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 013</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Multiple thread pools</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> -<P> -I've been trying to justify the chain of tasks by talking about a -Work object that implements a state machine. The idea is that your -Work object has to perform a series of discrete steps to complete it's -function. Traditionally, all of those steps would take place in one -thread of execution. That thread would probably be one from a Task -thread pool. -<P> -Suppose, however, that some of those steps spend a lot of time waiting -for disk IO. You could find that all of your thread-pool threads -are just sitting there waiting for the disk. You might then be -tempted to increase the thread pool size to get more work through. -However, if some of the stages are memory intensive, you could run out -of memory if all of the workers get to that state at the same time. -<P> -One solution might be to have different thread pools for each state. -Each pool could have it's size tuned appropriately for the work that -would be done there. That's where the chain of Tasks comes in. - In this tutorial's implementation I've taken the -easy route and set all of the thread pools to the same size but a more -realistic solution would be to set each thread pool in the chain to a -specific size as needed by that state of operation. -<P> -There's not much to this header either so I've combined it with the -cpp file as with task. -<P> -<HR WIDTH="100%"> -<PRE> -#include "ace/Log_Msg.h" -#include "ace/Synch.h" -#include "mld.h" - -/* - Our specilized message queue and thread pool will know how to do "work" on - our Unit_Of_Work baseclass. - */ -class Unit_Of_Work -{ -public: - Unit_Of_Work (void); - - virtual ~ Unit_Of_Work (void); - - // Display the object instance value - void who_am_i (void); - - // The baseclass can override this to show it's "type name" - virtual void what_am_i (void); - - // This is where you do application level logic. It will be - // called once for each thread pool it passes through. It - // would typically implement a state machine and execute a - // different state on each call. - virtual int process (void); - - // This is called by the last Task in the series (see task.h) - // in case our process() didn't get through all of it's states. - virtual int fini (void); - -protected: - ACE_Atomic_Op < ACE_Mutex, int >state_; - MLD; -}; - -/* - A fairly trivial work derivative that implements an equally trivial state - machine in process() - */ -class Work : public Unit_Of_Work -{ -public: - Work (void); - - Work (int message); - - virtual ~ Work (void); - - void what_am_i (void); - - int process (void); - - int fini (void); - -protected: - int message_; - MLD; -}; - -<HR WIDTH="50%"> - -#include "work.h" - -/* - Initialize the state to zero - */ -Unit_Of_Work::Unit_Of_Work (void) -: state_ (0) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) 0x%x Unit_Of_Work ctor\n", (void *) this)); -} - -Unit_Of_Work::~Unit_Of_Work (void) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) 0x%x Unit_Of_Work dtor\n", (void *) this)); -} - -/* - Display our instance value - */ -void Unit_Of_Work::who_am_i (void) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) 0x%x Unit_Of_Work instance\n", (void *) this)); -} - -/* - Dispay our type name - */ -void Unit_Of_Work::what_am_i (void) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) 0x%x I am a Unit_Of_Work object\n", (void *) this)); -} - -/* - Return failure. You should always derive from Unit_Of_Work... - */ -int Unit_Of_Work::process (void) -{ - return -1; -} - -/* - ditto - */ -int Unit_Of_Work::fini (void) -{ - return -1; -} - -/* - Default constructor has no "message number" - */ -Work::Work (void) -:message_ (-1) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) 0x%x Work ctor\n", (void *) this)); -} - -/* - The useful constructor remembers which message it is and will tell you if - you ask. - */ -Work::Work (int message) -: message_ (message) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) 0x%x Work ctor for message %d\n", (void *) this, message_)); -} - -Work::~Work (void) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) 0x%x Work dtor\n", (void *) this)); -} - -/* - This objects type name is different from the baseclass - */ -void Work::what_am_i (void) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) 0x%x I am a Work object for message %d\n", (void *) this, message_)); -} - -/* - A very simple state machine that just walks through three stages. If it is - called more than that, it will tell you not to bother. - */ -int Work::process (void) -{ - switch (++state_) - { - case 1: - ACE_DEBUG ((LM_DEBUG, "(%P|%t) 0x%x Stage One\n", (void *) this)); - break; - case 2: - ACE_DEBUG ((LM_DEBUG, "(%P|%t) 0x%x Stage Two\n", (void *) this)); - break; - case 3: - ACE_DEBUG ((LM_DEBUG, "(%P|%t) 0x%x Stage Three\n", (void *) this)); - break; - default: - ACE_DEBUG ((LM_DEBUG, "(%P|%t) 0x%x No work to do in state %d\n", - (void *) this, state_.value ())); - break; - } - return (0); -} - -/* - If you don't have enough subtasks in the chain then the state machine won't - progress to the end. The fini() hook will allow us to recover from that by - executing the remaining states in the final task of the chain. - */ -int Work::fini (void) -{ - while (state_.value () < 3) - { - if (this->process () == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "process"), -1); - } - } - return (0); -} - -</PRE> - -<HR WIDTH="100%"> -<P> -And that is that. For a more complex machine that may want to "jump -states" you would have to set some "state information" (sorry, bad -choice of terminology again) so that process() could decide what to do -at each call. You might also modify Task::svc() so that it will -respect the return value of process() and do something useful with the -information. -<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/013/page08.html b/docs/tutorials/013/page08.html deleted file mode 100644 index ce8e9158922..00000000000 --- a/docs/tutorials/013/page08.html +++ /dev/null @@ -1,44 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 013</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 013</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Multiple thread pools</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> -<P> -And that's the end of another tutorial. This one is probably the most -complicated so far because I've introduced or expanded upon -a number of different -concepts. Namely: state machines, reference counting and task -chaining. I hope I didn't complicate things to the point where the -lesson got lost in the noise. As always, feel free to drop a note to -the ACE-Users mailing list if you feel that some of this could use a -little more explaination. - -<P> -<UL> -<LI><A HREF="Makefile">Makefile</A> -<LI><A HREF="block.cpp">block.cpp</A> -<LI><A HREF="block.h">block.h</A> -<LI><A HREF="message_queue.cpp">message_queue.cpp</A> -<LI><A HREF="mld.cpp">mld.cpp</A> -<LI><A HREF="mld.h">mld.h</A> -<LI><A HREF="task.cpp">task.cpp</A> -<LI><A HREF="task.h">task.h</A> -<LI><A HREF="work.cpp">work.cpp</A> -<LI><A HREF="work.h">work.h</A> -</UL> -<P> -<HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial Index</A>]</CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/013/task.cpp b/docs/tutorials/013/task.cpp deleted file mode 100644 index 6ea62ef7de7..00000000000 --- a/docs/tutorials/013/task.cpp +++ /dev/null @@ -1,193 +0,0 @@ - -// $Id$ - -#include "task.h" -#include "block.h" -#include "work.h" - -/* - Construct the Task with zero or more subtasks. If subtasks are requested, - we assign our next_ pointer to the first of those and let it worry about - any remaining subtasks. - */ -Task::Task (int sub_tasks) -: barrier_ (0) - ,next_ (0) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Task ctor 0x%x\n", (void *) this)); - if (sub_tasks) - { - next_ = new Task (--sub_tasks); - } -} - -/* - Delete our barrier object and any subtasks we may have. - */ -Task::~Task (void) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Task dtor 0x%x\n", (void *) this)); - - delete barrier_; - delete next_; -} - -/* - Open our thread pool with the requested number of threads. If subtasks are - enabled, they inherit the thread-pool size. Make sure that the subtasks can - be opened before we open our own threadpool. - */ -int Task::open (int threads) -{ - if (next_) - { - if (next_->open (threads) == -1) - { - return -1; - } - } - - barrier_ = new ACE_Barrier (threads); - return this->activate (THR_NEW_LWP, threads); -} - -/* - Close ourselves and any subtasks. This just prints a message so that we can - assure ourselves things are cleaned up correctly. - */ -int Task::close (u_long flags) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Task close 0x%x\n", (void *) this)); - if (next_) - { - next_->close (flags); - } - - return (0); -} - -/* - Wait for all of the threads in our pool to exit and then wait for any - subtasks. When called from the front of the task chain, this won't return - until all thread pools in the chain have exited. - */ -int Task::wait (void) -{ - inherited::wait (); - if (next_) - { - next_->wait (); - } - return (0); -} - -/* - Like the thread-pools before, this is where all of the work is done. - */ -int Task::svc (void) -{ - // Wait for all threads to get this far before continuing. - this->barrier_->wait (); - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Task 0x%x starts in thread %u\n", (void *) this, ACE_Thread::self ())); - - // getq() wants an ACE_Message_Block so we'll start out with one - // of those. We could do some casting (or even auto-casting) to - // avoid the extra variable but I prefer to be clear about our actions. - ACE_Message_Block *message; - - // What we really put into the queue was our Message_Block. - // After we get the message from the queue, we'll cast it to this - // so that we know how to work on it. - Message_Block *message_block; - - // And, of course, our Message_Block contains our Data_Block - // instead of the typical ACE_Data_Block - Data_Block *data_block; - - // Even though we put Work objects into the queue, we take them - // out using the baseclass pointer. This allows us to create new - // derivatives without having to change this svc() method. - Unit_Of_Work *work; - - while (1) - { - // Get the ACE_Message_Block - if (this->getq (message) == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "getq"), -1); - } - - // "Convert" it to our Message_Block - message_block = (Message_Block *) message; - - // Get the ACE_Data_Block and "convert" to Data_Block in one step. - data_block = (Data_Block *) (message_block->data_block ()); - - // Get the unit of work from the data block - work = data_block->data (); - - // Show the object's instance value and "type name" - work->who_am_i (); - work->what_am_i (); - - // If there is a hangup we need to tell our pool-peers as - // well as any subtasks. - if (message_block->msg_type () == ACE_Message_Block::MB_HANGUP) - { - // duplicate()ing the message block will increment the - // reference counts on the data blocks. This allows us - // to safely release() the message block. The rule of - // thumb is that if you pass a message block to a new - // owner, duplicate() it. Then you can release() when - // you're done and not worry about memory leaks. - if (this->putq (message_block->duplicate ()) == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "putq"), -1); - } - - // If we have a subtask, duplicate() the message block - // again and pass it to that task's queue - if (next_ && next_->putq (message_block->duplicate ()) == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "putq"), -1); - } - - // We're now done with our copy of the block, so we can - // release it. Our peers/subtasks have their own message - // block to access the shared data blocks. - message_block->release (); - - break; - } - - // If this isn't a hangup/shutdown message then we tell the - // unit of work to process() for a while. - work->process (); - - if (next_) - { - // If we have subtasks, we pass the block on to them. Notice - // that I don't bother to duplicate() the block since I won't - // release it in this case. I could have invoked - // duplicate() in the puq() and then release() - // afterwards. Either is acceptable. - if (next_->putq (message_block) == -1) - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "putq"), -1); - } - else - { - // If we don't have subtasks then invoke fini() to tell - // the unit of work that we won't be invoking process() - // any more. Then release() the block. This release() - // would not change if we duplicate()ed in the above conditional - work->fini (); - message_block->release (); - } - - // Pretend that the work takes some time... - ACE_OS::sleep (ACE_Time_Value (0, 250)); - } - - return (0); -} diff --git a/docs/tutorials/013/task.h b/docs/tutorials/013/task.h deleted file mode 100644 index 0c813641169..00000000000 --- a/docs/tutorials/013/task.h +++ /dev/null @@ -1,48 +0,0 @@ - -// $Id$ - -#ifndef TASK_H -#define TASK_H - -#include "ace/Task.h" -#include "mld.h" - -/* - This is much like the Task we've used in the past for implementing a thread - pool. This time, however, I've made the Task an element in a singly-linked - list. As the svc() method finishes the process() on a unit of work, it - will enqueue that unit of work to the next_ Task if there is one. If the - Task does not have a next_ Task, it will invoke the unit of work object's - fini() method after invoking process(). - */ -class Task : public ACE_Task < ACE_MT_SYNCH > -{ -public: - - typedef ACE_Task < ACE_MT_SYNCH > inherited; - - // Construct ourselves and an optional number of subtasks - // chained beyond us. - Task (int sub_tasks = 0); - ~Task (void); - - // Open the Task with the proper thread-pool size - int open (int threads = 1); - - // Take Unit_Of_Work objects from the thread pool and invoke - // their process() and/or fini() as appropriate. - int svc (void); - - // Shut down the thread pool and it's associated subtasks - int close (u_long flags = 0); - - // Wait for the pool and subtasks to close - int wait (void); - -protected: - ACE_Barrier * barrier_; - Task *next_; - MLD; -}; - -#endif diff --git a/docs/tutorials/013/work.cpp b/docs/tutorials/013/work.cpp deleted file mode 100644 index 332353052a3..00000000000 --- a/docs/tutorials/013/work.cpp +++ /dev/null @@ -1,124 +0,0 @@ - -// $Id$ - -#include "work.h" - -/* - Initialize the state to zero - */ -Unit_Of_Work::Unit_Of_Work (void) -: state_ (0) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) 0x%x Unit_Of_Work ctor\n", (void *) this)); -} - -Unit_Of_Work::~Unit_Of_Work (void) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) 0x%x Unit_Of_Work dtor\n", (void *) this)); -} - -/* - Display our instance value - */ -void Unit_Of_Work::who_am_i (void) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) 0x%x Unit_Of_Work instance\n", (void *) this)); -} - -/* - Dispay our type name - */ -void Unit_Of_Work::what_am_i (void) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) 0x%x I am a Unit_Of_Work object\n", (void *) this)); -} - -/* - Return failure. You should always derive from Unit_Of_Work... - */ -int Unit_Of_Work::process (void) -{ - return -1; -} - -/* - ditto - */ -int Unit_Of_Work::fini (void) -{ - return -1; -} - -/* - Default constructor has no "message number" - */ -Work::Work (void) -:message_ (-1) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) 0x%x Work ctor\n", (void *) this)); -} - -/* - The useful constructor remembers which message it is and will tell you if - you ask. - */ -Work::Work (int message) -: message_ (message) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) 0x%x Work ctor for message %d\n", (void *) this, message_)); -} - -Work::~Work (void) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) 0x%x Work dtor\n", (void *) this)); -} - -/* - This objects type name is different from the baseclass - */ -void Work::what_am_i (void) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) 0x%x I am a Work object for message %d\n", (void *) this, message_)); -} - -/* - A very simple state machine that just walks through three stages. If it is - called more than that, it will tell you not to bother. - */ -int Work::process (void) -{ - switch (++state_) - { - case 1: - ACE_DEBUG ((LM_DEBUG, "(%P|%t) 0x%x Stage One\n", (void *) this)); - break; - case 2: - ACE_DEBUG ((LM_DEBUG, "(%P|%t) 0x%x Stage Two\n", (void *) this)); - break; - case 3: - ACE_DEBUG ((LM_DEBUG, "(%P|%t) 0x%x Stage Three\n", (void *) this)); - break; - default: - ACE_DEBUG ((LM_DEBUG, "(%P|%t) 0x%x No work to do in state %d\n", - (void *) this, state_.value ())); - break; - } - return (0); -} - -/* - If you don't have enough subtasks in the chain then the state machine won't - progress to the end. The fini() hook will allow us to recover from that by - executing the remaining states in the final task of the chain. - */ -int Work::fini (void) -{ - while (state_.value () < 3) - { - if (this->process () == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "process"), -1); - } - } - return (0); -} diff --git a/docs/tutorials/013/work.h b/docs/tutorials/013/work.h deleted file mode 100644 index 26e10b96266..00000000000 --- a/docs/tutorials/013/work.h +++ /dev/null @@ -1,67 +0,0 @@ - -// $Id$ - -#ifndef WORK_H -#define WORK_H - -#include "ace/Log_Msg.h" -#include "ace/Synch.h" -#include "mld.h" - -/* - Our specilized message queue and thread pool will know how to do "work" on - our Unit_Of_Work baseclass. - */ -class Unit_Of_Work -{ -public: - Unit_Of_Work (void); - - virtual ~ Unit_Of_Work (void); - - // Display the object instance value - void who_am_i (void); - - // The baseclass can override this to show it's "type name" - virtual void what_am_i (void); - - // This is where you do application level logic. It will be - // called once for each thread pool it passes through. It - // would typically implement a state machine and execute a - // different state on each call. - virtual int process (void); - - // This is called by the last Task in the series (see task.h) - // in case our process() didn't get through all of it's states. - virtual int fini (void); - -protected: - ACE_Atomic_Op < ACE_Mutex, int >state_; - MLD; -}; - -/* - A fairly trivial work derivative that implements an equally trivial state - machine in process() - */ -class Work : public Unit_Of_Work -{ -public: - Work (void); - - Work (int message); - - virtual ~ Work (void); - - void what_am_i (void); - - int process (void); - - int fini (void); - -protected: - int message_; - MLD; -}; - -#endif diff --git a/docs/tutorials/014/EndTask.h b/docs/tutorials/014/EndTask.h deleted file mode 100644 index e4ab823f1f9..00000000000 --- a/docs/tutorials/014/EndTask.h +++ /dev/null @@ -1,80 +0,0 @@ - -// $Id$ - -// EndTask.h -// -// Tutorial regarding a way to use ACE_Stream. -// -// written by bob mcwhirter (bob@netwrench.com) -// -// - -#ifndef ENDTASK_H -#define ENDTASK_H - -#include "Task.h" - -// When you setup a Stream and push your modules on, -// there are two additional modules that go unseen -// by the user. -// -// The Stream pushes on a Stream_Head in front of -// your first module, and a Stream_Tail behind your -// last module. -// -// If your put() a message to the Stream Tail, it -// assumes you did so in error. This simple EndTask -// class allows you to push a message to it and just -// have it safely Go Away. -// -// All this Task does is release the Message_Block -// and return 0. It's a suitable black-hole. - - -class EndTask : public Task -{ - -public: - - typedef Task inherited; - - EndTask(const char *nameOfTask) : - inherited(nameOfTask, 0) { - - // when we get open()'d, it with 0 threads - // since there is actually no processing to do. - - cerr << __LINE__ << " " << __FILE__ << endl; - }; - - virtual int open(void *) - { - cerr << __LINE__ << " " << __FILE__ << endl; - return 0; - } - - virtual int open(void) - { - cerr << __LINE__ << " " << __FILE__ << endl; - return 0; - } - - virtual ~EndTask(void) { - }; - - virtual int put(ACE_Message_Block *message, - ACE_Time_Value *timeout) { - - cerr << __LINE__ << " " << __FILE__ << endl; - ACE_UNUSED_ARG(timeout); - - // we don't have anything to do, so - // release() the message. - ACE_DEBUG ((LM_DEBUG, "(%P|%t) %s EndTask::put() -- releasing Message_Block\n", this->nameOfTask())); - message->release(); - return 0; - }; - -}; - -#endif // ENDTASK_H diff --git a/docs/tutorials/014/Makefile b/docs/tutorials/014/Makefile deleted file mode 100644 index 5a8d8891382..00000000000 --- a/docs/tutorials/014/Makefile +++ /dev/null @@ -1,69 +0,0 @@ - -# $Id$ - -#---------------------------------------------------------------------------- -# Local macros -#---------------------------------------------------------------------------- - -BIN = stream - -FILES = Task - -BUILD = $(VBIN) - -SRC = $(addsuffix .cpp,$(BIN)) -SRC += $(addsuffix .cpp,$(FILES)) - -HDR = *.h - -#---------------------------------------------------------------------------- -# Include macros and targets -#---------------------------------------------------------------------------- - -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 -#---------------------------------------------------------------------------- - -HTML : # - ../combine *.html - -rename : # - for i in *.cxx ; do \ - n=`expr "$$i" : "\(.*\).cxx"` ;\ - mv $$i $$n.cpp ;\ - done - -Indent : # - for i in $(SRC) $(HDR) ; do \ - indent -npsl -l80 -fca -fc1 -cli0 -cdb -ts2 -bl -bli0 < $$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/' \ - -e 's/ / /g' \ - > $$i~ ;\ - mv $$i~ $$i ;\ - done - -Depend : depend - perl ../007/fix.Makefile - -.depend : # - touch .depend - -#---------------------------------------------------------------------------- -# Dependencies -#---------------------------------------------------------------------------- - -include .depend diff --git a/docs/tutorials/014/Task.cpp b/docs/tutorials/014/Task.cpp deleted file mode 100644 index 4dc77b6e03b..00000000000 --- a/docs/tutorials/014/Task.cpp +++ /dev/null @@ -1,211 +0,0 @@ - -// $Id$ - -// Task.cxx -// -// Tutorial regarding a way to use ACE_Stream. -// -// written by bob mcwhirter (bob@netwrench.com) -// -// - -#include <ace/Message_Block.h> - -#include "Task.h" - -Task::Task(const char * nameOfTask, - int numberOfThreads) - : d_numberOfThreads(numberOfThreads), - d_barrier(numberOfThreads) -{ - // Just initialize our name, number of threads, and barrier. - - ACE_OS::strcpy(d_nameOfTask, nameOfTask); -} - -Task::~Task(void) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) %s Task::~Task() -- once per Task\n", d_nameOfTask)); -} - -int Task::open(void *arg) -{ - ACE_UNUSED_ARG(arg); - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) %s Task::open() -- once per Task\n", d_nameOfTask)); - - // call ACE_Task::activate() to spawn the threads using - // our Task::svc() as the function to be run. - - // FMM -- Frequently Made Mistake -- - // - // If you specify the flag THR_DETACHED when activating the - // Task, you will get an assert() violation during close(), - // since the Task waits for all of its threads to rejoin. - // - - return this->activate(THR_NEW_LWP, - d_numberOfThreads); -} - -int Task::put(ACE_Message_Block *message, - ACE_Time_Value *timeout) -{ - // ACE_Stream uses the put() method of Tasks to send messages. - // This defaultly does nothing. Here we link our put() method - // directly to our putq() method, so that Messages put() to us - // will appear in the Message_Queue that is checked by the - // service threads. - - return this->putq(message, timeout); -} - -int Task::close(u_long flags) -{ - - // When the Stream closes the Module, the Module then close()'s the Task - // and passing a value of (1) as the flag. - - // When a service thread exits, it calls close() with a value that is not - // (1). - - // We use this fact to tell the difference between closing a service thread, - // and closing the main Task itself. - - if (flags == 1) { - - // The Module has asked to close the main Task. - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) %s Task::close() -- flags == 1 -- once per Task\n", d_nameOfTask)); - - // We create a Message_Block... - - ACE_Message_Block *hangupBlock = new ACE_Message_Block(); - - // And make it of the type MB_HANGUP. - - hangupBlock->msg_type(ACE_Message_Block::MB_HANGUP); - - // We then send this Block into the Message_Queue to be seen by the - // service threads. - - // Once again we duplicate() the Block as send it off... - - if (this->putq(hangupBlock->duplicate()) == -1) { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "Task::close() putq"), -1); - } - - // ..and we're free to release() our copy of it. - - hangupBlock->release(); - - // Now, all we have to do is wait() for the service threads to all - // exit. This is where using THR_DETACHED in the activate() method - // will come back to haunt you. - - // The Stream waits until this returns before attempting to remove - // the next Module/Task group in the Stream. This allows for an - // orderly shutting down of the Stream. - - return this->wait(); - - - } else { - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) %s Task::close() -- flags != 1 -- once per servicing thread\n", d_nameOfTask)); - - // This is where we can clean up any mess left over by each service thread. - // In this Task, there is nothing to do. - - } - - return 0; - -} - -int Task::svc(void) -{ - - // This is the function that our service threads run once they are spawned. - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) %s Task::svc() -- once per servicing thread\n", d_nameOfTask)); - - // First, we wait until all of our peer service threads have arrived - // at this point also. - - d_barrier.wait(); - - ACE_Message_Block *messageBlock; - - while (1) { - - // And now we loop almost infinitely. - - // getq() will block until a Message_Block is available to be read, - // or an error occurs. - - if ( this->getq(messageBlock, 0) == -1) { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "Task::svc() getq"), -1); - } - - if (messageBlock->msg_type() == ACE_Message_Block::MB_HANGUP) { - - // If the Message_Block is of type MB_HANGUP, then we're being asked - // to shut down nicely. - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) %s Task::svc() -- HANGUP block received\n", d_nameOfTask)); - - // So, we duplicate the Block, and put it back into the Message_Queue, - // in case there are some more peer service threads still running. - - if (this->putq(messageBlock->duplicate()) == -1) { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "Task::svc() putq"), -1); - } - - // We release our copy of the Block. - messageBlock->release(); - - // And we break out of the nearly infinitely loop, and - // head towards close() ourselves. - break; - } - - // If we're here, then we've received a Message_Block that was - // not informing us to quit, so we're assuming it's a valid - // meaningful Block. - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) %s Task::svc() -- Normal block received\n", d_nameOfTask)); - - // We grab the read-pointer from the Block, and display it through a DEBUG statement. - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) %s Task::svc() -- %s\n", d_nameOfTask, messageBlock->rd_ptr() )); - - // We pretend that this takes to time to process the Block. - // If you're on a fast machine, you might have to raise this - // value to actually witness different threads handling - // blocks for each Task. - - ACE_OS::sleep (ACE_Time_Value (0, 250)); - - // Since we're part of a Stream, we duplicate the Block, and - // send it on to the next Task. - - if (put_next(messageBlock->duplicate()) == -1) { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "Task::svc() put_next"), -1); - } - - // And then we release our copy of it. - - messageBlock->release(); - - } - - return 0; - -} - - -const char * Task::nameOfTask(void) const -{ - return d_nameOfTask; -} diff --git a/docs/tutorials/014/Task.h b/docs/tutorials/014/Task.h deleted file mode 100644 index e4797f49892..00000000000 --- a/docs/tutorials/014/Task.h +++ /dev/null @@ -1,68 +0,0 @@ - -// $Id$ - -// Task.h -// -// Tutorial regarding a way to use ACE_Stream. -// -// written by bob mcwhirter (bob@netwrench.com) -// -// - -#ifndef TASK_H -#define TASK_H - -#include <ace/Task.h> -#include <ace/Synch.h> - -// Always typedef when possible. - -typedef ACE_Task<ACE_MT_SYNCH> Task_Base; - -class Task : public Task_Base -{ - -public: - - typedef Task_Base inherited; - // This is just good form. - - Task(const char *nameOfTask, - int numberOfThreads); - // Initialize our Task with a name, - // and number of threads to spawn. - - virtual ~Task(void); - - virtual int open(void *arg); - // This is provided to prevent compiler complaints - // about hidden virtual functions. - - virtual int close(u_long flags); - // This closes down the Task and all service threads. - - virtual int put(ACE_Message_Block *message, - ACE_Time_Value *timeout); - // This is the interface that ACE_Stream uses to - // communicate with our Task. - - virtual int svc(void); - // This is the actual service loop each of the service - // threads iterates through. - - const char *nameOfTask(void) const; - // Returns the name of this Task. - -private: - - int d_numberOfThreads; - char d_nameOfTask[64]; - - ACE_Barrier d_barrier; - // Simple Barrier to make sure all of our service - // threads have entered their loop before accepting - // any messages. -}; - - -#endif // TASK_H diff --git a/docs/tutorials/014/page01.html b/docs/tutorials/014/page01.html deleted file mode 100644 index ac4a0ea6d65..00000000000 --- a/docs/tutorials/014/page01.html +++ /dev/null @@ -1,38 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="Bob McWhirter"> - <TITLE>ACE Tutorial 014</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 014</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>ACE_Stream Tutorial, Of Sorts</FONT></B></CENTER> - -<P> -<HR WIDTH="100%"> - -<p><b>ACE_Stream</b> is handy when you have several <b>ACE_Task</b> objects -that you would like to link together. - -<p>An intermediate class you we will deal with is the <b>ACE_Module</b>. - -<p>The basic plan is to wrap your <b>Task</b> into a <b>Module</b>, push -the <b>Module</b> onto the <b>Stream</b>. Do this for each <b>Task</b>, - and then inject <b>Message_Block</b>s into the <b>Stream</b>. - -<p>Each <b>Task</b> then processes the <b>Message_Block</b>, and forwards -it on to the next <b>Task</b> in the <b>Stream</b>. - -<p>If you are not already familiar with <b>Message_Block</b>s and <b>Message_Queue</b>s, -I highly suggest that you check out <A HREF="../#MQ">Tutorials 10-13</A>. - -<p>Streams can be used for both downstream and upstream movement of messages. Used -this way mirrors closely the way System V STREAMS work. But you don't have to use them -bidirectionally. In this tutorial, we only use one direction of the Stream. Down. - -<p>This tutorial is contributed by Bob McWhirter (bob@netwrench.com) -<P> -<P><HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial Index</A>] [<A HREF="page02.html">Continue This Tutorial</A>]</CENTER> diff --git a/docs/tutorials/014/page02.html b/docs/tutorials/014/page02.html deleted file mode 100644 index 9dd05c3a0b5..00000000000 --- a/docs/tutorials/014/page02.html +++ /dev/null @@ -1,91 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="Bob McWhirter"> - <TITLE>ACE Tutorial 014</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 014</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>ACE_Stream Tutorial, Of Sorts</FONT></B></CENTER> - -<P> -<HR WIDTH="100%"> -<P> -You find pretty soon that anytime you work with ACE_Task<> you - have to create a derivative. The Task.h header simply provides - that derivative with the overrides we'll need in our application. -<P> -<HR WIDTH="100%"><PRE> - -// $Id$ - -// Task.h -// -// Tutorial regarding a way to use ACE_Stream. -// -// written by bob mcwhirter (bob@netwrench.com) -// -// - -#ifndef TASK_H -#define TASK_H - -#include <ace/Task.h> -#include <ace/Synch.h> - -// Always typedef when possible. - -typedef ACE_Task<ACE_MT_SYNCH> Task_Base; - -class Task : public Task_Base -{ - -public: - - typedef Task_Base inherited; - // This is just good form. - - Task(const char *nameOfTask, - int numberOfThreads); - // Initialize our Task with a name, - // and number of threads to spawn. - - virtual ~Task(void); - - virtual int open(void *arg); - // This is provided to prevent compiler complaints - // about hidden virtual functions. - - virtual int close(u_long flags); - // This closes down the Task and all service threads. - - virtual int put(ACE_Message_Block *message, - ACE_Time_Value *timeout); - // This is the interface that ACE_Stream uses to - // communicate with our Task. - - virtual int svc(void); - // This is the actual service loop each of the service - // threads iterates through. - - const char *nameOfTask(void) const; - // Returns the name of this Task. - -private: - - int d_numberOfThreads; - char d_nameOfTask[64]; - - ACE_Barrier d_barrier; - // Simple Barrier to make sure all of our service - // threads have entered their loop before accepting - // any messages. -}; - - -#endif // TASK_H -</PRE> -<P><HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial Index</A>] [<A HREF="page03.html">Continue This Tutorial</A>]</CENTER> diff --git a/docs/tutorials/014/page03.html b/docs/tutorials/014/page03.html deleted file mode 100644 index a0edf26f328..00000000000 --- a/docs/tutorials/014/page03.html +++ /dev/null @@ -1,243 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="Bob McWhirter"> - <TITLE>ACE Tutorial 014</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 014</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>ACE_Stream Tutorial, Of Sorts</FONT></B></CENTER> - -<P> -<HR WIDTH="100%"> -<P> -Before we get to main() let's take a look at the Task implementation. - While we've overridden several methods, the real work is done in - the close() and svc() methods. -<P> -Notice how close() figures out if it is being called by the shutdown - of the ACE_Stream or by the exit of svc(). The magic here is - provided by the <i>flags</i> parameter. By handling the stream - shutdown in this way, we don't have to do anything strange in - svc(). We also don't end up with extra hangup messages in the - queue when the dust all settles down. -<P> -Like our other tutorials, svc() looks for a hangup and processes data. -<P> -<HR WIDTH="100%"><PRE> - -// $Id$ - -// Task.cxx -// -// Tutorial regarding a way to use ACE_Stream. -// -// written by bob mcwhirter (bob@netwrench.com) -// -// - -#include <ace/Message_Block.h> - -#include "Task.h" - -Task::Task(const char * nameOfTask, - int numberOfThreads) - : d_numberOfThreads(numberOfThreads), - d_barrier(numberOfThreads) -{ - // Just initialize our name, number of threads, and barrier. - - ACE_OS::strcpy(d_nameOfTask, nameOfTask); -} - -Task::~Task(void) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) %s Task::~Task() -- once per Task\n", d_nameOfTask)); -} - -int Task::open(void *arg) -{ - ACE_UNUSED_ARG(arg); - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) %s Task::open() -- once per Task\n", d_nameOfTask)); - - // call ACE_Task::activate() to spawn the threads using - // our Task::svc() as the function to be run. - - // FMM -- Frequently Made Mistake -- - // - // If you specify the flag THR_DETACHED when activating the - // Task, you will get an assert() violation during close(), - // since the Task waits for all of its threads to rejoin. - // - - return this->activate(THR_NEW_LWP, - d_numberOfThreads); -} - -int Task::put(ACE_Message_Block *message, - ACE_Time_Value *timeout) -{ - // ACE_Stream uses the put() method of Tasks to send messages. - // This defaultly does nothing. Here we link our put() method - // directly to our putq() method, so that Messages put() to us - // will appear in the Message_Queue that is checked by the - // service threads. - - return this->putq(message, timeout); -} - -int Task::close(u_long flags) -{ - - // When the Stream closes the Module, the Module then close()'s the Task - // and passing a value of (1) as the flag. - - // When a service thread exits, it calls close() with a value that is not - // (1). - - // We use this fact to tell the difference between closing a service thread, - // and closing the main Task itself. - - if (flags == 1) { - - // The Module has asked to close the main Task. - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) %s Task::close() -- flags == 1 -- once per Task\n", d_nameOfTask)); - - // We create a Message_Block... - - ACE_Message_Block *hangupBlock = new ACE_Message_Block(); - - // And make it of the type MB_HANGUP. - - hangupBlock->msg_type(ACE_Message_Block::MB_HANGUP); - - // We then send this Block into the Message_Queue to be seen by the - // service threads. - - // Once again we duplicate() the Block as send it off... - - if (this->putq(hangupBlock->duplicate()) == -1) { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "Task::close() putq"), -1); - } - - // ..and we're free to release() our copy of it. - - hangupBlock->release(); - - // Now, all we have to do is wait() for the service threads to all - // exit. This is where using THR_DETACHED in the activate() method - // will come back to haunt you. - - // The Stream waits until this returns before attempting to remove - // the next Module/Task group in the Stream. This allows for an - // orderly shutting down of the Stream. - - return this->wait(); - - - } else { - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) %s Task::close() -- flags != 1 -- once per servicing thread\n", d_nameOfTask)); - - // This is where we can clean up any mess left over by each service thread. - // In this Task, there is nothing to do. - - } - - return 0; - -} - -int Task::svc(void) -{ - - // This is the function that our service threads run once they are spawned. - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) %s Task::svc() -- once per servicing thread\n", d_nameOfTask)); - - // First, we wait until all of our peer service threads have arrived - // at this point also. - - d_barrier.wait(); - - ACE_Message_Block *messageBlock; - - while (1) { - - // And now we loop almost infinitely. - - // getq() will block until a Message_Block is available to be read, - // or an error occurs. - - if ( this->getq(messageBlock, 0) == -1) { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "Task::svc() getq"), -1); - } - - if (messageBlock->msg_type() == ACE_Message_Block::MB_HANGUP) { - - // If the Message_Block is of type MB_HANGUP, then we're being asked - // to shut down nicely. - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) %s Task::svc() -- HANGUP block received\n", d_nameOfTask)); - - // So, we duplicate the Block, and put it back into the Message_Queue, - // in case there are some more peer service threads still running. - - if (this->putq(messageBlock->duplicate()) == -1) { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "Task::svc() putq"), -1); - } - - // We release our copy of the Block. - messageBlock->release(); - - // And we break out of the nearly infinitely loop, and - // head towards close() ourselves. - break; - } - - // If we're here, then we've received a Message_Block that was - // not informing us to quit, so we're assuming it's a valid - // meaningful Block. - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) %s Task::svc() -- Normal block received\n", d_nameOfTask)); - - // We grab the read-pointer from the Block, and display it through a DEBUG statement. - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) %s Task::svc() -- %s\n", d_nameOfTask, messageBlock->rd_ptr() )); - - // We pretend that this takes to time to process the Block. - // If you're on a fast machine, you might have to raise this - // value to actually witness different threads handling - // blocks for each Task. - - ACE_OS::sleep (ACE_Time_Value (0, 250)); - - // Since we're part of a Stream, we duplicate the Block, and - // send it on to the next Task. - - if (put_next(messageBlock->duplicate()) == -1) { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "Task::svc() put_next"), -1); - } - - // And then we release our copy of it. - - messageBlock->release(); - - } - - return 0; - -} - - -const char * Task::nameOfTask(void) const -{ - return d_nameOfTask; -} -</PRE> -<P><HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial Index</A>] [<A HREF="page04.html">Continue This Tutorial</A>]</CENTER> diff --git a/docs/tutorials/014/page04.html b/docs/tutorials/014/page04.html deleted file mode 100644 index c173178dbc2..00000000000 --- a/docs/tutorials/014/page04.html +++ /dev/null @@ -1,108 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="Bob McWhirter"> - <TITLE>ACE Tutorial 014</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 014</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>ACE_Stream Tutorial, Of Sorts</FONT></B></CENTER> - -<P> -<HR WIDTH="100%"> -<P> -As stated in the comments below, the default action of the task at the - stream tail is to treat any received data as an error. In our - implementation it will often happen that data gets through to - the tail. How, then, do we handle this without creating an - error condition? Simple: Create a custom Task for use as the - stream tail that doesn't consider it an error to receive data. -<P> -Read on... -<P> -<HR WIDTH="100%"><PRE> - -// $Id$ - -// EndTask.h -// -// Tutorial regarding a way to use ACE_Stream. -// -// written by bob mcwhirter (bob@netwrench.com) -// -// - -#ifndef ENDTASK_H -#define ENDTASK_H - -#include "Task.h" - -// When you setup a Stream and push your modules on, -// there are two additional modules that go unseen -// by the user. -// -// The Stream pushes on a Stream_Head in front of -// your first module, and a Stream_Tail behind your -// last module. -// -// If your put() a message to the Stream Tail, it -// assumes you did so in error. This simple EndTask -// class allows you to push a message to it and just -// have it safely Go Away. -// -// All this Task does is release the Message_Block -// and return 0. It's a suitable black-hole. - - -class EndTask : public Task -{ - -public: - - typedef Task inherited; - - EndTask(const char *nameOfTask) : - inherited(nameOfTask, 0) { - - // when we get open()'d, it with 0 threads - // since there is actually no processing to do. - - cerr << __LINE__ << " " << __FILE__ << endl; - }; - - virtual int open(void *) - { - cerr << __LINE__ << " " << __FILE__ << endl; - return 0; - } - - virtual int open(void) - { - cerr << __LINE__ << " " << __FILE__ << endl; - return 0; - } - - virtual ~EndTask(void) { - }; - - virtual int put(ACE_Message_Block *message, - ACE_Time_Value *timeout) { - - cerr << __LINE__ << " " << __FILE__ << endl; - ACE_UNUSED_ARG(timeout); - - // we don't have anything to do, so - // release() the message. - ACE_DEBUG ((LM_DEBUG, "(%P|%t) %s EndTask::put() -- releasing Message_Block\n", this->nameOfTask())); - message->release(); - return 0; - }; - -}; - -#endif // ENDTASK_H -</PRE> -<P><HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial Index</A>] [<A HREF="page05.html">Continue This Tutorial</A>]</CENTER> diff --git a/docs/tutorials/014/page05.html b/docs/tutorials/014/page05.html deleted file mode 100644 index c654dd69a83..00000000000 --- a/docs/tutorials/014/page05.html +++ /dev/null @@ -1,215 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="Bob McWhirter"> - <TITLE>ACE Tutorial 014</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 014</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>ACE_Stream Tutorial, Of Sorts</FONT></B></CENTER> - -<P> -<HR WIDTH="100%"> -<P> -Now we come to main(). In the previous task-chain tutorial - every thread pool had to have the same number of threads. This - time around, we leverage the construction method of ACE_Stream - and ACE_Module to customize the thread-pool size in each - ACE_Task of the stream. -<P> -Remember EndTask from the previous page? We create one here and push - it into the stream to take care of cleaning up the messages. - Technically, we could have replaced the default Tail task - created by the ACE framework but it seems to make more sense to - just push our "tail" onto the stream like the other tasks. The - caveat to this method is that you must be sure you don't push() - any other Modules behind the EndTask! -<P> -Once the stream of modules containing tasks is all setup then we can - put() some data into the stream for processing. The clever use - of Task::close() makes shutting downt the stream easier than - ever. No messing with hangup messages at the application level, - just close() when you're done! What could be simpler? -<P> -<HR WIDTH="100%"> -<PRE> - -// $Id$ - -// stream.cxx -// -// Tutorial regarding a way to use ACE_Stream. -// -// written by bob mcwhirter (bob@netwrench.com) -// -// - -#include "Task.h" -#include "EndTask.h" -// This is our specialized ACE_Task. - -#include <ace/Module.h> -#include <ace/Stream.h> -// These are the neccessary ACE headers. - - -typedef ACE_Module<ACE_MT_SYNCH> Module; -typedef ACE_Stream<ACE_MT_SYNCH> Stream; -// Just to avoid a lot of typing, typedefs -// are generally a good idea. - -int main(int argc, char *argv[]) -{ - cerr << __LINE__ << endl; - - int numberOfMessages = argc > 1 ? ACE_OS::atoi(argv[1]) : 3; - // unless otherwise specified, just send three messages - // down the stream. - - Stream theStream; - // the ACE_Stream itself. - - cerr << __LINE__ << endl; - - // Now, we instantiate 4 different Tasks. These do not - // need to be all the same class, but they do need to - // all derrive from the same flavor of ACE_Task. - // - // Also, we instantiate a fifth end-cap Task to clean - // up Message_Blocks as they reach the end. - - Task *taskOne; - Task *taskTwo; - Task *taskThree; - Task *taskFour; - Task *taskEnd; - - // Out Task's take two arguments: a name, and the number - // of threads to dedicate to the task. - - taskOne = new Task("Task No. 1", 1); - taskTwo = new Task("Task No. 2", 3); - taskThree = new Task("Task No. 3", 7); - taskFour = new Task("Task No. 4", 1); - - // Our EndTask only takes 1 argument, as it actually - // doesn't spawn any threads for processing. - - taskEnd = new EndTask("End Task"); - - Module *moduleOne; - Module *moduleTwo; - Module *moduleThree; - Module *moduleFour; - Module *moduleEnd; - - // ACE_Stream accepts ACE_Modules, which are simply a pair of - // ACE_Tasks. One is dedicated for writing, while the other - // is dedicated to reading. Think of the writing side as - // downstream, and the reading side as upstream. - // - // We're only working with a unidirection Stream today, - // so we'll only actually install a Task into the write - // side of the module, effectively downstream. - - cerr << __LINE__ << endl; - moduleOne = new Module("Module No. 1", taskOne); - moduleTwo = new Module("Module No. 2", taskTwo); - moduleThree = new Module("Module No. 3", taskThree); - moduleFour = new Module("Module No. 4", taskFour); - moduleEnd = new Module("Module End", taskEnd); - - cerr << __LINE__ << endl; - // Now we push the Modules onto the Stream. - // Pushing adds the module to the head, or - // otherwise prepends it to whatever modules - // are already installed. - - // So, you need to push() the modules on -backwards- - // from our viewpoint. - - if (theStream.push(moduleEnd) == -1) { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "push"), -1); - } - - cerr << __LINE__ << endl; - if (theStream.push(moduleFour) == -1) { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "push"), -1); - } - - // As we push a Module onto the Stream, it gets opened. - // When a Module open()s, it opens the Tasks that it contains. - // - // Since we cannot provide an argument to this embedded - // call to open(), we supplied specified the number of - // threads in the constructor of our Tasks. - - if (theStream.push(moduleThree) == -1) { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "push"), -1); - } - - if (theStream.push(moduleTwo) == -1) { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "push"), -1); - } - - if (theStream.push(moduleOne) == -1) { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "push"), -1); - } - - cerr << __LINE__ << endl; - // Now that the Modules are open, the Tasks threads should - // be launching and entering their svc() loop, so we send - // some messages down the Stream. - - int sent = 1; - - ACE_Message_Block *message; - - while (sent <= numberOfMessages) { - - // First, create ourselves a Message_Block. - // see Tutorials 10-13 for more information - // about Message_Blocks and Message_Queues. - - message = new ACE_Message_Block(128); - - // Now, we grab the write-pointer from the Block, - // and sprintf() our text into it. - - ACE_OS::sprintf(message->wr_ptr(), "Message No. %d", sent); - - // All we have to do now is drop the Message_Block - // into the Stream. - - // It is always a good idea to duplicate() a Message_Block - // when you put it into any Message_Queue, as then - // you can always be allowed to release() your copy - // without worry. - - if (theStream.put(message->duplicate(), 0) == -1) { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "put"), -1); - } - - message->release(); - ++sent; - } - - // Now that we've sent our Message_Blocks, close down - // the Stream. - // - // The Stream will automagically delete the Modules and - // the contained Tasks. We don't have to do that. - // - // This call will block (due to the way we've written our - // Task class) until all Message_Blocks have cleared the - // entire Stream, and all associated threads have exited. - - theStream.close(); - - return 0; -} -</PRE> -<P><HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial Index</A>] [<A HREF="page06.html">Continue This Tutorial</A>]</CENTER> diff --git a/docs/tutorials/014/page06.html b/docs/tutorials/014/page06.html deleted file mode 100644 index 01e5fef889c..00000000000 --- a/docs/tutorials/014/page06.html +++ /dev/null @@ -1,28 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="Bob McWhirter"> - <TITLE>ACE Tutorial 014</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 014</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>ACE_Stream Tutorial, Of Sorts</FONT></B></CENTER> - -<P> -<HR WIDTH="100%"> - -Ok, so that's the Stream tutorial. As you can see, it's much simpler - than the task-chain developed last time but at the same time it - is also much more extensible. - -<UL> -<LI><A HREF="Makefile">Makefile</A> -<LI><A HREF="Task.h">Task.h</A> -<LI><A HREF="Task.cpp">Task.cpp</A> -<LI><A HREF="EndTask.h">EndTask.h</A> -<LI><A HREF="stream.cpp">stream.cpp</A> -</UL> -<P><HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial Index</A>] </CENTER> diff --git a/docs/tutorials/014/stream.cpp b/docs/tutorials/014/stream.cpp deleted file mode 100644 index 4925bd5cf10..00000000000 --- a/docs/tutorials/014/stream.cpp +++ /dev/null @@ -1,175 +0,0 @@ - -// $Id$ - -// stream.cxx -// -// Tutorial regarding a way to use ACE_Stream. -// -// written by bob mcwhirter (bob@netwrench.com) -// -// - -#include "Task.h" -#include "EndTask.h" -// This is our specialized ACE_Task. - -#include <ace/Module.h> -#include <ace/Stream.h> -// These are the neccessary ACE headers. - - -typedef ACE_Module<ACE_MT_SYNCH> Module; -typedef ACE_Stream<ACE_MT_SYNCH> Stream; -// Just to avoid a lot of typing, typedefs -// are generally a good idea. - -int main(int argc, char *argv[]) -{ - cerr << __LINE__ << endl; - - int numberOfMessages = argc > 1 ? ACE_OS::atoi(argv[1]) : 3; - // unless otherwise specified, just send three messages - // down the stream. - - Stream theStream; - // the ACE_Stream itself. - - cerr << __LINE__ << endl; - - // Now, we instantiate 4 different Tasks. These do not - // need to be all the same class, but they do need to - // all derrive from the same flavor of ACE_Task. - // - // Also, we instantiate a fifth end-cap Task to clean - // up Message_Blocks as they reach the end. - - Task *taskOne; - Task *taskTwo; - Task *taskThree; - Task *taskFour; - Task *taskEnd; - - // Out Task's take two arguments: a name, and the number - // of threads to dedicate to the task. - - taskOne = new Task("Task No. 1", 1); - taskTwo = new Task("Task No. 2", 3); - taskThree = new Task("Task No. 3", 7); - taskFour = new Task("Task No. 4", 1); - - // Our EndTask only takes 1 argument, as it actually - // doesn't spawn any threads for processing. - - taskEnd = new EndTask("End Task"); - - Module *moduleOne; - Module *moduleTwo; - Module *moduleThree; - Module *moduleFour; - Module *moduleEnd; - - // ACE_Stream accepts ACE_Modules, which are simply a pair of - // ACE_Tasks. One is dedicated for writing, while the other - // is dedicated to reading. Think of the writing side as - // downstream, and the reading side as upstream. - // - // We're only working with a unidirection Stream today, - // so we'll only actually install a Task into the write - // side of the module, effectively downstream. - - cerr << __LINE__ << endl; - moduleOne = new Module("Module No. 1", taskOne); - moduleTwo = new Module("Module No. 2", taskTwo); - moduleThree = new Module("Module No. 3", taskThree); - moduleFour = new Module("Module No. 4", taskFour); - moduleEnd = new Module("Module End", taskEnd); - - cerr << __LINE__ << endl; - // Now we push the Modules onto the Stream. - // Pushing adds the module to the head, or - // otherwise prepends it to whatever modules - // are already installed. - - // So, you need to push() the modules on -backwards- - // from our viewpoint. - - if (theStream.push(moduleEnd) == -1) { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "push"), -1); - } - - cerr << __LINE__ << endl; - if (theStream.push(moduleFour) == -1) { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "push"), -1); - } - - // As we push a Module onto the Stream, it gets opened. - // When a Module open()s, it opens the Tasks that it contains. - // - // Since we cannot provide an argument to this embedded - // call to open(), we supplied specified the number of - // threads in the constructor of our Tasks. - - if (theStream.push(moduleThree) == -1) { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "push"), -1); - } - - if (theStream.push(moduleTwo) == -1) { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "push"), -1); - } - - if (theStream.push(moduleOne) == -1) { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "push"), -1); - } - - cerr << __LINE__ << endl; - // Now that the Modules are open, the Tasks threads should - // be launching and entering their svc() loop, so we send - // some messages down the Stream. - - int sent = 1; - - ACE_Message_Block *message; - - while (sent <= numberOfMessages) { - - // First, create ourselves a Message_Block. - // see Tutorials 10-13 for more information - // about Message_Blocks and Message_Queues. - - message = new ACE_Message_Block(128); - - // Now, we grab the write-pointer from the Block, - // and sprintf() our text into it. - - ACE_OS::sprintf(message->wr_ptr(), "Message No. %d", sent); - - // All we have to do now is drop the Message_Block - // into the Stream. - - // It is always a good idea to duplicate() a Message_Block - // when you put it into any Message_Queue, as then - // you can always be allowed to release() your copy - // without worry. - - if (theStream.put(message->duplicate(), 0) == -1) { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "put"), -1); - } - - message->release(); - ++sent; - } - - // Now that we've sent our Message_Blocks, close down - // the Stream. - // - // The Stream will automagically delete the Modules and - // the contained Tasks. We don't have to do that. - // - // This call will block (due to the way we've written our - // Task class) until all Message_Blocks have cleared the - // entire Stream, and all associated threads have exited. - - theStream.close(); - - return 0; -} diff --git a/docs/tutorials/index.html b/docs/tutorials/index.html deleted file mode 100644 index 1ba3fbcc63a..00000000000 --- a/docs/tutorials/index.html +++ /dev/null @@ -1,106 +0,0 @@ -<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"> - <TITLE>Online ACE Tutorials</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<HR> -<H3> -Online ACE Tutorials</H3> - -The following online tutorials are designed to help get you started -with ACE. The original audience for these tutorials was the <A -HREF="http://www.lads.com">Automated Design Systems</A> (ADS) IPC -team, lead by <A HREF="mailto:jcej@lads.com">James Johnson</A>. Since -then, the scope has been changed to include anyone who wants to learn -about the ACE framework. Hopefully, even experienced ACE programmers -will find something new here. With a framework as encompassing as ACE, -it is easy to become an expert in one area and know little or nothing -about others. <P> - -<FONT size=-1>Before you try compiling Tutorial 2 (and beyond) you -might want to read these comments about <A HREF="templates.html">C++ -templates</A></font> <P> - -<P><HR WIDTH="50%" align=left><P> -<H4> -Your basic Client/Server hookup</H4> - -<OL> -<LI> -<A HREF="001/page01.html">A -Simple Server</A></LI> - -<LI> -<A HREF="002/page01.html">A -Simpler Server</A></LI> - -<LI> -<A HREF="003/page01.html">Finally, -a Client</A></LI> - -<LI> -<A HREF="004/page01.html">A -much <I>cooler</I> client</A></LI> -</OL> - -<P><HR WIDTH="50%" align=left><P> -<H4> -A word about concurrency</H4> - -<OL> -<LI> -<A HREF="005/page01.html">No -threads, nothing fancy, just do the work!</A></LI> - -<LI> -<A HREF="006/page01.html">I'd -like to dedicate... a thread to each connection.</A></LI> - -<LI> -<A HREF="007/page01.html">Let's -pool our resources: a fixed-size pool of threads.</A></LI> -</OL> - -<P><HR WIDTH="50%" align=left><P> -<H4> -Finding servers on your network</H4> - -<OL> -<LI> -<A HREF="008/page01.html">Calling -all servers!</A></LI> - -<LI> -<A HREF="009/page01.html">Discriminating tastes...</A></LI> -</OL> - -<P><HR WIDTH="50%" align=left><P> - -<H4> -A word about ACE_Message_Queue</H4> - -<OL> -<LI> -<A HREF="010/page01.html">Puttin' data</A></LI> -<LI> -<A HREF="011/page01.html">What about non-trivial data?</A></LI> -<LI> -<A HREF="012/page01.html">Puttin' pointers</A></LI> -<LI> -<A HREF="013/page01.html">Task chains and state machines</A></LI> -</OL> -<HR> - -<P>Back to the <A -HREF="http://www.cs.wustl.edu/~schmidt/ACE_wrappers/docs/ACE-tutorials.html">ACE -tutorials</A> page. - -<P> -<!--#include virtual="/~schmidt/cgi-sig.html" --> -</BODY> -</HTML> - diff --git a/docs/tutorials/linify b/docs/tutorials/linify deleted file mode 100755 index f44747f5269..00000000000 --- a/docs/tutorials/linify +++ /dev/null @@ -1,52 +0,0 @@ -#!/usr/local/bin/perl - -while( $#ARGV > -1 ) { - - print "$ARGV[0]\n"; - - $source = "$ARGV[0]"; - - if( $source =~ /~$/ ) { - $dest = "$`"; - } else { - rename("$source","$source"."~") || die "Cannot rename ($source)"; - $dest = "$source"; - $source .= "~"; - } - - open(INPUT,"<$source") || die "Cannot open ($source)"; - open(OUTPUT,">$dest") || die "Cannot open ($dest)"; - - $n = 1; - - $prestrip = 0; - while( <INPUT> ) { - chomp; - - if( ! $prestrip && /^[0-9]+\.\t/ ) { - $prestrip = 1; - $_ = $'; - } elsif( $prestrip ) { - if( /^[0-9]+\.\t/ ) { - $_ = $'; - } else { - s/^\t//; - } - } - - if( /^\s*$/ || /^\s*({|})\s*;?\s*$/ || /^\s*\/\// - || /^\s*private\s*:/ || /^\s*protected\s*:/ || /^\s*public\s*:/ - || /^\s*}?\s*else\s*{?\s*:/ - ) { - print OUTPUT "\t$_\n"; - } else { - print OUTPUT "$n.\t$_\n"; - ++$n; - } - } - - close(INPUT); - close(OUTPUT); - - shift(@ARGV); -} diff --git a/docs/tutorials/new-tutorials.html b/docs/tutorials/new-tutorials.html deleted file mode 100644 index a886f6f0094..00000000000 --- a/docs/tutorials/new-tutorials.html +++ /dev/null @@ -1,80 +0,0 @@ -<TITLE>ACE Beginners' Guide</TITLE> -<BODY text = "#000000" link="#000fff" vlink="#ff0f0f" bgcolor="#ffffff"> - -<HR><P> -<H3>Developing New Tutorials</H3> - -Here are some general guidelines for creating new ACE tutorials: <P> - -<hr width=50% align=left> -<H4>Choose a Topic You Know Very Well (or are just learning)</h4> - - This isn't really a conflict... -<P> - If you know a topic very well, you're likely to know what is most - important to the novice and what can be left until later. If you're - just learning a topic, then you know what questions you have that - must be answered before you can continue. -<P> -<hr width=50% align=left> -<H4> Keep It Simple</H4> -<P> - Don't try to use a lot of really cool ACE features along the way. Stick - to the basic stuff and show that. Try to use a minimum of ACE objects - that are not the direct target of the tutorial. -<P> - (For instance, don't get all caught up in ACE_Singleton<> if you're - trying to show how to use an ACE_Reactor.) -<P> - If you want to show something really cool that happens to depend on - another ACE feature, do a tutorial on that other feature first! I've - found that folks will tend to get stuck on *anything* they don't - understand even if it isn't directly relevant to what you're trying - to teach. -<P> -<hr width=50% align=left> -<h4>Document the Heck Out of It!</H4> -<P> - There's no such thing as too much documentation. Don't worry about - repeating yourself along the way. Assume that the reader knows nothing - at all about the topic at hand and explain even the parts that you feel - are painfully obvious. -<P> - If you feel that sticking a bunch of comments in the code makes it harder - to read then stick in a label and document at the end of the file or - something. Alternately, create both a well-documented version and a - sparsely-documented version. Then folks can choose between 'em. -<P> -<hr width=50% align=left> -<h4>Over-teach It</H4> -<P> - If there's a tutorial created for a topic that you feel strong in, - create another one anyway. Everybody tends to code a little differently. - Perhaps your tutorial style will "feel" better to some newcomers - than an existing tutorial. You won't hurt anybody's feelings if - you present the same material in a different way. -<P> -<hr width=50% align=left> -<h4>Leverage Existing Code</H4> -<P> - The ultimate form of code reuse :-) Seriously... grab one or more - of the existing ACE tests or examples. Then strip it down to the - bare bones & add heaps of comments. I don't think the software-police - will be coming after anyone for that! - -<P> If this thing takes off, I'll start to organize the tutorials into -groups. For now, lets concentrate on quantity & quality. -Organization can come later... <P> - -<HR><P> <H3> What about TAO?</H3> In the early stages, these tutorials -won't address The ACE ORB (<A -HREF="http://www.cs.wustl.edu/~schmidt">TAO</A>). However, if you -want to request a tutorial on some aspect of TAO or even create one -yourself, I'll be glad to integrate those into these tutorials. It's -rare when folks want to write documentation, so nothing will be -refused!<P> - -<HR><P> -Back to the <A -HREF="http://www.cs.wustl.edu/~schmidt/ACE_wrappers/docs/ACE-tutorials.html">ACE -tutorials</A> page. diff --git a/docs/tutorials/templates.html b/docs/tutorials/templates.html deleted file mode 100644 index 81294f489b0..00000000000 --- a/docs/tutorials/templates.html +++ /dev/null @@ -1,185 +0,0 @@ -<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"> -<html> - <head> - <title>About C++ Templates</title> - </head> - - <BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> -<center> - <h1>About C++ Templates</h1> -</center> - - - <hr> - -When you get to server.cpp in Tutorial 2 you'll see these lines at the bottom: -<P> -<UL> -<PRE> -#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION) -template class ACE_Acceptor <Logging_Handler, ACE_SOCK_ACCEPTOR>; -template class ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH>; -#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA) -#pragma instantiate ACE_Acceptor <Logging_Handler, ACE_SOCK_ACCEPTOR> -#pragma instantiate ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH> -#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */ -<font size=-1>Thanks to Krishna Padmasola for providing these.</font> -</PRE> -</UL> -<P> -What's that all about? -<P> -Well, if you've been doing ACE for more than about 30 seconds you will -have run into the joys and sorrows of C++ templates. They're really -great things that prevent the need for complex #define'd macros, -ensure type safety and do other really nifty things. One of the -problems, however, is that not all compilers can figure out what -templates you need. -<P> -Take the simple templated class: -<UL> -<PRE> -template <class DATATYPE> -class MyTemplate -{ -public: - MyTemplate(void) - { - } - - DATATYPE data(void) - { - return data_; - } - - void data( DATATYE _data ) - { - data_ = _data; - } - -protected: - - DATATYPE data_; -}; -</PRE> -</UL> -<P> -Now suppose you write the following code fragment: -<P> -<UL> -<PRE> -int main(int,char**) -{ - MyTemplate<int> itemp; - MyTemplate<char> ctemp; - - ... -} -</pre> -</ul> -<P> -Some compilers will take care of you and automatically generate the -equivalent classes: -<UL> -<pre> -class MyTemplate -{ -public: - MyTemplate(void) - { - } - - int data(void) - { - return data_; - } - - void data( int _data ) - { - data_ = _data; - } - -protected: - - int data_; -}; - -class MyTemplate -{ -public: - MyTemplate(void) - { - } - - char data(void) - { - return data_; - } - - void data( char _data ) - { - data_ = _data; - } - -protected: - - char data_; -}; -</pre> -</ul> -<P> -On the other hand, some compilers will complain loudly about undefined -symbols and all sorts of other things. When Clinton Carr compiled -server.cpp of Tutorial 2 on his RedHat 5.1 (gcc) system, for instance, -he was rewarded with these lovely errors: -<P> -<UL> -<PRE> -server.cpp:60: undefined reference to `ACE_Acceptor<Client_Handler, ACE_SOCK_Acceptor>::ACE_Acceptor(ACE_Reactor *)' -server.cpp:72: undefined reference to `ACE_Acceptor<Client_Handler, ACE_SOCK_Acceptor>::open(ACE_INET_Addr const &, ACE_Reactor *,int)' -server.cpp:73: undefined reference to `ACE_Acceptor<Client_Handler, ACE_SOCK_Acceptor>::~ACE_Acceptor(void)' -server.cpp:112: undefined reference to `ACE_Acceptor<Client_Handler, ACE_SOCK_Acceptor>::~ACE_Acceptor(void)' -</PRE> -</UL> -<P> -Figuring out the correct manual instantiations is usually an -interative and tedious process. On Linux, I generally use a version of gcc that -will do automatic instantiaion. "Normal" gcc with the Cygnus repo -patches does that as does egcs. Lately (9/98) I've been using egcs -1.1b with pretty good results. On our Digital Unix 4.0b system the -native compiler (CXX) has switches that will request it to also -automatically instantiate templates as needed. -<P> -The tradeoffs? -<P> -If you choose to do manual instantiation then your code will work just -about anywhere ACE will. For complex applications, it can take a -number of hours to get things right. -<P> -If you choose to let the compiler do instantiations for you then it -will perform the iterative process. That means that every compile -will be longer than without manual instantiations. -<P> -Compromise? -<P> -Yes, you can do that. You can manually instantiate some -templates and let the compiler get the rest. Some compilers will -generate output that you can then use to figure out the correct -templates. Gcc/egcs create .rpo files for each object. These files -contain mangled names that the compiler uses to figure out what to -instantiate. With c++filt and some patience, you can parse that stuff -to figure out what the compiler is instantiating for you. -<P> -My best advice is to get a compiler that will handle the -instantiations for you. When you have some free time on your hands, -take a look at it's intermediate files (if any) and start working on -manual instantiation. -<P> -For some more hints, take a look at <A HREF="../../ACE-INSTALL.html#g++">ACE-INSTALL</A> -<P> - <hr> - - - </body> -</html> -
\ No newline at end of file |