diff options
author | William R. Otte <wotte@dre.vanderbilt.edu> | 2006-07-24 15:50:30 +0000 |
---|---|---|
committer | William R. Otte <wotte@dre.vanderbilt.edu> | 2006-07-24 15:50:30 +0000 |
commit | c44379cc7d9c7aa113989237ab0f56db12aa5219 (patch) | |
tree | 66a84b20d47f2269d8bdc6e0323f338763424d3a /ACE/examples | |
parent | 3aff90f4a822fcf5d902bbfbcc9fa931d6191a8c (diff) | |
download | ATCD-c44379cc7d9c7aa113989237ab0f56db12aa5219.tar.gz |
Repo restructuring
Diffstat (limited to 'ACE/examples')
1002 files changed, 92336 insertions, 0 deletions
diff --git a/ACE/examples/APG/Active_Objects/.cvsignore b/ACE/examples/APG/Active_Objects/.cvsignore new file mode 100644 index 00000000000..2af94b7dd8c --- /dev/null +++ b/ACE/examples/APG/Active_Objects/.cvsignore @@ -0,0 +1,4 @@ +AO +AO +AO2 +AO2 diff --git a/ACE/examples/APG/Active_Objects/AO.cpp b/ACE/examples/APG/Active_Objects/AO.cpp new file mode 100644 index 00000000000..b84a017d590 --- /dev/null +++ b/ACE/examples/APG/Active_Objects/AO.cpp @@ -0,0 +1,186 @@ +// $Id$ + +#include "ace/config-lite.h" +#if defined (ACE_HAS_THREADS) + +#include "ace/OS_NS_unistd.h" +#include "ace/Activation_Queue.h" +#include "ace/Method_Request.h" +#include "ace/Task.h" +#include "ace/Future.h" +#include "ace/Auto_Ptr.h" +// Listing 1 code/ch15 +class HA_ControllerAgent +{ + // Proxy to the HA_Controller that is on the network. +public: + HA_ControllerAgent () + { + ACE_TRACE + (ACE_TEXT ("HA_ControllerAgent::HA_ControllerAgent")); + status_result_ = 1; + } + + int status_update (void) + { + ACE_TRACE (ACE_TEXT ("HA_ControllerAgent::status_update")); + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("Obtaining a status_update in %t ") + ACE_TEXT ("thread of control\n"))); + // Simulate time to send message and get status. + ACE_OS::sleep (2); + return next_result_id (); + } + +private: + int next_result_id (void) + { + ACE_TRACE (ACE_TEXT ("HA_ControllerAgent::next_cmd_id")); + return status_result_++; + } + + int status_result_; +}; +// Listing 1 +// Listing 2 code/ch15 +class StatusUpdate : public ACE_Method_Request +{ +public: + StatusUpdate (HA_ControllerAgent& controller, + ACE_Future<int>& returnVal) + : controller_(controller), returnVal_(returnVal) + { + ACE_TRACE (ACE_TEXT ("StatusUpdate::StatusUpdate")); + } + + virtual int call (void) + { + ACE_TRACE (ACE_TEXT ("StatusUpdate::call")); + + // status_update with the controller. + this->returnVal_.set (this->controller_.status_update ()); + return 0; + } + +private: + HA_ControllerAgent& controller_; + ACE_Future<int> returnVal_; +}; +// Listing 2 +// Listing 3 code/ch15 +class ExitMethod : public ACE_Method_Request +{ +public: + virtual int call (void) + { + // Cause exit. + return -1; + } +}; +// Listing 3 +// Listing 4 code/ch15 +class Scheduler : public ACE_Task_Base +{ +public: + Scheduler () + { + ACE_TRACE (ACE_TEXT ("Scheduler::Scheduler")); + this->activate (); + } + + virtual int svc (void) + { + ACE_TRACE (ACE_TEXT ("Scheduler::svc")); + + while (1) + { + // Dequeue the next method object + auto_ptr<ACE_Method_Request> + request (this->activation_queue_.dequeue ()); + + // Invoke the method request. + if (request->call () == -1) + break; + } + + return 0; + } + + int enqueue (ACE_Method_Request *request) + { + ACE_TRACE (ACE_TEXT ("Scheduler::enqueue")); + return this->activation_queue_.enqueue (request); + } + +private: + ACE_Activation_Queue activation_queue_; +}; +// Listing 4 +// Listing 5 code/ch15 +class HA_ControllerAgentProxy +{ + // This acts as a Proxy to the controller impl object. +public: + ACE_Future<int> status_update (void) + { + ACE_TRACE + (ACE_TEXT ("HA_ControllerAgentProxy::status_update")); + ACE_Future<int> result; + + // Create and enqueue a method request on the scheduler. + this->scheduler_.enqueue + (new StatusUpdate (this->controller_, result)); + + // Return Future to the client. + return result; + } + + void exit (void) + { + ACE_TRACE (ACE_TEXT ("HA_ControllerAgentProxy::exit")); + this->scheduler_.enqueue (new ExitMethod); + } + +private: + Scheduler scheduler_; + HA_ControllerAgent controller_; +}; +// Listing 5 +// Listing 6 code/ch15 +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + HA_ControllerAgentProxy controller; + ACE_Future<int> results[10]; + + for (int i = 0 ; i < 10; i++) + results[i] = controller.status_update (); + + ACE_OS::sleep (5); // Do other work. + + // Get results... + for (int j = 0; j < 10; j++) + { + int result = 0; + results[j].get (result); + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("New status_update %d\n"), result)); + } + + // Cause the status_updater threads to exit. + controller.exit (); + ACE_Thread_Manager::instance ()->wait (); + return 0; +} +// Listing 6 + +#else +#include "ace/OS_main.h" +#include "ace/OS_NS_stdio.h" + +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_OS::puts (ACE_TEXT ("This example requires threads.")); + return 0; +} + +#endif /* ACE_HAS_THREADS */ diff --git a/ACE/examples/APG/Active_Objects/AO2.cpp b/ACE/examples/APG/Active_Objects/AO2.cpp new file mode 100644 index 00000000000..04553c8e1b8 --- /dev/null +++ b/ACE/examples/APG/Active_Objects/AO2.cpp @@ -0,0 +1,196 @@ +// $Id$ + +#include "ace/config-lite.h" +#if defined (ACE_HAS_THREADS) + +#include "ace/OS_NS_unistd.h" +#include "ace/Activation_Queue.h" +#include "ace/Method_Request.h" +#include "ace/Task.h" +#include "ace/Future.h" +#include "ace/Auto_Ptr.h" + +class HA_ControllerAgent +{ + // Proxy to the HA_Controller that is on the network. +public: + HA_ControllerAgent () + { + ACE_TRACE + (ACE_TEXT ("HA_ControllerAgent::HA_ControllerAgent")); + status_result_ = 1; + } + + int status_update (void) + { + ACE_TRACE (ACE_TEXT ("HA_ControllerAgent::status_update")); + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("Obtaining a status_update in %t ") + ACE_TEXT ("thread of control\n"))); + // Simulate sending message to controller + // and getting status. + ACE_OS::sleep (2); + return next_result_id (); + } + +private: + int next_result_id (void) + { + ACE_TRACE (ACE_TEXT ("HA_ControllerAgent::next_cmd_id")); + return status_result_++; + } + + int status_result_; +}; + +class StatusUpdate : public ACE_Method_Request +{ +public: + StatusUpdate (HA_ControllerAgent& controller, + ACE_Future<int>& returnVal) + : controller_(controller), returnVal_(returnVal) + { + ACE_TRACE (ACE_TEXT ("StatusUpdate::StatusUpdate")); + } + + virtual int call (void) + { + ACE_TRACE (ACE_TEXT ("StatusUpdate::call")); + + // status_update with the controller. + this->returnVal_.set (this->controller_.status_update ()); + return 0; + } + +private: + HA_ControllerAgent& controller_; + ACE_Future<int> returnVal_; +}; + +class ExitMethod : public ACE_Method_Request +{ +public: + virtual int call (void) + { + // Cause exit. + return -1; + } +}; + +class Scheduler : public ACE_Task_Base +{ +public: + Scheduler () + { + ACE_TRACE (ACE_TEXT ("Scheduler::Scheduler")); + this->activate (); + } + + virtual int svc (void) + { + ACE_TRACE (ACE_TEXT ("Scheduler::svc")); + + while (1) + { + // Dequeue the next method object + auto_ptr<ACE_Method_Request> + request (this->activation_queue_.dequeue ()); + + // Invoke the method request. + if (request->call () == -1) + break; + } + + return 0; + } + + int enqueue (ACE_Method_Request *request) + { + ACE_TRACE (ACE_TEXT ("Scheduler::enqueue")); + return this->activation_queue_.enqueue (request); + } + +private: + ACE_Activation_Queue activation_queue_; +}; + +class HA_ControllerAgentProxy +{ + // This acts as a Proxy to the controller impl object. +public: + ACE_Future<int> status_update (void) + { + ACE_TRACE + (ACE_TEXT ("HA_ControllerAgentProxy::status_update")); + ACE_Future<int> result; + + // Create and enqueue a method request on the scheduler. + this->scheduler_.enqueue + (new StatusUpdate (this->controller_, result)); + + // Return Future to the client. + return result; + } + + void exit (void) + { + ACE_TRACE (ACE_TEXT ("HA_ControllerAgentProxy::exit")); + this->scheduler_.enqueue (new ExitMethod); + } + +private: + Scheduler scheduler_; + HA_ControllerAgent controller_; +}; + +// Listing 1 code/ch15 +class CompletionCallBack : public ACE_Future_Observer<int> +{ +public: + CompletionCallBack (HA_ControllerAgentProxy& proxy) + : proxy_(proxy) + { } + + virtual void update (const ACE_Future<int>& future) + { + int result = 0; + ((ACE_Future<int>)future).get (result); + ACE_DEBUG ((LM_INFO, + ACE_TEXT ("(%t) New Status %d\n"), result)); + if (result == 10) + this->proxy_.exit (); + } + +private: + HA_ControllerAgentProxy& proxy_; +}; +// Listing 1 +// Listing 2 code/ch15 +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + HA_ControllerAgentProxy controller; + ACE_Future<int> results[10]; + CompletionCallBack cb (controller); + + for (int i = 0 ; i < 10; i++) + { + results[i] = controller.status_update (); + results[i].attach (&cb); + } + + ACE_Thread_Manager::instance ()->wait (); + return 0; +} +// Listing 2 + +#else +#include "ace/OS_main.h" +#include "ace/OS_NS_stdio.h" + +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_OS::puts (ACE_TEXT ("This example requires threads.")); + return 0; +} + +#endif /* ACE_HAS_THREADS */ diff --git a/ACE/examples/APG/Active_Objects/Makefile.am b/ACE/examples/APG/Active_Objects/Makefile.am new file mode 100644 index 00000000000..4562743bc87 --- /dev/null +++ b/ACE/examples/APG/Active_Objects/Makefile.am @@ -0,0 +1,56 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +ACE_BUILDDIR = $(top_builddir) +ACE_ROOT = $(top_srcdir) + +noinst_PROGRAMS = + +## Makefile.AO.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS += AO + +AO_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +AO_SOURCES = \ + AO.cpp + +AO_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Makefile.AO2.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS += AO2 + +AO2_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +AO2_SOURCES = \ + AO2.cpp + +AO2_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Clean up template repositories, etc. +clean-local: + -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.* + -rm -f gcctemp.c gcctemp so_locations *.ics + -rm -rf cxx_repository ptrepository ti_files + -rm -rf templateregistry ir.out + -rm -rf ptrepository SunWS_cache Templates.DB diff --git a/ACE/examples/APG/Active_Objects/active_objects.mpc b/ACE/examples/APG/Active_Objects/active_objects.mpc new file mode 100644 index 00000000000..44fe88bfd30 --- /dev/null +++ b/ACE/examples/APG/Active_Objects/active_objects.mpc @@ -0,0 +1,18 @@ +// -*- MPC -*- +// $Id$ + +project(AO) : aceexe { + avoids += ace_for_tao + exename = AO + Source_Files { + AO.cpp + } +} + +project(AO2) : aceexe { + avoids += ace_for_tao + exename = AO2 + Source_Files { + AO2.cpp + } +} diff --git a/ACE/examples/APG/Config/.cvsignore b/ACE/examples/APG/Config/.cvsignore new file mode 100644 index 00000000000..b9f807ab7a6 --- /dev/null +++ b/ACE/examples/APG/Config/.cvsignore @@ -0,0 +1,6 @@ +ARGV_Example +ARGV_Example +Get_Opt +Get_Opt +Get_Opt_Long +Get_Opt_Long diff --git a/ACE/examples/APG/Config/ARGV_Example.cpp b/ACE/examples/APG/Config/ARGV_Example.cpp new file mode 100644 index 00000000000..92fb25cd30d --- /dev/null +++ b/ACE/examples/APG/Config/ARGV_Example.cpp @@ -0,0 +1,62 @@ +/** + * $Id$ + * + * ACE_ARGV examples not in a larger program. Sample code from The ACE + * Programmer's Guide, Copyright 2003 Addison-Wesley. All Rights Reserved. + */ + +#include "ace/os_include/os_netdb.h" +#include "ace/OS_NS_string.h" +#include "ace/Log_Msg.h" + +// Listing 1 code/ch04 +#include "ace/ARGV.h" +#include "ace/Get_Opt.h" + +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + static const ACE_TCHAR options[] = ACE_TEXT (":f:h:"); + static const ACE_TCHAR cmdline[] = + ACE_TEXT ("-f /home/managed.cfg -h $HOSTNAME"); + ACE_ARGV cmdline_args (cmdline); + ACE_Get_Opt cmd_opts (cmdline_args.argc (), + cmdline_args.argv (), + options, + 0); // Don't skip any args + +// Listing 1 + + int option; + ACE_TCHAR config_file[MAXPATHLEN]; + ACE_TCHAR hostname[MAXHOSTNAMELEN]; + ACE_OS_String::strcpy (config_file, ACE_TEXT ("HAStatus.conf")); + ACE_OS_String::strcpy (hostname, ACE_TEXT ("not set")); + while ((option = cmd_opts ()) != EOF) + switch (option) { + case 'f': + ACE_OS_String::strncpy (config_file, + cmd_opts.opt_arg (), + MAXPATHLEN); + break; + + case 'h': + ACE_OS_String::strncpy (hostname, + cmd_opts.opt_arg (), + MAXHOSTNAMELEN); + break; + + case ':': + ACE_ERROR_RETURN + ((LM_ERROR, ACE_TEXT ("-%c requires an argument\n"), + cmd_opts.opt_opt ()), -1); + + + default: + ACE_ERROR_RETURN + ((LM_ERROR, ACE_TEXT ("Parse error.\n")), -1); + } + + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Config file: %s\n"), config_file)); + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Hostname: %s\n"), hostname)); + return 0; +} diff --git a/ACE/examples/APG/Config/Get_Opt.cpp b/ACE/examples/APG/Config/Get_Opt.cpp new file mode 100644 index 00000000000..604dc38326e --- /dev/null +++ b/ACE/examples/APG/Config/Get_Opt.cpp @@ -0,0 +1,59 @@ +/** + * $Id$ + * + * ACE_Get_Opt examples not in a larger program. Sample code from The ACE + * Programmer's Guide, Copyright 2003 Addison-Wesley. All Rights Reserved. + */ + +#include "ace/OS_NS_string.h" +#include "ace/Get_Opt.h" +#include "ace/Log_Msg.h" + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + + // Example for a long option without a corresponding short option. + // Just put some context here so the following compiles and runs. + static const ACE_TCHAR options[] = ACE_TEXT (":f:"); + ACE_Get_Opt cmd_opts (argc, argv, options); + + // Listing 1 code/ch04 + cmd_opts.long_option (ACE_TEXT ("cool_option")); + cmd_opts.long_option (ACE_TEXT ("the_answer"), 42); + // Listing 1 + + int option; + ACE_TCHAR config_file[MAXPATHLEN]; + ACE_OS_String::strcpy (config_file, ACE_TEXT ("HAStatus.conf")); + while ((option = cmd_opts ()) != EOF) + switch (option) { + case 'f': + ACE_OS_String::strncpy (config_file, + cmd_opts.opt_arg (), + MAXPATHLEN); + break; + + // Listing 2 code/ch04 + case 0: + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Yes, very cool.\n"))); + break; + + case 42: + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("the_answer is 42\n"))); + break; + // Listing 2 + + case ':': + ACE_ERROR_RETURN + ((LM_ERROR, ACE_TEXT ("-%c requires an argument\n"), + cmd_opts.opt_opt ()), -1); + + + default: + ACE_ERROR_RETURN + ((LM_ERROR, ACE_TEXT ("Parse error.\n")), -1); + } + + return 0; +} diff --git a/ACE/examples/APG/Config/Get_Opt_Long.cpp b/ACE/examples/APG/Config/Get_Opt_Long.cpp new file mode 100644 index 00000000000..66baed05cdb --- /dev/null +++ b/ACE/examples/APG/Config/Get_Opt_Long.cpp @@ -0,0 +1,48 @@ +/** + * $Id$ + * + * ACE_Get_Opt long_only examples. Sample code from The ACE + * Programmer's Guide, Copyright 2003 Addison-Wesley. All Rights Reserved. + */ + +#include "ace/OS_NS_string.h" +#include "ace/Get_Opt.h" +#include "ace/Log_Msg.h" + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + + static const ACE_TCHAR options[] = ACE_TEXT (":f:"); + ACE_Get_Opt cmd_opts + (argc, argv, options, 1, 0, ACE_Get_Opt::PERMUTE_ARGS, 1); + if (cmd_opts.long_option + (ACE_TEXT ("config"), 'f', ACE_Get_Opt::ARG_REQUIRED) == -1) + return -1; + + int option; + ACE_TCHAR config_file[MAXPATHLEN]; + ACE_OS_String::strcpy (config_file, ACE_TEXT ("HAStatus.conf")); + while ((option = cmd_opts ()) != EOF) + switch (option) { + case 'f': + ACE_OS_String::strncpy (config_file, + cmd_opts.opt_arg (), + MAXPATHLEN); + break; + + case ':': + ACE_ERROR_RETURN + ((LM_ERROR, ACE_TEXT ("-%c requires an argument\n"), + cmd_opts.opt_opt ()), -1); + + + default: + ACE_ERROR_RETURN + ((LM_ERROR, ACE_TEXT ("Parse error.\n")), -1); + } + + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Config file is %s\n"), config_file)); + + return 0; +} diff --git a/ACE/examples/APG/Config/HASTATUS_export.h b/ACE/examples/APG/Config/HASTATUS_export.h new file mode 100644 index 00000000000..09fe1797f80 --- /dev/null +++ b/ACE/examples/APG/Config/HASTATUS_export.h @@ -0,0 +1,54 @@ + +// -*- C++ -*- +// $Id$ +// Definition for Win32 Export directives. +// This file is generated automatically by generate_export_file.pl HASTATUS +// ------------------------------ +#ifndef HASTATUS_EXPORT_H +#define HASTATUS_EXPORT_H + +#include "ace/config-all.h" + +#if defined (ACE_AS_STATIC_LIBS) && !defined (HASTATUS_HAS_DLL) +# define HASTATUS_HAS_DLL 0 +#endif /* ACE_AS_STATIC_LIBS && ! HASTATUS_HAS_DLL */ + +#if !defined (HASTATUS_HAS_DLL) +# define HASTATUS_HAS_DLL 1 +#endif /* ! HASTATUS_HAS_DLL */ + +#if defined (HASTATUS_HAS_DLL) && (HASTATUS_HAS_DLL == 1) +# if defined (HASTATUS_BUILD_DLL) +# define HASTATUS_Export ACE_Proper_Export_Flag +# define HASTATUS_SINGLETON_DECLARATION(T) ACE_EXPORT_SINGLETON_DECLARATION (T) +# define HASTATUS_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) ACE_EXPORT_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) +# else /* HASTATUS_BUILD_DLL */ +# define HASTATUS_Export ACE_Proper_Import_Flag +# define HASTATUS_SINGLETON_DECLARATION(T) ACE_IMPORT_SINGLETON_DECLARATION (T) +# define HASTATUS_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) ACE_IMPORT_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) +# endif /* HASTATUS_BUILD_DLL */ +#else /* HASTATUS_HAS_DLL == 1 */ +# define HASTATUS_Export +# define HASTATUS_SINGLETON_DECLARATION(T) +# define HASTATUS_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) +#endif /* HASTATUS_HAS_DLL == 1 */ + +// Set HASTATUS_NTRACE = 0 to turn on library specific tracing even if +// tracing is turned off for ACE. +#if !defined (HASTATUS_NTRACE) +# if (ACE_NTRACE == 1) +# define HASTATUS_NTRACE 1 +# else /* (ACE_NTRACE == 1) */ +# define HASTATUS_NTRACE 0 +# endif /* (ACE_NTRACE == 1) */ +#endif /* !HASTATUS_NTRACE */ + +#if (HASTATUS_NTRACE == 1) +# define HASTATUS_TRACE(X) +#else /* (HASTATUS_NTRACE == 1) */ +# define HASTATUS_TRACE(X) ACE_TRACE_IMPL(X) +#endif /* (HASTATUS_NTRACE == 1) */ + +#endif /* HASTATUS_EXPORT_H */ + +// End of auto generated file. diff --git a/ACE/examples/APG/Config/HA_Status.cpp b/ACE/examples/APG/Config/HA_Status.cpp new file mode 100644 index 00000000000..1bad687be80 --- /dev/null +++ b/ACE/examples/APG/Config/HA_Status.cpp @@ -0,0 +1,98 @@ +/** + * $Id$ + * + * Home Automation Status server. Sample code from The ACE Programmer's Guide, + * Copyright 2003 Addison-Wesley. All Rights Reserved. + */ + +#include "ace/OS_NS_string.h" +#include "ace/Configuration.h" +#include "ace/Configuration_Import_Export.h" +#include "ace/Get_Opt.h" +#include "ace/Log_Msg.h" +#include "ace/INET_Addr.h" +#include "ace/Service_Object.h" + +class HA_Status : public ACE_Service_Object +{ +public: + virtual int init (int argc, ACE_TCHAR *argv[]); + +private: + ACE_INET_Addr listen_addr_; +}; + + +int +HA_Status::init (int argc, ACE_TCHAR *argv[]) +{ + + // Do ACE_Get_Opt and get conf file name, read out the sections + // and print the names. + + // Listing 1 code/ch04 + static const ACE_TCHAR options[] = ACE_TEXT (":f:"); + ACE_Get_Opt cmd_opts (argc, argv, options); + if (cmd_opts.long_option + (ACE_TEXT ("config"), 'f', ACE_Get_Opt::ARG_REQUIRED) == -1) + return -1; + int option; + ACE_TCHAR config_file[MAXPATHLEN]; + ACE_OS::strcpy (config_file, ACE_TEXT ("HAStatus.conf")); + while ((option = cmd_opts ()) != EOF) + switch (option) { + case 'f': + ACE_OS::strncpy (config_file, + cmd_opts.opt_arg (), + MAXPATHLEN); + break; + case ':': + ACE_ERROR_RETURN + ((LM_ERROR, ACE_TEXT ("-%c requires an argument\n"), + cmd_opts.opt_opt ()), -1); + default: + ACE_ERROR_RETURN + ((LM_ERROR, ACE_TEXT ("Parse error.\n")), -1); + } + // Listing 1 + + // Listing 2 code/ch04 + ACE_Configuration_Heap config; + if (config.open () == -1) + ACE_ERROR_RETURN + ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("config")), -1); + ACE_Registry_ImpExp config_importer (config); + if (config_importer.import_config (config_file) == -1) + ACE_ERROR_RETURN + ((LM_ERROR, ACE_TEXT ("%p\n"), config_file), -1); + + ACE_Configuration_Section_Key status_section; + if (config.open_section (config.root_section (), + ACE_TEXT ("HAStatus"), + 0, + status_section) == -1) + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), + ACE_TEXT ("Can't open HAStatus section")), + -1); + + u_int status_port; + if (config.get_integer_value (status_section, + ACE_TEXT ("ListenPort"), + status_port) == -1) + ACE_ERROR_RETURN + ((LM_ERROR, + ACE_TEXT ("HAStatus ListenPort does not exist\n")), + -1); + this->listen_addr_.set (static_cast<u_short> (status_port)); + // Listing 2 + + return 0; +} + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + HA_Status status; + status.init (argc, argv); + return 0; +} diff --git a/ACE/examples/APG/Config/Makefile.am b/ACE/examples/APG/Config/Makefile.am new file mode 100644 index 00000000000..5320bfdf85c --- /dev/null +++ b/ACE/examples/APG/Config/Makefile.am @@ -0,0 +1,81 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +ACE_BUILDDIR = $(top_builddir) +ACE_ROOT = $(top_srcdir) + + +## Makefile.ARGV_Example.am +noinst_PROGRAMS = ARGV_Example + +ARGV_Example_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +ARGV_Example_SOURCES = \ + ARGV_Example.cpp \ + HASTATUS_export.h + +ARGV_Example_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Config_HA_Status.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS += HA_Status + +HA_Status_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +HA_Status_SOURCES = \ + HA_Status.cpp \ + HASTATUS_export.h + +HA_Status_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Makefile.Get_Opt.am +noinst_PROGRAMS += Get_Opt + +Get_Opt_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +Get_Opt_SOURCES = \ + Get_Opt.cpp \ + HASTATUS_export.h + +Get_Opt_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Get_Opt_Long.am +noinst_PROGRAMS += Get_Opt_Long + +Get_Opt_Long_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +Get_Opt_Long_SOURCES = \ + Get_Opt_Long.cpp \ + HASTATUS_export.h + +Get_Opt_Long_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Clean up template repositories, etc. +clean-local: + -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.* + -rm -f gcctemp.c gcctemp so_locations *.ics + -rm -rf cxx_repository ptrepository ti_files + -rm -rf templateregistry ir.out + -rm -rf ptrepository SunWS_cache Templates.DB diff --git a/ACE/examples/APG/Config/config.mpc b/ACE/examples/APG/Config/config.mpc new file mode 100644 index 00000000000..5b705d144bc --- /dev/null +++ b/ACE/examples/APG/Config/config.mpc @@ -0,0 +1,31 @@ +// -*- MPC -*- +// $Id$ + +project(*HA Status) : aceexe { + avoids += ace_for_tao + exename = HA_Status + Source_Files { + HA_Status.cpp + } +} + +project(Get Opt) : aceexe { + exename = Get_Opt + Source_Files { + Get_Opt.cpp + } +} + +project(Get Opt Long) : aceexe { + exename = Get_Opt_Long + Source_Files { + Get_Opt_Long.cpp + } +} + +project(ARGV Example) : aceexe { + exename = ARGV_Example + Source_Files { + ARGV_Example.cpp + } +} diff --git a/ACE/examples/APG/Containers/.cvsignore b/ACE/examples/APG/Containers/.cvsignore new file mode 100644 index 00000000000..20d09b55a72 --- /dev/null +++ b/ACE/examples/APG/Containers/.cvsignore @@ -0,0 +1,24 @@ +Allocator +Allocator +Array +Array +DLList +DLList +Hash_Map +Hash_Map +Hash_Map_Hash +Hash_Map_Hash +Map_Manager +Map_Manager +Map_Manager_Specialization +Map_Manager_Specialization +Queues +Queues +RB_Tree +RB_Tree +RB_Tree_Functors +RB_Tree_Functors +Sets +Sets +Stacks +Stacks diff --git a/ACE/examples/APG/Containers/Allocator.cpp b/ACE/examples/APG/Containers/Allocator.cpp new file mode 100644 index 00000000000..847235a3061 --- /dev/null +++ b/ACE/examples/APG/Containers/Allocator.cpp @@ -0,0 +1,93 @@ +// $Id$ + +#include "ace/Containers.h" +#include "ace/Malloc_T.h" +#include "ace/Synch.h" // Needed for the lock. +#include "DataElement.h" + +class StackExample +{ +public: + // Illustrate all the differnet + // types of stacks provided by ACE. + int run (void); + +private: + // Illustrate the use of an unbounded stack. + int runUnboundedStack (ACE_Allocator* allocator); +}; + +// Listing 1 code/ch05 +int StackExample::run (void) +{ + ACE_TRACE (ACE_TEXT ("StackUser::run")); + + ACE_Allocator *allocator = 0; + size_t block_size = sizeof(ACE_Node<DataElement>); + ACE_NEW_RETURN + (allocator, + ACE_Dynamic_Cached_Allocator<ACE_Null_Mutex> + (100 + 1, block_size), + -1); + + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\n# of live objects %d\n"), + DataElement::numOfActiveObjects ())); + + ACE_ASSERT (this->runUnboundedStack (allocator) != -1); + + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\n# of live objects %d\n"), + DataElement::numOfActiveObjects ())); + + delete allocator; + return 0; +} +// Listing 1 +// Listing 2 code/ch05 +int StackExample::runUnboundedStack (ACE_Allocator* allocator) +{ + ACE_TRACE (ACE_TEXT ("StackExample::runUnboundedStack")); + + // Pass in an allocator during construction. + ACE_Unbounded_Stack<DataElement> ustack (allocator); + + for (int m = 0; m < 100; m++) + { + DataElement elem (m); + int result = ustack.push (elem); + if (result == -1) + ACE_ERROR_RETURN + ((LM_ERROR, ACE_TEXT ("%p\n"), + ACE_TEXT ("Push Next Element")), + -1); + } + + void* furtherMemory = 0; + furtherMemory = allocator->malloc + (sizeof(ACE_Node<DataElement>)); + ACE_ASSERT (furtherMemory == 0); + + // No memory left.. + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("%p\n"), + ACE_TEXT ("No memory.."))); + + // Free up some memory in the allocator. + DataElement e; + for (int n = 0; n < 10; n++) + { + ustack.pop (e); + } + + furtherMemory = + allocator->malloc (sizeof (ACE_Node<DataElement>)); + ACE_ASSERT (furtherMemory != 0); + + return 0; +} +// Listing 2 + +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + StackExample se; + return se.run (); +} + diff --git a/ACE/examples/APG/Containers/Array.cpp b/ACE/examples/APG/Containers/Array.cpp new file mode 100644 index 00000000000..1ffb19f22e9 --- /dev/null +++ b/ACE/examples/APG/Containers/Array.cpp @@ -0,0 +1,41 @@ +// $Id$ + +#include "ace/OS_Memory.h" +#include "ace/Log_Msg.h" +// Listing 1 code/ch05 +#include "ace/Containers.h" +#include "DataElement.h" + +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_Array<DataElement*> arr (10); + DataElement *elem = 0; + // Allocate and insert elements. + for (int i = 0; i < 10; i++) + { + ACE_NEW_RETURN (elem, DataElement (i), -1); + arr[i] = elem; + } + + // Checked access. + ACE_ASSERT (arr.set (elem, 11) == -1); + ACE_ASSERT (arr.get (elem, 11) == -1); + + // Make a copy and compare to the original. + ACE_Array<DataElement*> copy = arr; + ACE_ASSERT (copy == arr); + + ACE_Array<DataElement*>::ITERATOR iter (arr); + while (!iter.done ()) + { + DataElement** data; + iter.next (data); + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("%d\n"), (*data)->getData ())); + delete (*data); + iter.advance (); + } + return 0; +} +// Listing 1 + diff --git a/ACE/examples/APG/Containers/DLList.cpp b/ACE/examples/APG/Containers/DLList.cpp new file mode 100644 index 00000000000..8c93e5b4039 --- /dev/null +++ b/ACE/examples/APG/Containers/DLList.cpp @@ -0,0 +1,116 @@ +// $Id$ + +#include "ace/OS_Memory.h" +#include "ace/Log_Msg.h" + +// Listing 1 code/ch05 +#include "ace/Containers.h" +#include "DataElement.h" + +// Create a new type of list that can store only DataElements. +typedef ACE_DLList<DataElement> MyList; +// Listing 1 + +// Listing 2 code/ch05 +class ListTest +{ +public: + int run (void); + void displayList (MyList & list); // Display all elements. + void destroyList (MyList& list); // Destroy all elements. +}; +// Listing 2 +// Listing 3 code/ch05 +int +ListTest::run (void) +{ + ACE_TRACE (ACE_TEXT ("ListTest::run")); + + // Create a list and insert 100 elements. + MyList list1; + + for (int i = 0; i < 100; i++) + { + DataElement *element; + ACE_NEW_RETURN (element, DataElement (i), -1); + list1.insert_tail (element); + } + + // Iterate through and display to output. + this->displayList (list1); + + // Create a copy of list1. + MyList list2; + list2 = list1; + + // Iterate over the copy and display it to output. + this->displayList(list2); + + // Get rid of the copy list and all its elements. + // Since both lists had the *same* elements + // this will cause list1 to contain pointers that + // point to data elements that have already been destroyed! + this->destroyList (list2); + + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("# of live objects: %d\n"), + DataElement::numOfActiveObjects())); + + // The lists themselves are destroyed here. Note that the + // list destructor will destroy copies of whatever data the + // list contained. Since in this case the list contained + // copies of pointers to the data elements these are the + // only thing that gets destroyed here. + return 0; +} +// Listing 3 +// Listing 4 code/ch05 +void +ListTest::destroyList (MyList& list) +{ + ACE_TRACE (ACE_TEXT ("ListTest::destroyList")); + + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Destroying data elements\n"))); + + // Iterate through and delete all the data elements on the list. + for (ACE_DLList_Iterator<DataElement> iter (list); + !iter.done (); + iter++) + { + DataElement *de = iter.next (); + delete de; + } +} +// Listing 4 +// Listing 5 code/ch05 +void +ListTest::displayList (MyList& list) +{ + ACE_TRACE (ACE_TEXT ("ListTest::displayList")); + + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Forward iteration\n"))); + ACE_DLList_Iterator<DataElement> iter (list); + while (!iter.done ()) + { + ACE_DEBUG + ((LM_DEBUG, ACE_TEXT ("%d:"), iter.next()->getData())); + iter++; + } + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\n"))); + + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Reverse Iteration \n"))); + ACE_DLList_Reverse_Iterator<DataElement> riter (list); + while (!riter.done ()) + { + ACE_DEBUG + ((LM_DEBUG, ACE_TEXT ("%d:"), riter.next()->getData())); + riter++; + } + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\n"))); +} +// Listing 5 +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ListTest test; + return test.run (); +} + diff --git a/ACE/examples/APG/Containers/DataElement.h b/ACE/examples/APG/Containers/DataElement.h new file mode 100644 index 00000000000..cd09d86fa87 --- /dev/null +++ b/ACE/examples/APG/Containers/DataElement.h @@ -0,0 +1,52 @@ +/* -*- C++ -*- */ +// $Id$ + +#if !defined(DATAELEMENT_H) +#define DATAELEMENT_H + +class DataElementEx; + +// Listing 1 code/ch05 +// A simple data element class. +class DataElement +{ + friend class DataElementEx; + +public: + DataElement () : data_ (0) { count_++; } + + DataElement (int data) : data_(data) { count_++; } + + DataElement (const DataElement& e) + { + data_ = e.getData (); + count_++; + } + + DataElement & operator= (const DataElement& e) + { + data_ = e.getData (); + return *this; + } + + bool operator== (const DataElement& e) + { return this->data_ == e.data_; } + + ~DataElement () { count_--; } + + int getData (void) const { return data_; } + + void setData (int val) { data_ = val; } + + static int numOfActiveObjects (void) { return count_; } + + private: + int data_; + static int count_; +}; +// Listing 1 + +int DataElement::count_ = 0; + +#endif /*DATAELEMENT_H*/ + diff --git a/ACE/examples/APG/Containers/Hash_Map.cpp b/ACE/examples/APG/Containers/Hash_Map.cpp new file mode 100644 index 00000000000..1b2d4ee4634 --- /dev/null +++ b/ACE/examples/APG/Containers/Hash_Map.cpp @@ -0,0 +1,118 @@ +// $Id$ + +#include "ace/Hash_Map_Manager.h" +#include "ace/Synch.h" // needed for the lock +#include "ace/Functor.h" +#include "DataElement.h" + +// Listing 1 code/ch05 +// Little helper class. +template<class EXT_ID, class INT_ID> +class Hash_Map : + public ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, + ACE_Hash<EXT_ID>, ACE_Equal_To<EXT_ID>, ACE_Null_Mutex> +{}; +// Listing 1 + +class Hash_Map_Example +{ +public: + // Constructor + Hash_Map_Example (); + + // Illustrate the hash map. + int run (void); + + // Use the forward iterator. + void iterate_forward (void); + + // Use the reverse iterator. + void iterate_reverse (void); + + // Remove all the elements from the map. + void remove_all (void); + +private: + Hash_Map<int, DataElement> map_; +}; + +// Listing 2 code/ch05 +Hash_Map_Example::Hash_Map_Example() +{ + ACE_TRACE (ACE_TEXT ("Hash_Map_Example::Hash_Map_Example")); + + map_.open (100); +} +// Listing 2 + +int Hash_Map_Example::run (void) +{ + ACE_TRACE (ACE_TEXT ("Hash_Map_Example::run")); + + for (int i = 0; i < 100; i++) + { + map_.bind (i, DataElement(i)); + } + + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Map has \n"))); + for (int j = 0; j < 100; j++) + { + DataElement d; + map_.find (j,d); + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("%d:"), d.getData ())); + } + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\n"))); + + // Use the forward iterator. + this->iterate_forward (); + + // Use the reverse iterator. + this->iterate_reverse (); + + // Remove all the elements from the map. + this->remove_all (); + + // Iterate through the map again. + this->iterate_forward (); + + return 0; +} + +void Hash_Map_Example::iterate_forward (void) +{ + ACE_TRACE (ACE_TEXT ("Hash_Map_Example::iterate_forward")); + + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Forward Iteration \n"))); + for (Hash_Map<int, DataElement>::iterator iter = map_.begin (); + iter != map_.end (); iter++) + { + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("%d:"), (*iter).int_id_.getData ())); + } + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\n"))); +} + +void Hash_Map_Example::iterate_reverse (void) +{ + ACE_TRACE (ACE_TEXT ("Hash_Map_Example::iterate_reverse")); + + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Reverse Iteration \n"))); + for (Hash_Map<int, DataElement>::reverse_iterator iter = map_.rbegin (); + iter != map_.rend (); iter++) + { + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("%d:"), (*iter).int_id_.getData ())); + } + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\n"))); +} + +void Hash_Map_Example::remove_all (void) +{ + ACE_TRACE (ACE_TEXT ("Hash_Map_Example::remove_all")); + map_.unbind_all (); +} + +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + Hash_Map_Example me; + return me.run (); +} + diff --git a/ACE/examples/APG/Containers/Hash_Map_Hash.cpp b/ACE/examples/APG/Containers/Hash_Map_Hash.cpp new file mode 100644 index 00000000000..faad3c72585 --- /dev/null +++ b/ACE/examples/APG/Containers/Hash_Map_Hash.cpp @@ -0,0 +1,111 @@ +// $Id$ + +#include "ace/Hash_Map_Manager.h" +#include "ace/Synch.h" // Needed for the lock +#include "ace/Functor.h" +#include "DataElement.h" +#include "Hash_Map_Hash.h" + +// Little helper class +template<class EXT_ID, class INT_ID> +class Hash_Map : + public ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, + ACE_Hash<EXT_ID>, ACE_Equal_To<EXT_ID>, ACE_Null_Mutex> +{}; + + +class Hash_Map_Example +{ +public: + ~Hash_Map_Example () + { + map_.close (); + } + + // illustrate the hash map + int run (void); + + // use the forward iterate + void iterate_forward (void); + + // use the reverse iterator + void iterate_reverse (void); + + // remove all the elements from the map + void remove_all (void); + +private: + Hash_Map<KeyType, DataElement> map_; +}; + +int Hash_Map_Example::run (void) +{ + ACE_TRACE (ACE_TEXT ("Hash_Map_Example::run")); + + for (int i = 0; i < 100; i++) + { + map_.bind (i, DataElement (i)); + } + + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Map has \n"))); + for (int j = 0; j < 100; j++) + { + DataElement d; + map_.find (j, d); + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("%d:"), d.getData ())); + } + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\n"))); + + // Use the forward iterator. + this->iterate_forward (); + + // Use the reverse iterator. + this->iterate_reverse (); + + // Remove all the elements from the map. + this->remove_all (); + + // Iterate through the map again. + this->iterate_forward (); + + return 0; +} + +void Hash_Map_Example::iterate_forward (void) +{ + ACE_TRACE (ACE_TEXT ("Hash_Map_Example::iterate_forward")); + + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Forward Iteration \n"))); + for (Hash_Map<KeyType, DataElement>::iterator iter = map_.begin (); + iter != map_.end (); iter++) + { + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("%d:"), (*iter).int_id_.getData ())); + } + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\n"))); +} + +void Hash_Map_Example::iterate_reverse (void) +{ + ACE_TRACE (ACE_TEXT ("Hash_Map_Example::iterate_reverse")); + + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Reverse Iteration \n"))); + for (Hash_Map<KeyType, DataElement>::reverse_iterator iter = map_.rbegin (); + iter != map_.rend (); iter++) + { + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("%d:"), (*iter).int_id_.getData ())); + } + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\n"))); +} + +void Hash_Map_Example::remove_all (void) +{ + ACE_TRACE (ACE_TEXT ("Hash_Map_Example::remove_all")); + map_.unbind_all (); +} + +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + Hash_Map_Example me; + return me.run (); +} + diff --git a/ACE/examples/APG/Containers/Hash_Map_Hash.h b/ACE/examples/APG/Containers/Hash_Map_Hash.h new file mode 100644 index 00000000000..a125f9ee7e6 --- /dev/null +++ b/ACE/examples/APG/Containers/Hash_Map_Hash.h @@ -0,0 +1,57 @@ +/* -*- C++ -*- */ +// $Id$ + +#ifndef __HASH_MAP_HASH_H_ +#define __HASH_MAP_HASH_H_ + +// Listing 1 code/ch05 +// Key type that we are going to use. +class KeyType +{ +public: + KeyType () : val_(0) {} + + KeyType (int i) : val_(i) {} + + KeyType (const KeyType& kt) { this->val_ = kt.val_; } + + operator int (void) const { return val_; } + +private: + int val_; +}; + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +// Specialize the hash functor. +template<> +class ACE_Hash<KeyType> +{ +public: + u_long operator() (const KeyType kt) const + { + int val = kt; + return (u_long)val; + } +}; + + +// Specialize the equality functor. +template<> +class ACE_Equal_To<KeyType> +{ +public: + int operator() (const KeyType& kt1, + const KeyType& kt2) const + { + int val1 = kt1; + int val2 = kt2; + return (val1 == val2); + } +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +// Listing 1 + +#endif /* __HASH_MAP_HASH_H_ */ diff --git a/ACE/examples/APG/Containers/KeyType.h b/ACE/examples/APG/Containers/KeyType.h new file mode 100644 index 00000000000..268b56c1684 --- /dev/null +++ b/ACE/examples/APG/Containers/KeyType.h @@ -0,0 +1,28 @@ +/* -*- C++ -*- */ +// $Id$ + +#ifndef __KEYTYPE_H_ +#define __KEYTYPE_H_ + +// Listing 1 code/ch05 +class KeyType +{ +public: + friend bool operator == (const KeyType&, const KeyType&); + + KeyType () : val_(0) {} + KeyType (int i) : val_(i) {} + KeyType (const KeyType& kt) { this->val_ = kt.val_; }; + operator int() const { return val_; }; + +private: + int val_; +}; + +bool operator == (const KeyType& a, const KeyType& b) +{ + return (a.val_ == b.val_); +} +// Listing 1 + +#endif /* __KEYTYPE_H_ */ diff --git a/ACE/examples/APG/Containers/Makefile.am b/ACE/examples/APG/Containers/Makefile.am new file mode 100644 index 00000000000..e5ef96ad6dc --- /dev/null +++ b/ACE/examples/APG/Containers/Makefile.am @@ -0,0 +1,223 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +ACE_BUILDDIR = $(top_builddir) +ACE_ROOT = $(top_srcdir) + + +## Makefile.Allocator.am +noinst_PROGRAMS = Allocator + +Allocator_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +Allocator_SOURCES = \ + Allocator.cpp \ + DataElement.h \ + Hash_Map_Hash.h \ + KeyType.h \ + RB_Tree_Functors.h + +Allocator_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Array.am +noinst_PROGRAMS += Array + +Array_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +Array_SOURCES = \ + Array.cpp \ + DataElement.h \ + Hash_Map_Hash.h \ + KeyType.h \ + RB_Tree_Functors.h + +Array_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Containers_Hash_Map.am +noinst_PROGRAMS += Hash_Map + +Hash_Map_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +Hash_Map_SOURCES = \ + Hash_Map.cpp \ + DataElement.h \ + Hash_Map_Hash.h \ + KeyType.h \ + RB_Tree_Functors.h + +Hash_Map_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Containers_Map_Manager.am +noinst_PROGRAMS += Map_Manager + +Map_Manager_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +Map_Manager_SOURCES = \ + Map_Manager.cpp \ + DataElement.h \ + Hash_Map_Hash.h \ + KeyType.h \ + RB_Tree_Functors.h + +Map_Manager_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.DLList.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS += DLList + +DLList_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +DLList_SOURCES = \ + DLList.cpp \ + DataElement.h \ + Hash_Map_Hash.h \ + KeyType.h \ + RB_Tree_Functors.h + +DLList_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Makefile.Hash_Map_Hash.am +noinst_PROGRAMS += Hash_Map_Hash + +Hash_Map_Hash_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +Hash_Map_Hash_SOURCES = \ + Hash_Map_Hash.cpp \ + Hash_Map_Hash.h + +Hash_Map_Hash_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Map_Manager_Specialization.am +noinst_PROGRAMS += Map_Manager_Specialization + +Map_Manager_Specialization_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +Map_Manager_Specialization_SOURCES = \ + Map_Manager_Specialization.cpp \ + DataElement.h \ + Hash_Map_Hash.h \ + KeyType.h \ + RB_Tree_Functors.h + +Map_Manager_Specialization_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Queues.am +noinst_PROGRAMS += Queues + +Queues_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +Queues_SOURCES = \ + Queues.cpp \ + DataElement.h \ + Hash_Map_Hash.h \ + KeyType.h \ + RB_Tree_Functors.h + +Queues_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.RB_Tree.am +noinst_PROGRAMS += RB_Tree + +RB_Tree_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +RB_Tree_SOURCES = \ + RB_Tree.cpp \ + DataElement.h \ + Hash_Map_Hash.h \ + KeyType.h \ + RB_Tree_Functors.h + +RB_Tree_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.RB_Tree_Functors.am +noinst_PROGRAMS += RB_Tree_Functors + +RB_Tree_Functors_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +RB_Tree_Functors_SOURCES = \ + RB_Tree_Functors.cpp \ + RB_Tree_Functors.h + +RB_Tree_Functors_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Sets.am +noinst_PROGRAMS += Sets + +Sets_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +Sets_SOURCES = \ + Sets.cpp \ + DataElement.h \ + Hash_Map_Hash.h \ + KeyType.h \ + RB_Tree_Functors.h + +Sets_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Stacks.am +noinst_PROGRAMS += Stacks + +Stacks_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +Stacks_SOURCES = \ + Stacks.cpp \ + DataElement.h \ + Hash_Map_Hash.h \ + KeyType.h \ + RB_Tree_Functors.h + +Stacks_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Clean up template repositories, etc. +clean-local: + -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.* + -rm -f gcctemp.c gcctemp so_locations *.ics + -rm -rf cxx_repository ptrepository ti_files + -rm -rf templateregistry ir.out + -rm -rf ptrepository SunWS_cache Templates.DB diff --git a/ACE/examples/APG/Containers/Map_Manager.cpp b/ACE/examples/APG/Containers/Map_Manager.cpp new file mode 100644 index 00000000000..6673204fcc4 --- /dev/null +++ b/ACE/examples/APG/Containers/Map_Manager.cpp @@ -0,0 +1,117 @@ +// $Id$ + +#include "ace/Log_Msg.h" +#include "ace/Map_Manager.h" +#include "ace/Synch.h" +#include "DataElement.h" +#include "KeyType.h" + +class Map_Example +{ +public: + // Illustrate the ACE_Map_Manager. + int run (void); + +private: + // Iterate in the forward direction. + void iterate_forward (void); + + // Iterate in the other direction. + void iterate_reverse (void); + + // Remove all elements from the map. + void remove_all (void); + +private: + ACE_Map_Manager<KeyType,DataElement,ACE_Null_Mutex> map_; +}; + +// Listing 2 code/ch05 +int Map_Example::run (void) +{ + ACE_TRACE (ACE_TEXT ("Map_Example::run")); + + // Corresponding KeyType objects are created on the fly. + for (int i = 0; i < 100; i++) + { + map_.bind (i, DataElement (i)); + } + + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Map has \n"))); + for (int j = 0; j < 100; j++) + { + DataElement d; + map_.find (j,d); + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("%d:"), d.getData ())); + } + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\n"))); + + // Iterate in the forward direction. + this->iterate_forward (); + + // Iterate in the other direction. + this->iterate_reverse (); + + // Remove all elements from the map. + this->remove_all (); + + // Iterate in the forward direction. + this->iterate_forward (); + + return 0; +} +// Listing 2 +// Listing 3 code/ch05 +void Map_Example::iterate_forward (void) +{ + ACE_TRACE (ACE_TEXT ("Map_Example::iterate_forward")); + + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Forward iteration\n"))); + for (ACE_Map_Manager<KeyType, + DataElement, + ACE_Null_Mutex>::iterator + iter = map_.begin (); + iter != map_.end (); + iter++) + { + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("%d:"), + (*iter).int_id_.getData ())); + } + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\n"))); +} + + +void Map_Example::iterate_reverse (void) +{ + ACE_TRACE (ACE_TEXT ("Map_Example::iterate_reverse")); + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Reverse iteration\n"))); + for (ACE_Map_Manager<KeyType, + DataElement, + ACE_Null_Mutex>::reverse_iterator + iter = map_.rbegin (); + iter != map_.end (); + iter++) + { + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("%d:"), + (*iter).int_id_.getData ())); + } + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\n"))); +} +// Listing 3 +// Listing 4 code/ch05 +void Map_Example::remove_all (void) +{ + ACE_TRACE (ACE_TEXT ("Map_Example::remove_all")); + + // Note that we can't use the iterators here as they + // are invalidated after deletions or insertions. + map_.unbind_all (); +} +// Listing 4 + +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + Map_Example me; + return me.run (); +} + diff --git a/ACE/examples/APG/Containers/Map_Manager_Specialization.cpp b/ACE/examples/APG/Containers/Map_Manager_Specialization.cpp new file mode 100644 index 00000000000..fc9c00d86f0 --- /dev/null +++ b/ACE/examples/APG/Containers/Map_Manager_Specialization.cpp @@ -0,0 +1,153 @@ +// $Id$ + +#include "ace/Log_Msg.h" +#include "ace/Map_Manager.h" +#include "ace/Synch.h" // Needed for the lock. +#include "DataElement.h" +#include "KeyType.h" + +/* +** This needs to stay in the book for 2nd printing, but is the same as +** what's in KeyType.h. +*/ +#if 0 +// Listing 1 code/ch05 +class KeyType +{ +public: + KeyType () : val_(0) {} + + KeyType (int i) : val_(i) {} + + KeyType (const KeyType& kt) { this->val_ = kt.val_; }; + + operator int () const { return val_; }; + +private: + int val_; +}; + +template<> +int +ACE_Map_Manager<KeyType, DataElement, ACE_Null_Mutex>::equal +(const KeyType& r1, const KeyType &r2) +{ + return (r1 == r2); +} +// Listing 1 +#else +template<> +int +ACE_Map_Manager<KeyType, DataElement, ACE_Null_Mutex>::equal +(const KeyType& r1, const KeyType &r2) +{ + return (r1 == r2); +} +#endif /* 0 */ + +class Map_Example +{ +public: + // Illustrate the ACE_Map_Manager<>. + int run (void); + +private: + // Iterate in the forward direction. + void iterate_forward (void); + + // Iterate in the other direction. + void iterate_reverse (void); + + // Remove all elements from the map. + void remove_all (void); + +private: + ACE_Map_Manager<KeyType,DataElement,ACE_Null_Mutex> map_; +}; + +int Map_Example::run (void) +{ + ACE_TRACE (ACE_TEXT ("Map_Example::run")); + + // Corresponding KeyType objects are created on the fly. + for (int i = 0; i < 100; i++) + { + map_.bind (i, DataElement (i)); + } + + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Map has \n"))); + for (int j = 0; j < 100; j++) + { + DataElement d; + int result = map_.find (j,d); + if (result == 0) + { + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("%d:"), d.getData ())); + } + } + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\n"))); + + // Iterate in the forward direction. + this->iterate_forward (); + + // Iterate in the other direction. + this->iterate_reverse (); + + // Remove all elements from the map. + this->remove_all (); + + // Iterate in the forward direction. + this->iterate_forward (); + + return 0; +} + +void Map_Example::iterate_forward (void) +{ + ACE_TRACE (ACE_TEXT ("Map_Example::iterate_forward")); + + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Forward iteration\n"))); + for (ACE_Map_Manager<KeyType, DataElement, ACE_Null_Mutex>::iterator + iter = map_.begin (); + iter!= map_.end (); + iter++) + { + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("%d:"), (*iter).int_id_.getData ())); + } + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\n"))); +} + +void Map_Example::iterate_reverse (void) +{ + ACE_TRACE (ACE_TEXT ("Map_Example::iterate_reverse")); + + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Reverse iteration\n"))); + for (ACE_Map_Manager<KeyType, DataElement, ACE_Null_Mutex>::reverse_iterator + iter = map_.rbegin (); + iter!= map_.end (); + iter++) + { + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("%d:"), (*iter).int_id_.getData ())); + } + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\n"))); +} + +void Map_Example::remove_all (void) +{ + ACE_TRACE (ACE_TEXT ("Map_Example::remove_all")); + + // Note that we can't use the iterators here + // as they are invalidated after deletions + // or insertions. + for (int i = 0; i < 100; i++) + { + map_.unbind (i); + } +} + +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + Map_Example me; + return me.run (); +} + diff --git a/ACE/examples/APG/Containers/Queues.cpp b/ACE/examples/APG/Containers/Queues.cpp new file mode 100644 index 00000000000..ca945169ed4 --- /dev/null +++ b/ACE/examples/APG/Containers/Queues.cpp @@ -0,0 +1,115 @@ +// $Id$ + +#include "ace/OS_Memory.h" +#include "ace/Log_Msg.h" +#include "ace/Containers.h" +#include "DataElement.h" + +class QueueExample +{ +public: + // Illustrate the various ACE Queues. + int run (void); + +private: + // Illustrate the ACE unbounded queue + // that has copies of the data elements. + int runStackUnboundedQueue (void); + + // Illustrate the ACE unbounded queue + // with pointers to elements on the heap. + int runHeapUnboundedQueue (void); +}; + +int QueueExample::run (void) +{ + ACE_TRACE (ACE_TEXT ("QueueExample::run")); + + // Illustrate the queue with elements on the stack. + if (this->runStackUnboundedQueue () != 0) + { + return -1; + } + + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\n# of live objects %d\n"), + DataElement::numOfActiveObjects ())); + + // Illustrate the queue with elements on the heap. + if (this->runHeapUnboundedQueue () != 0) + { + return -1; + } + + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\n# of live objects %d\n"), + DataElement::numOfActiveObjects ())); + + return 0; +} + +// Listing 1 code/ch05 +int QueueExample::runStackUnboundedQueue (void) +{ + ACE_TRACE (ACE_TEXT ("QueueExample::runStackUnboundedQueue")); + + ACE_Unbounded_Queue<DataElement> queue; + DataElement elem1[10]; + int i; + for (i = 0; i < 10; i++) + { + elem1[i].setData (9-i); + queue.enqueue_head (elem1[i]); + } + + DataElement elem2[10]; + for (i = 0; i < 10; i++) + { + elem2[i].setData (i+10); + queue.enqueue_tail (elem2[i]); + } + + for (ACE_Unbounded_Queue_Iterator<DataElement> iter (queue); + !iter.done (); + iter.advance ()) + { + DataElement *elem = 0; + iter.next (elem); + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("%d:"), elem->getData ())); + } + + return 0; +} +// Listing 1 +// Listing 2 code/ch05 +int QueueExample::runHeapUnboundedQueue (void) +{ + ACE_TRACE (ACE_TEXT ("QueueExample::runHeapUnboundedQueue")); + + ACE_Unbounded_Queue<DataElement*> queue; + for (int i = 0; i < 20; i++) + { + DataElement *elem; + ACE_NEW_RETURN(elem, DataElement (i), -1); + queue.enqueue_head (elem); + } + + for (ACE_Unbounded_Queue_Iterator<DataElement*> iter + = queue.begin (); + !iter.done (); + iter.advance ()) + { + DataElement **elem = 0; + iter.next(elem); + ACE_DEBUG + ((LM_DEBUG, ACE_TEXT ("%d:"), (*elem)->getData ())); + delete (*elem); + } + + return 0; +} +// Listing 2 +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + QueueExample que; + return que.run (); +} + diff --git a/ACE/examples/APG/Containers/RB_Tree.cpp b/ACE/examples/APG/Containers/RB_Tree.cpp new file mode 100644 index 00000000000..187332a31d8 --- /dev/null +++ b/ACE/examples/APG/Containers/RB_Tree.cpp @@ -0,0 +1,135 @@ +// $Id$ + +#include "ace/RB_Tree.h" +#include "ace/Log_Msg.h" +#include "ace/Synch.h" +#include "DataElement.h" + +// Little helper class. +template<class EXT_ID, class INT_ID> +class Tree : public ACE_RB_Tree<EXT_ID, INT_ID, + ACE_Less_Than<EXT_ID>, + ACE_Null_Mutex> +{}; + +class Tree_Example +{ +public: + // Illustrate the tree. + int run (void); + +private: + // Use the forward iterator. + void iterate_forward (void); + + // Use the reverse iterator. + void iterate_reverse (void); + + // Remove all elements from the tree. + int remove_all (void); + +private: + Tree<int, DataElement*> tree_; +}; + +// Listing 1 code/ch05 +int Tree_Example::run (void) +{ + ACE_TRACE (ACE_TEXT ("Tree_Example::run")); + + DataElement *d = 0; + for (int i = 0; i < 100; i++) + { + ACE_NEW_RETURN (d, DataElement (i), -1); + int result = tree_.bind (i, d); + if (result!= 0) + { + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), + ACE_TEXT ("Bind")), + -1); + } + } + + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Using find: \n"))); + for (int j = 0; j < 100; j++) + { + tree_.find (j, d); + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("%d:"), d->getData ())); + } + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\n"))); + + // Use the forward iterator. + this->iterate_forward (); + + // Use the reverse iterator. + this->iterate_reverse (); + + // Remove all elements from the tree. + ACE_ASSERT (this->remove_all ()!= -1); + + // Iterate through once again. + this->iterate_forward (); + + return 0; +} + +void Tree_Example::iterate_forward (void) +{ + ACE_TRACE (ACE_TEXT ("Tree_Example::iterate_forward")); + + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Forward Iteration: \n"))); + for (Tree<int, DataElement*>::iterator iter = tree_.begin (); + iter != tree_.end (); iter++) + { + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("%d:"), + (*iter).item ()->getData ())); + } + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\n"))); +} + +void Tree_Example::iterate_reverse (void) +{ + ACE_TRACE (ACE_TEXT ("Tree_Example::iterate_reverse")); + + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Reverse Iteration: \n"))); + for (Tree<int, DataElement*>::reverse_iterator iter + = tree_.rbegin (); + iter != tree_.rend (); iter++) + { + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("%d:"), + (*iter).item ()->getData ())); + } + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\n"))); +} + +int Tree_Example::remove_all (void) +{ + ACE_TRACE (ACE_TEXT ("Tree_Example::remove_all")); + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Removing elements\n"))); + + // Note that we can't use the iterators here as they are + // invalidated after deletions or insertions. + for (int i = 0; i < 100; i++) + { + DataElement * d = 0; + int result = tree_.unbind (i, d); + if (result != 0) + { + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), + ACE_TEXT ("Unbind")), + -1); + } + ACE_ASSERT (d!= 0); + delete d; + } + + return 0; +} +// Listing 1 + +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + Tree_Example te; + return te.run (); +} + diff --git a/ACE/examples/APG/Containers/RB_Tree_Functors.cpp b/ACE/examples/APG/Containers/RB_Tree_Functors.cpp new file mode 100644 index 00000000000..cb71fd75d79 --- /dev/null +++ b/ACE/examples/APG/Containers/RB_Tree_Functors.cpp @@ -0,0 +1,134 @@ +// $Id$ + +#include "ace/Log_Msg.h" +#include "DataElement.h" +#include "RB_Tree_Functors.h" + +// Listing 0 code/ch05 +#include "ace/RB_Tree.h" +#include "ace/Synch.h" + +// Little helper class. +template<class EXT_ID, class INT_ID> +class Tree : public ACE_RB_Tree<EXT_ID, INT_ID, + ACE_Less_Than<EXT_ID>, + ACE_Null_Mutex> +{}; +// Listing 0 + +class Tree_Example +{ +public: + // Illustrate the tree. + int run (void); + +private: + // Use the forward iterator. + void iterate_forward (void); + + // Use the reverse iterator. + void iterate_reverse (void); + + // Remove all elements from the tree. + int remove_all (void); + +private: + Tree<KeyType, DataElement*> tree_; +}; + + +int Tree_Example::run () +{ + ACE_TRACE (ACE_TEXT ("Tree_Example::run")); + + DataElement *d = 0; + for (int i = 0; i < 100; i++) + { + ACE_NEW_RETURN (d, DataElement (i), -1); + int result = tree_.bind(i, d); + if (result != 0) + { + ACE_ERROR_RETURN((LM_ERROR, "%p\n", "Bind"), -1); + } + } + + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Using find: \n"))); + for (int j = 0; j < 100; j++) + { + DataElement* d = 0; + int result = tree_.find (j, d); + if (result != 0) + { + ACE_ERROR_RETURN((LM_ERROR, "%p\n", "Find"), -1); + } + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("%d:"), d->getData ())); + } + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\n"))); + + // Use the forward iterator. + this->iterate_forward (); + + // Use the reverse iterator. + this->iterate_reverse (); + + // Remove all elements from the tree. + ACE_ASSERT (this->remove_all ()!= -1); + + // Iterate through once again. + this->iterate_forward (); + + return 0; +} + +void Tree_Example::iterate_forward (void) +{ + ACE_TRACE (ACE_TEXT ("Tree_Example::iterate_forward")); + + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Forward Iteration \n"))); + for (Tree<KeyType, DataElement*>::iterator iter = tree_.begin (); + iter != tree_.end (); iter++) + { + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("%d:"), (*iter).item ()->getData ())); + } + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\n"))); +} + +void Tree_Example::iterate_reverse (void) +{ + ACE_TRACE (ACE_TEXT ("Tree_Example::iterate_reverse")); + + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Reverse Iteration \n"))); + for (Tree<KeyType, DataElement*>::reverse_iterator iter = tree_.rbegin (); + iter != tree_.rend (); iter++) + { + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("%d:"), (*iter).item ()->getData ())); + } + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\n"))); +} + +int Tree_Example::remove_all (void) +{ + ACE_TRACE (ACE_TEXT ("Tree_Example::remove_all")); + + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Removing elements\n"))); + for (int i = 0; i < 100; i++) + { + DataElement * d = 0; + int result = tree_.unbind (i, d); + if (result != 0) + { + ACE_ERROR_RETURN((LM_ERROR, "%p\n", "Unbind"), -1); + } + ACE_ASSERT (d != 0); + delete d; + } + + return 0; +} + +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + Tree_Example te; + return te.run (); +} + diff --git a/ACE/examples/APG/Containers/RB_Tree_Functors.h b/ACE/examples/APG/Containers/RB_Tree_Functors.h new file mode 100644 index 00000000000..010fb5fda62 --- /dev/null +++ b/ACE/examples/APG/Containers/RB_Tree_Functors.h @@ -0,0 +1,37 @@ +/* -*- C++ -*- */ +// $Id$ + +#ifndef __RB_TREE_FUNCTORS_H_ +#define __RB_TREE_FUNCTORS_H_ + +#include "ace/Functor.h" + +// Listing 1 code/ch05 +// Same key type. +class KeyType +{ +public: + KeyType () : val_(0) {} + KeyType (int i) : val_ (i) {} + KeyType (const KeyType& kt) { this->val_ = kt.val_; } + operator int() const { return val_; }; + +private: + int val_; +}; + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +template<> +class ACE_Less_Than<KeyType> +{ +public: + int operator() (const KeyType k1, const KeyType k2) + { return k1 < k2; } +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +// Listing 1 + +#endif /* __RB_TREE_FUNCTORS_H_ */ diff --git a/ACE/examples/APG/Containers/Sets.cpp b/ACE/examples/APG/Containers/Sets.cpp new file mode 100644 index 00000000000..3eaec6f7bec --- /dev/null +++ b/ACE/examples/APG/Containers/Sets.cpp @@ -0,0 +1,123 @@ +// $Id$ + +#include "ace/OS_Memory.h" +#include "ace/Log_Msg.h" +#include "ace/Containers.h" +#include "DataElement.h" + +class SetExample +{ +public: + // Illustrate all ACE set types. + int run (void); + +private: + // Illustrate the ACE Bounded Sets. + int runBoundedSet (void); + + // Illustrate the ACE Unbounded sets. + int runUnboundedSet (void); +}; + +int SetExample::run (void) +{ + ACE_TRACE (ACE_TEXT ("SetExample::run")); + + ACE_ASSERT (!this->runBoundedSet ()); + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\n# of live objects %d\n"), + DataElement::numOfActiveObjects ())); + + ACE_ASSERT (!this->runUnboundedSet ()); + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\n# of live objects %d\n"), + DataElement::numOfActiveObjects ())); + + return 0; +} +// Listing 1 code/ch05 +int SetExample::runBoundedSet () +{ + ACE_TRACE (ACE_TEXT ("SetExample::runBoundedSet")); + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Using a bounded set\n"))); + ACE_Bounded_Set<DataElement> bset (100); + + DataElement elem[100]; + for (int i = 0; i < 100; i++) + { + elem[i].setData (i); + + // Inserting two copies of the same element isn't allowed. + bset.insert (elem[i]); + if (bset.insert (elem[i]) == -1) + { + ACE_DEBUG ((LM_ERROR, ACE_TEXT ("%p\n"), + ACE_TEXT ("insert set"))); + } + } + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("%d\n"), + DataElement::numOfActiveObjects ())); + + DataElement elem1 (10), elem2 (99); + if (!bset.find (elem1) && !bset.find (elem2)) + { + ACE_DEBUG ((LM_INFO, + ACE_TEXT ("The elements %d and %d are ") + ACE_TEXT ("in the set!\n"), + elem1.getData (), elem2.getData ())); + } + + for (int j = 0; j < 50; j++) + { + bset.remove (elem[j]); // Remove the element from the set. + ACE_DEBUG + ((LM_DEBUG, ACE_TEXT ("%d:"), elem[j].getData ())); + } + + if ((bset.find (elem[0]) == -1) && (bset.find (elem[49]) == -1)) + { + ACE_DEBUG ((LM_INFO, + ACE_TEXT ("The elements %d and %d are ") + ACE_TEXT ("NOT in the set!\n"), + elem[0].getData (), elem[99].getData ())); + } + + return 0; +} +// Listing 1 +// Listing 2 code/ch05 +int SetExample::runUnboundedSet () +{ + ACE_TRACE (ACE_TEXT ("SetExample::runUnboundedSet")); + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Using an unbounded set.\n"))); + ACE_Unbounded_Set<DataElement*> uset; + for (int m = 0; m < 100; m++) + { + DataElement *elem; + ACE_NEW_RETURN (elem, DataElement (m), -1); + uset.insert (elem); + } + DataElement deBegin (0), deEnd (99); + if (!uset.find (&deBegin) && !uset.find (&deEnd)) + { + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Found the elements\n"))); + } + + // Iterate and destroy the elements in the set. + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Deleting the elements\n"))); + ACE_Unbounded_Set_Iterator<DataElement*> iter (uset); + for (iter = uset.begin (); iter != uset.end (); iter++) + { + DataElement* elem = (*iter); + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("%d:"), elem->getData ())); + delete elem; + } + + return 0; +} +// Listing 2 + +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + SetExample se; + se.run (); + return 0; +} diff --git a/ACE/examples/APG/Containers/Stacks.cpp b/ACE/examples/APG/Containers/Stacks.cpp new file mode 100644 index 00000000000..b02a243ab92 --- /dev/null +++ b/ACE/examples/APG/Containers/Stacks.cpp @@ -0,0 +1,147 @@ +// $Id$ + +#include "ace/OS_Memory.h" +#include "ace/Log_Msg.h" +#include "ace/Containers.h" +#include "DataElement.h" + +class StackExample +{ +public: + StackExample (): privateStack_(100) {} + + // Illustrate all the differnet + // types of stacks provided by ACE. + int run (void); + +private: + // Illustrate the use of a bounded stack. + int runBoundedStack (void); + + // Illustrate the use of an unbounded stack. + int runUnboundedStack (void); + + // Illustrate the use of a compile time fixed stack. + int runFixedStack (void); + +private: + ACE_Bounded_Stack<DataElement*> privateStack_; +}; + +int StackExample::run (void) +{ + ACE_TRACE (ACE_TEXT ("StackUser::run")); + + ACE_ASSERT(!this->runBoundedStack()); + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\n# of live objects %d\n"), + DataElement::numOfActiveObjects())); + + ACE_ASSERT(!this->runFixedStack()); + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\n# of live objects %d\n"), + DataElement::numOfActiveObjects())); + + ACE_ASSERT(!this->runUnboundedStack()); + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\n# of live objects %d\n"), + DataElement::numOfActiveObjects())); + + return 0; +} +// Listing 1 code/ch05 +int StackExample::runBoundedStack (void) +{ + ACE_TRACE (ACE_TEXT ("StackExample::runBoundedStack")); + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Using a bounded stack\n"))); + + ACE_Bounded_Stack<DataElement> bstack1 (100); + + // The element array is constrained to this scope. + { + DataElement elem[100]; + for (int i = 0; i < 100; i++) + { + elem[i].setData(i); + // Push the element on the stack. + bstack1.push (elem[i]); + } + } + + ACE_Bounded_Stack<DataElement> bstack2 (100); + + // Make a copy! + bstack2 = bstack1; + for (int j = 0; j < 100; j++) + { + DataElement elem; + bstack2.pop (elem); + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("%d:"), elem.getData ())); + } + + return 0; +} +// Listing 1 +// Listing 2 code/ch05 +int StackExample::runFixedStack (void) +{ + ACE_TRACE (ACE_TEXT ("StackExample::runFixedStack")); + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Using a fixed stack\n"))); + + ACE_Fixed_Stack<DataElement*, 100> fstack; + for (int k = 0; k < 100; k++) + { + DataElement* elem; + ACE_NEW_RETURN(elem, DataElement (k), -1); + fstack.push (elem); // Push the element on the stack. + } + + for (int l = 0; l < 100; l++) + { + DataElement* elem = 0; + fstack.pop (elem); + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("%d:"), elem->getData ())); + delete elem; + } + + return 0; +} + +int StackExample::runUnboundedStack (void) +{ + ACE_TRACE (ACE_TEXT ("StackExample::runUnboundedStack")); + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Using an unbounded stack\n"))); + + ACE_Unbounded_Stack<DataElement*> ustack; + for (int m = 0; m < 100; m++) + { + DataElement *elem; + ACE_NEW_RETURN(elem, DataElement (m), -1); + // Push the element on both stacks. + ustack.push (elem); + privateStack_.push (elem); + } + + // Oddly enough, you can actually iterate through an + // unbounded stack! This is because underneath the covers + // the unbounded stack is a linked list. + + // This will cause the elements in the private stack to + // also disappear! + ACE_Unbounded_Stack_Iterator<DataElement*> iter (ustack); + for (iter.first (); !iter.done (); iter.advance ()) + { + DataElement** elem = 0; + iter.next (elem); + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("%d:"), + (*elem)->getData ())); + delete (*elem); + } + + return 0; +} +// Listing 2 + +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + StackExample se; + return se.run (); +} + diff --git a/ACE/examples/APG/Containers/containers.mpc b/ACE/examples/APG/Containers/containers.mpc new file mode 100644 index 00000000000..d08ef9133aa --- /dev/null +++ b/ACE/examples/APG/Containers/containers.mpc @@ -0,0 +1,87 @@ +// -*- MPC -*- +// $Id$ + +project(DLList) : aceexe { + avoids += ace_for_tao + exename = DLList + Source_Files { + DLList.cpp + } +} + +project(Stacks) : aceexe { + exename = Stacks + Source_Files { + Stacks.cpp + } +} + +project(Queues) : aceexe { + exename = Queues + Source_Files { + Queues.cpp + } +} + +project(Array) : aceexe { + exename = Array + Source_Files { + Array.cpp + } +} + +project(Sets) : aceexe { + exename = Sets + Source_Files { + Sets.cpp + } +} + +project(*Map Manager) : aceexe { + exename = Map_Manager + Source_Files { + Map_Manager.cpp + } +} + +project(Map Manager Specialization) : aceexe { + exename = Map_Manager_Specialization + Source_Files { + Map_Manager_Specialization.cpp + } +} + +project(*Hash Map) : aceexe { + exename = Hash_Map + Source_Files { + Hash_Map.cpp + } +} + +project(Hash Map Hash) : aceexe { + exename = Hash_Map_Hash + Source_Files { + Hash_Map_Hash.cpp + } +} + +project(RB Tree) : aceexe { + exename = RB_Tree + Source_Files { + RB_Tree.cpp + } +} + +project(RB Tree Functors) : aceexe { + exename = RB_Tree_Functors + Source_Files { + RB_Tree_Functors.cpp + } +} + +project(Allocator) : aceexe { + exename = Allocator + Source_Files { + Allocator.cpp + } +} diff --git a/ACE/examples/APG/Logging/.cvsignore b/ACE/examples/APG/Logging/.cvsignore new file mode 100644 index 00000000000..821ee0bc87c --- /dev/null +++ b/ACE/examples/APG/Logging/.cvsignore @@ -0,0 +1,36 @@ +Change_Instance_Default +Change_Instance_Default +Change_Mask +Change_Mask +Howto_Syslog +Howto_Syslog +Simple1 +Simple1 +Simple2 +Simple2 +Trace_Return +Trace_Return +Use_Callback +Use_Callback +Use_Callback2 +Use_Callback2 +Use_LogManager +Use_LogManager +Use_Logger +Use_Logger +Use_Logging_Server +Use_Logging_Server +Use_Logging_Strategy +Use_Logging_Strategy +Use_Multiple_Sinks +Use_Multiple_Sinks +Use_Ostream +Use_Ostream +Use_Stderr +Use_Stderr +Use_Syslog +Use_Syslog +Wrap_Macros +Wrap_Macros +Wrap_Macros_Alt +Wrap_Macros_Alt diff --git a/ACE/examples/APG/Logging/Callback-2.h b/ACE/examples/APG/Logging/Callback-2.h new file mode 100644 index 00000000000..906b2e43286 --- /dev/null +++ b/ACE/examples/APG/Logging/Callback-2.h @@ -0,0 +1,44 @@ +// $Id$ + +#ifndef APG_CALLBACK2_H +#define APG_CALLBACK2_H + +#include "ace/OS_NS_time.h" +#include "ace/streams.h" +#include "ace/Log_Msg_Callback.h" +#include "ace/Log_Record.h" +#include "ace/SString.h" +#include "ace/Time_Value.h" + +class Callback : public ACE_Log_Msg_Callback +{ +public: + void log (ACE_Log_Record &log_record) + { + cerr << "Log Message Received:" << endl; + unsigned long msg_severity = log_record.type (); + ACE_Log_Priority prio = + static_cast<ACE_Log_Priority> (msg_severity); + const ACE_TCHAR *prio_name = + ACE_Log_Record::priority_name (prio); + cerr << "\tType: " + << ACE_TEXT_ALWAYS_CHAR (prio_name) + << endl; + + cerr << "\tLength: " << log_record.length () << endl; + + const time_t epoch = log_record.time_stamp ().sec (); + cerr << "\tTime_Stamp: " + << ACE_TEXT_ALWAYS_CHAR (ACE_OS::ctime (&epoch)) + << flush; + + cerr << "\tPid: " << log_record.pid () << endl; + + ACE_CString data (">> "); + data += ACE_TEXT_ALWAYS_CHAR (log_record.msg_data ()); + + cerr << "\tMsgData: " << data.c_str () << endl; + } +}; + +#endif /* APG_CALLBACK2_H */ diff --git a/ACE/examples/APG/Logging/Callback-3.h b/ACE/examples/APG/Logging/Callback-3.h new file mode 100644 index 00000000000..22824fad382 --- /dev/null +++ b/ACE/examples/APG/Logging/Callback-3.h @@ -0,0 +1,69 @@ +// $Id$ + +#ifndef APG_CALLBACK3_H +#define APG_CALLBACK3_H + +#include "ace/streams.h" +#include "ace/Log_Msg.h" +#include "ace/Log_Msg_Callback.h" +#include "ace/Log_Record.h" +#include "ace/SOCK_Stream.h" +#include "ace/SOCK_Connector.h" +#include "ace/INET_Addr.h" + +#define LOGGER_PORT 20009 + +class Callback : public ACE_Log_Msg_Callback +{ +public: + Callback () + { + this->logger_ = new ACE_SOCK_Stream; + ACE_SOCK_Connector connector; + ACE_INET_Addr addr (LOGGER_PORT, ACE_DEFAULT_SERVER_HOST); + + if (connector.connect (*(this->logger_), addr) == -1) + { + delete this->logger_; + this->logger_ = 0; + } + } + + virtual ~Callback () + { + if (this->logger_) + { + this->logger_->close (); + } + delete this->logger_; + } + + void log (ACE_Log_Record &log_record) + { + if (!this->logger_) + { +# if defined (ACE_LACKS_IOSTREAM_TOTALLY) + log_record.print + (ACE_TEXT (""), ACE_Log_Msg::VERBOSE, stderr); +# else + log_record.print + (ACE_TEXT (""), ACE_Log_Msg::VERBOSE, cerr); +# endif /* ACE_LACKS_IOSTREAM_TOTALLY */ + return; + } + + size_t len = log_record.length(); + log_record.encode (); + + if (this->logger_->send_n ((char *) &log_record, len) == -1) + { + delete this->logger_; + this->logger_ = 0; + } + } + +private: + ACE_SOCK_Stream *logger_; +}; + +#endif /* APG_CALLBACK3_H */ diff --git a/ACE/examples/APG/Logging/Callback.h b/ACE/examples/APG/Logging/Callback.h new file mode 100644 index 00000000000..86dff9ea826 --- /dev/null +++ b/ACE/examples/APG/Logging/Callback.h @@ -0,0 +1,25 @@ +// $Id$ + +#ifndef APG_CALLBACK_H +#define APG_CALLBACK_H + +#include "ace/streams.h" +#include "ace/Log_Msg.h" +#include "ace/Log_Msg_Callback.h" +#include "ace/Log_Record.h" + +class Callback : public ACE_Log_Msg_Callback +{ +public: + void log (ACE_Log_Record &log_record) { +# if defined (ACE_LACKS_IOSTREAM_TOTALLY) + log_record.print (ACE_TEXT (""), 0, stderr); + log_record.print (ACE_TEXT (""), ACE_Log_Msg::VERBOSE, stderr); +# else + log_record.print (ACE_TEXT (""), 0, cerr); + log_record.print (ACE_TEXT (""), ACE_Log_Msg::VERBOSE, cerr); +# endif /* ACE_LACKS_IOSTREAM_TOTALLY */ + } +}; + +#endif /* APG_CALLBACK_H */ diff --git a/ACE/examples/APG/Logging/Change_Instance_Default.cpp b/ACE/examples/APG/Logging/Change_Instance_Default.cpp new file mode 100644 index 00000000000..e22af840259 --- /dev/null +++ b/ACE/examples/APG/Logging/Change_Instance_Default.cpp @@ -0,0 +1,37 @@ +/** + * $Id$ + * + * Sample code from The ACE Programmer's Guide, + * Copyright 2003 Addison-Wesley. All Rights Reserved. + * + * This code shows how to set the ACE_Log_Msg per-instance default + * differently for groups of spawned threads. + */ + +#include "ace/Log_Msg.h" +#include "ace/Thread_Manager.h" + +ACE_THR_FUNC_RETURN worker (void *) +{ + // do some work + return 0; +} + +ACE_THR_FUNC_RETURN service (void *) +{ + // run the service + return 0; +} + +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + // Listing 1 code/ch03 + ACE_LOG_MSG->priority_mask (0, ACE_Log_Msg::PROCESS); + ACE_Log_Msg::enable_debug_messages (); + ACE_Thread_Manager::instance ()->spawn (service); + ACE_Log_Msg::disable_debug_messages (); + ACE_Thread_Manager::instance ()->spawn_n (3, worker); + // Listing 1 + ACE_Thread_Manager::instance ()->wait (); + return 0; +} diff --git a/ACE/examples/APG/Logging/Change_Mask.cpp b/ACE/examples/APG/Logging/Change_Mask.cpp new file mode 100644 index 00000000000..a34a00e63b1 --- /dev/null +++ b/ACE/examples/APG/Logging/Change_Mask.cpp @@ -0,0 +1,29 @@ +// $Id$ + +#include "ace/Log_Msg.h" + +void foo (void); + +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_TRACE ("main"); + + // Listing 1 code/ch03 + ACE_LOG_MSG->priority_mask (0, ACE_Log_Msg::PROCESS); + ACE_LOG_MSG->priority_mask (LM_DEBUG | LM_NOTICE, + ACE_Log_Msg::THREAD); + // Listing 1 + + ACE_DEBUG ((LM_INFO, ACE_TEXT ("%IHi Mom\n"))); + foo (); + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("%IGoodnight\n"))); + + return 0; +} + +void foo (void) +{ + ACE_TRACE ("foo"); + + ACE_DEBUG ((LM_NOTICE, ACE_TEXT ("%IHowdy Pardner\n"))); +} diff --git a/ACE/examples/APG/Logging/Howto_Syslog.cpp b/ACE/examples/APG/Logging/Howto_Syslog.cpp new file mode 100644 index 00000000000..283099a3da1 --- /dev/null +++ b/ACE/examples/APG/Logging/Howto_Syslog.cpp @@ -0,0 +1,28 @@ +// $Id$ + +#include "ace/Log_Msg.h" + +void foo (void); + +// Listing 1 code/ch03 +int ACE_TMAIN (int, ACE_TCHAR *argv[]) +{ + ACE_LOG_MSG->open + (argv[0], ACE_Log_Msg::SYSLOG, ACE_TEXT ("syslogTest")); + // Listing 1 + + ACE_TRACE ("main"); + + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("%IHi Mom\n"))); + foo (); + ACE_DEBUG ((LM_INFO, ACE_TEXT ("%IGoodnight\n"))); + + return 0; +} + +void foo (void) +{ + ACE_TRACE ("foo"); + + ACE_DEBUG ((LM_INFO, ACE_TEXT ("%IHowdy Pardner\n"))); +} diff --git a/ACE/examples/APG/Logging/LogManager.h b/ACE/examples/APG/Logging/LogManager.h new file mode 100644 index 00000000000..2cf8c7f7d48 --- /dev/null +++ b/ACE/examples/APG/Logging/LogManager.h @@ -0,0 +1,102 @@ +// $Id$ + +#include "ace/streams.h" +#include "ace/Synch.h" +#include "ace/Singleton.h" +#include "ace/Log_Msg.h" +#include "ace/Log_Msg_Callback.h" + +#ifndef LOG_MANAGER_H +#define LOG_MANAGER_H + +// Listing 1 code/ch03 +class LogManager +{ +public: + LogManager (); + ~LogManager (); + + void redirectToDaemon + (const ACE_TCHAR *prog_name = ACE_TEXT ("")); + void redirectToSyslog + (const ACE_TCHAR *prog_name = ACE_TEXT ("")); + void redirectToOStream (ACE_OSTREAM_TYPE *output); + void redirectToFile (const char *filename); + void redirectToStderr (void); + ACE_Log_Msg_Callback * redirectToCallback + (ACE_Log_Msg_Callback *callback); + + // Exclude 1 +private: + ofstream *log_stream_; + ACE_OSTREAM_TYPE *output_stream_; + // Exclude 1 +}; +// Listing 1 + +// Listing 2 code/ch03 +LogManager::LogManager () + : log_stream_ (0), output_stream_ (0) +{ } + +LogManager::~LogManager () +{ + if (log_stream_) + log_stream_->close (); + delete log_stream_; +} + +void LogManager::redirectToSyslog (const ACE_TCHAR *prog_name) +{ + ACE_LOG_MSG->open (prog_name, ACE_Log_Msg::SYSLOG, prog_name); +} + +void LogManager::redirectToDaemon (const ACE_TCHAR *prog_name) +{ + ACE_LOG_MSG->open (prog_name, ACE_Log_Msg::LOGGER, + ACE_DEFAULT_LOGGER_KEY); +} + +void LogManager::redirectToOStream (ACE_OSTREAM_TYPE *output) +{ + output_stream_ = output; + ACE_LOG_MSG->msg_ostream (this->output_stream_); + ACE_LOG_MSG->clr_flags + (ACE_Log_Msg::STDERR | ACE_Log_Msg::LOGGER); + ACE_LOG_MSG->set_flags (ACE_Log_Msg::OSTREAM); +} + +void LogManager::redirectToFile (const char *filename) +{ + log_stream_ = new ofstream (); + log_stream_->open (filename, ios::out | ios::app); + this->redirectToOStream ((ACE_OSTREAM_TYPE *)log_stream_); +} + +void LogManager::redirectToStderr (void) +{ + ACE_LOG_MSG->clr_flags + (ACE_Log_Msg::OSTREAM | ACE_Log_Msg::LOGGER); + ACE_LOG_MSG->set_flags (ACE_Log_Msg::STDERR); +} + +ACE_Log_Msg_Callback * +LogManager::redirectToCallback (ACE_Log_Msg_Callback * callback) +{ + ACE_Log_Msg_Callback *previous = + ACE_LOG_MSG->msg_callback (callback); + if (callback == 0) + ACE_LOG_MSG->clr_flags (ACE_Log_Msg::MSG_CALLBACK); + else + ACE_LOG_MSG->set_flags (ACE_Log_Msg::MSG_CALLBACK); + return previous; +} +// Listing 2 + +// Listing 3 code/ch03 +typedef ACE_Singleton<LogManager, ACE_Null_Mutex> + LogManagerSingleton; +#define LOG_MANAGER LogManagerSingleton::instance() +// Listing 3 + +#endif /* LOG_MANAGER_H */ diff --git a/ACE/examples/APG/Logging/Log_Msg_Alt.h b/ACE/examples/APG/Logging/Log_Msg_Alt.h new file mode 100644 index 00000000000..c78d2bd1f4a --- /dev/null +++ b/ACE/examples/APG/Logging/Log_Msg_Alt.h @@ -0,0 +1,19 @@ +// $Id$ + +#ifndef LOG_MSG_ALT_H +#define LOG_MSG_ALT_H + +#include "ace/Log_Msg.h" + +// Listing 1 code/ch03 +#define MY_DEBUG LM_DEBUG, ACE_TEXT ("DEBUG%I") +#define MY_INFO LM_INFO, ACE_TEXT ("INFO%I") +#define MY_NOTICE LM_NOTICE, ACE_TEXT ("NOTICE%I") +#define MY_WARNING LM_WARNING, ACE_TEXT ("WARNING%I") +#define MY_ERROR LM_ERROR, ACE_TEXT ("ERROR%I") +#define MY_CRITICAL LM_CRITICAL, ACE_TEXT ("CRITICAL%I") +#define MY_ALERT LM_ALERT, ACE_TEXT ("ALERT%I") +#define MY_EMERGENCY LM_EMERGENCY, ACE_TEXT ("EMERGENCY%I") +// Listing 1 + +#endif /* LOG_ALT_H */ diff --git a/ACE/examples/APG/Logging/Makefile.am b/ACE/examples/APG/Logging/Makefile.am new file mode 100644 index 00000000000..69564edb197 --- /dev/null +++ b/ACE/examples/APG/Logging/Makefile.am @@ -0,0 +1,362 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +ACE_BUILDDIR = $(top_builddir) +ACE_ROOT = $(top_srcdir) + +## Makefile.Change_Instance_Default.am +noinst_PROGRAMS = Change_Instance_Default + +Change_Instance_Default_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +Change_Instance_Default_SOURCES = \ + Change_Instance_Default.cpp \ + Callback-2.h \ + Callback-3.h \ + Callback.h \ + LogManager.h \ + Log_Msg_Alt.h \ + Trace.h + +Change_Instance_Default_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Change_Mask.am +noinst_PROGRAMS += Change_Mask + +Change_Mask_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +Change_Mask_SOURCES = \ + Change_Mask.cpp \ + Callback-2.h \ + Callback-3.h \ + Callback.h \ + LogManager.h \ + Log_Msg_Alt.h \ + Trace.h + +Change_Mask_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Howto_Syslog.am +noinst_PROGRAMS += Howto_Syslog + +Howto_Syslog_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +Howto_Syslog_SOURCES = \ + Howto_Syslog.cpp \ + Callback-2.h \ + Callback-3.h \ + Callback.h \ + LogManager.h \ + Log_Msg_Alt.h \ + Trace.h + +Howto_Syslog_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Simple1.am +noinst_PROGRAMS += Simple1 + +Simple1_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +Simple1_SOURCES = \ + Simple1.cpp \ + Callback-2.h \ + Callback-3.h \ + Callback.h \ + LogManager.h \ + Log_Msg_Alt.h \ + Trace.h + +Simple1_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Simple2.am +noinst_PROGRAMS += Simple2 + +Simple2_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +Simple2_SOURCES = \ + Simple2.cpp \ + Callback-2.h \ + Callback-3.h \ + Callback.h \ + LogManager.h \ + Log_Msg_Alt.h \ + Trace.h + +Simple2_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Trace_Return.am +noinst_PROGRAMS += Trace_Return + +Trace_Return_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +Trace_Return_SOURCES = \ + Trace_Return.cpp \ + Callback-2.h \ + Callback-3.h \ + Callback.h \ + LogManager.h \ + Log_Msg_Alt.h \ + Trace.h + +Trace_Return_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Use_Callback.am +noinst_PROGRAMS += Use_Callback + +Use_Callback_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +Use_Callback_SOURCES = \ + Use_Callback.cpp \ + Callback-2.h \ + Callback-3.h \ + Callback.h \ + LogManager.h \ + Log_Msg_Alt.h \ + Trace.h + +Use_Callback_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Use_Callback2.am +noinst_PROGRAMS += Use_Callback2 + +Use_Callback2_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +Use_Callback2_SOURCES = \ + Use_Callback2.cpp \ + Callback-2.h \ + Callback-3.h \ + Callback.h \ + LogManager.h \ + Log_Msg_Alt.h \ + Trace.h + +Use_Callback2_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Use_LogManager.am +noinst_PROGRAMS += Use_LogManager + +Use_LogManager_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +Use_LogManager_SOURCES = \ + Use_LogManager.cpp \ + Callback-2.h \ + Callback-3.h \ + Callback.h \ + LogManager.h \ + Log_Msg_Alt.h \ + Trace.h + +Use_LogManager_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Use_Logger.am +noinst_PROGRAMS += Use_Logger + +Use_Logger_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +Use_Logger_SOURCES = \ + Use_Logger.cpp \ + Callback-2.h \ + Callback-3.h \ + Callback.h \ + LogManager.h \ + Log_Msg_Alt.h \ + Trace.h + +Use_Logger_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Use_Logging_Server.am +noinst_PROGRAMS += Use_Logging_Server + +Use_Logging_Server_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +Use_Logging_Server_SOURCES = \ + Use_Logging_Server.cpp \ + Callback-2.h \ + Callback-3.h \ + Callback.h \ + LogManager.h \ + Log_Msg_Alt.h \ + Trace.h + +Use_Logging_Server_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Use_Logging_Strategy.am +noinst_PROGRAMS += Use_Logging_Strategy + +Use_Logging_Strategy_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +Use_Logging_Strategy_SOURCES = \ + Use_Logging_Strategy.cpp \ + Callback-2.h \ + Callback-3.h \ + Callback.h \ + LogManager.h \ + Log_Msg_Alt.h \ + Trace.h + +Use_Logging_Strategy_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Use_Multiple_Sinks.am +noinst_PROGRAMS += Use_Multiple_Sinks + +Use_Multiple_Sinks_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +Use_Multiple_Sinks_SOURCES = \ + Use_Multiple_Sinks.cpp \ + Callback-2.h \ + Callback-3.h \ + Callback.h \ + LogManager.h \ + Log_Msg_Alt.h \ + Trace.h + +Use_Multiple_Sinks_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Use_Ostream.am +noinst_PROGRAMS += Use_Ostream + +Use_Ostream_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +Use_Ostream_SOURCES = \ + Use_Ostream.cpp \ + Callback-2.h \ + Callback-3.h \ + Callback.h \ + LogManager.h \ + Log_Msg_Alt.h \ + Trace.h + +Use_Ostream_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Use_Stderr.am +noinst_PROGRAMS += Use_Stderr + +Use_Stderr_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +Use_Stderr_SOURCES = \ + Use_Stderr.cpp \ + Callback-2.h \ + Callback-3.h \ + Callback.h \ + LogManager.h \ + Log_Msg_Alt.h \ + Trace.h + +Use_Stderr_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Use_Syslog.am +noinst_PROGRAMS += Use_Syslog + +Use_Syslog_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +Use_Syslog_SOURCES = \ + Use_Syslog.cpp \ + Callback-2.h \ + Callback-3.h \ + Callback.h \ + LogManager.h \ + Log_Msg_Alt.h \ + Trace.h + +Use_Syslog_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Wrap_Macros.am +noinst_PROGRAMS += Wrap_Macros + +Wrap_Macros_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +Wrap_Macros_SOURCES = \ + Wrap_Macros.cpp \ + Callback-2.h \ + Callback-3.h \ + Callback.h \ + LogManager.h \ + Log_Msg_Alt.h \ + Trace.h + +Wrap_Macros_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Wrap_Macros_Alt.am +noinst_PROGRAMS += Wrap_Macros_Alt + +Wrap_Macros_Alt_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +Wrap_Macros_Alt_SOURCES = \ + Wrap_Macros_Alt.cpp \ + Callback-2.h \ + Callback-3.h \ + Callback.h \ + LogManager.h \ + Log_Msg_Alt.h \ + Trace.h + +Wrap_Macros_Alt_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Clean up template repositories, etc. +clean-local: + -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.* + -rm -f gcctemp.c gcctemp so_locations *.ics + -rm -rf cxx_repository ptrepository ti_files + -rm -rf templateregistry ir.out + -rm -rf ptrepository SunWS_cache Templates.DB diff --git a/ACE/examples/APG/Logging/Simple1.cpp b/ACE/examples/APG/Logging/Simple1.cpp new file mode 100644 index 00000000000..cf7a12e410b --- /dev/null +++ b/ACE/examples/APG/Logging/Simple1.cpp @@ -0,0 +1,23 @@ +// $Id$ + +#include "ace/Log_Msg.h" + +void foo (void); + +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_TRACE("main"); + + ACE_DEBUG ((LM_INFO, ACE_TEXT ("%IHi Mom\n"))); + foo(); + ACE_DEBUG ((LM_INFO, ACE_TEXT ("%IGoodnight\n"))); + + return 0; +} + +void foo (void) +{ + ACE_TRACE ("foo"); + + ACE_DEBUG ((LM_INFO, ACE_TEXT ("%IHowdy Pardner\n"))); +} diff --git a/ACE/examples/APG/Logging/Simple2.cpp b/ACE/examples/APG/Logging/Simple2.cpp new file mode 100644 index 00000000000..26315b9d689 --- /dev/null +++ b/ACE/examples/APG/Logging/Simple2.cpp @@ -0,0 +1,25 @@ +// $Id$ + +#include "ace/Log_Msg.h" + +void foo(void); + +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_TRACE ("main"); + + ACE_LOG_MSG->priority_mask (LM_DEBUG | LM_NOTICE, + ACE_Log_Msg::PROCESS); + ACE_DEBUG ((LM_INFO, ACE_TEXT ("%IHi Mom\n"))); + foo (); + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("%IGoodnight\n"))); + + return 0; +} + +void foo(void) +{ + ACE_TRACE ("foo"); + + ACE_DEBUG ((LM_NOTICE, ACE_TEXT ("%IHowdy Pardner\n"))); +} diff --git a/ACE/examples/APG/Logging/Trace.h b/ACE/examples/APG/Logging/Trace.h new file mode 100644 index 00000000000..c7f40c343eb --- /dev/null +++ b/ACE/examples/APG/Logging/Trace.h @@ -0,0 +1,153 @@ +// $Id$ + +#ifndef TRACE_H +#define TRACE_H + +#include "ace/Log_Msg.h" + +// Listing 1 code/ch03 +class Trace +{ +public: + Trace (const ACE_TCHAR *prefix, + const ACE_TCHAR *name, + int line, + const ACE_TCHAR *file) + { + this->prefix_ = prefix; + this->name_ = name; + this->line_ = line; + this->file_ = file; + + ACE_Log_Msg *lm = ACE_LOG_MSG; + if (lm->tracing_enabled () + && lm->trace_active () == 0) + { + lm->trace_active (1); + ACE_DEBUG + ((LM_TRACE, + ACE_TEXT ("%s%*s(%t) calling %s in file `%s'") + ACE_TEXT (" on line %d\n"), + this->prefix_, + Trace::nesting_indent_ * lm->inc (), + ACE_TEXT (""), + this->name_, + this->file_, + this->line_)); + lm->trace_active (0); + } + } + + void setLine (int line) + { + this->line_ = line; + } + + ~Trace (void) + { + ACE_Log_Msg *lm = ACE_LOG_MSG; + if (lm->tracing_enabled () + && lm->trace_active () == 0) + { + lm->trace_active (1); + ACE_DEBUG + ((LM_TRACE, + ACE_TEXT ("%s%*s(%t) leaving %s in file `%s'") + ACE_TEXT (" on line %d\n"), + this->prefix_, + Trace::nesting_indent_ * lm->dec (), + ACE_TEXT (""), + this->name_, + this->file_, + this->line_)); + lm->trace_active (0); + } + } + +private: + enum { nesting_indent_ = 3 }; + + const ACE_TCHAR *prefix_; + const ACE_TCHAR *name_; + const ACE_TCHAR *file_; + int line_; +}; +// Listing 1 + +// Listing 2 code/ch03 +#define TRACE_PREFIX ACE_TEXT ("TRACE ") + +#if (ACE_NTRACE == 1) +# define TRACE(X) +# define TRACE_RETURN(V) return V; +# define TRACE_RETURN_VOID() +#else +# define TRACE(X) \ + Trace ____ (TRACE_PREFIX, \ + ACE_TEXT (X), \ + __LINE__, \ + ACE_TEXT (__FILE__)) + +# define TRACE_RETURN(V) \ + do { ____.setLine(__LINE__); return V; } while (0) + +# define TRACE_RETURN_VOID() \ + do { ____.setLine(__LINE__); } while (0) +#endif +// Listing 2 + +////////////////////////////////////////////////// + +#if defined (__GNUC__) && (__GNUC__ >= 3 || __GNUC_MINOR__ > 95) && \ + (!defined (VXWORKS) || !(__GNUC__ == 2 && __GNUC_MINOR__ == 96)) +// This stuff only works with g++ 2.96 and later... +// But not with VxWorks g++ 2.96. + +// Listing 3 code/ch03 + +#define DEBUG_PREFIX ACE_TEXT ("DEBUG%I") +#define INFO_PREFIX ACE_TEXT ("INFO%I") +#define NOTICE_PREFIX ACE_TEXT ("NOTICE%I") +#define WARNING_PREFIX ACE_TEXT ("WARNING%I") +#define ERROR_PREFIX ACE_TEXT ("ERROR%I") +#define CRITICAL_PREFIX ACE_TEXT ("CRITICAL%I") +#define ALERT_PREFIX ACE_TEXT ("ALERT%I") +#define EMERGENCY_PREFIX ACE_TEXT ("EMERGENCY%I") + +#define MY_DEBUG(FMT, ...) \ + ACE_DEBUG(( LM_DEBUG, \ + DEBUG_PREFIX FMT \ + ##__VA_ARGS__)) +#define MY_INFO(FMT, ...) \ + ACE_DEBUG(( LM_INFO, \ + INFO_PREFIX FMT \ + ##__VA_ARGS__)) +#define MY_NOTICE(FMT, ...) \ + ACE_DEBUG(( LM_NOTICE, \ + NOTICE_PREFIX FMT \ + ##__VA_ARGS__)) +#define MY_WARNING(FMT, ...) \ + ACE_DEBUG(( LM_WARNING, \ + WARNING_PREFIX FMT \ + ##__VA_ARGS__)) +#define MY_ERROR(FMT, ...) \ + ACE_DEBUG(( LM_ERROR, \ + ERROR_PREFIX FMT \ + ##__VA_ARGS__)) +#define MY_CRITICAL(FMT, ...) \ + ACE_DEBUG(( LM_CRITICAL, \ + CRITICAL_PREFIX FMT \ + ##__VA_ARGS__)) +#define MY_ALERT(FMT, ...) \ + ACE_DEBUG(( LM_ALERT, \ + ALERT_PREFIX FMT \ + ##__VA_ARGS__)) +#define MY_EMERGENCY(FMT, ...) \ + ACE_DEBUG(( LM_EMERGENCY, \ + EMERGENCY_PREFIX FMT \ + ##__VA_ARGS__)) +// Listing 3 + +#endif /* __GNUC__ */ + +#endif /* TRACE_H */ diff --git a/ACE/examples/APG/Logging/Trace_Return.cpp b/ACE/examples/APG/Logging/Trace_Return.cpp new file mode 100644 index 00000000000..1bb32a03456 --- /dev/null +++ b/ACE/examples/APG/Logging/Trace_Return.cpp @@ -0,0 +1,41 @@ +// $Id$ + +#include "Trace.h" + +#if defined (__GNUC__) && (__GNUC__ >= 3 || __GNUC_MINOR__ > 95) && \ + (!defined (VXWORKS) || !(__GNUC__ == 2 && __GNUC_MINOR__ == 96)) +// The DEBUG stuff only works with g++ 2.96 and later. +// But not with VxWorks g++ 2.96. + +// Listing 1 code/ch03 +void foo (void); + +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + TRACE ("main"); + + MY_DEBUG (ACE_TEXT ("Hi Mom\n")); + foo (); + MY_DEBUG (ACE_TEXT ("Goodnight\n")); + + TRACE_RETURN (0); +} + +void foo (void) +{ + TRACE ("foo"); + MY_DEBUG (ACE_TEXT ("Howdy Pardner\n")); + TRACE_RETURN_VOID (); +} +// Listing 1 + +#else +#include <stdio.h> + +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + puts ("This example only works on g++ 2.96 and later.\n"); + return 0; +} + +#endif /* __GNUC__ */ diff --git a/ACE/examples/APG/Logging/Use_Callback.cpp b/ACE/examples/APG/Logging/Use_Callback.cpp new file mode 100644 index 00000000000..2f08a2127ed --- /dev/null +++ b/ACE/examples/APG/Logging/Use_Callback.cpp @@ -0,0 +1,20 @@ +// $Id$ + +#include "ace/Log_Msg.h" +#include "Callback.h" + +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + Callback *callback = new Callback; + + ACE_LOG_MSG->set_flags (ACE_Log_Msg::MSG_CALLBACK); + ACE_LOG_MSG->clr_flags (ACE_Log_Msg::STDERR); + ACE_LOG_MSG->msg_callback (callback); + + ACE_TRACE ("main"); + + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("%IHi Mom\n"))); + ACE_DEBUG ((LM_INFO, ACE_TEXT ("%IGoodnight\n"))); + + return 0; +} diff --git a/ACE/examples/APG/Logging/Use_Callback2.cpp b/ACE/examples/APG/Logging/Use_Callback2.cpp new file mode 100644 index 00000000000..bcfe8b8e5d7 --- /dev/null +++ b/ACE/examples/APG/Logging/Use_Callback2.cpp @@ -0,0 +1,20 @@ +// $Id$ + +#include "ace/Log_Msg.h" +#include "Callback-2.h" + +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + Callback *callback = new Callback; + + ACE_LOG_MSG->set_flags (ACE_Log_Msg::MSG_CALLBACK); + ACE_LOG_MSG->clr_flags (ACE_Log_Msg::STDERR); + ACE_LOG_MSG->msg_callback (callback); + + ACE_TRACE ("main"); + + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("%IHi Mom\n"))); + ACE_DEBUG ((LM_INFO, ACE_TEXT ("%IGoodnight\n"))); + + return 0; +} diff --git a/ACE/examples/APG/Logging/Use_LogManager.cpp b/ACE/examples/APG/Logging/Use_LogManager.cpp new file mode 100644 index 00000000000..76de7b7fb56 --- /dev/null +++ b/ACE/examples/APG/Logging/Use_LogManager.cpp @@ -0,0 +1,33 @@ +// $Id$ + +#include "LogManager.h" + +// Listing 1 code/ch03 +void foo (void); + +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + LOG_MANAGER->redirectToStderr (); + ACE_TRACE ("main"); + LOG_MANAGER->redirectToSyslog (); + ACE_DEBUG ((LM_INFO, ACE_TEXT ("%IHi Mom\n"))); + foo (); + LOG_MANAGER->redirectToDaemon (); + ACE_DEBUG ((LM_INFO, ACE_TEXT ("%IGoodnight\n"))); + + return 0; +} +void foo (void) +{ + ACE_TRACE ("foo"); + LOG_MANAGER->redirectToFile ("output.test"); + ACE_DEBUG ((LM_INFO, ACE_TEXT ("%IHowdy Pardner\n"))); +} +// Listing 1 + +// Listing 2 code/ch03 +#if defined (ACE_HAS_EXPLICIT_STATIC_TEMPLATE_MEMBER_INSTANTIATION) +template ACE_Singleton<LogManager, ACE_Null_Mutex> * + ACE_Singleton<LogManager, ACE_Null_Mutex>::singleton_; +#endif /* ACE_HAS_EXPLICIT_STATIC_TEMPLATE_MEMBER_INSTANTIATION */ +// Listing 2 diff --git a/ACE/examples/APG/Logging/Use_Logger.cpp b/ACE/examples/APG/Logging/Use_Logger.cpp new file mode 100644 index 00000000000..5fb672c1ab4 --- /dev/null +++ b/ACE/examples/APG/Logging/Use_Logger.cpp @@ -0,0 +1,17 @@ +// $Id$ + +#include "ace/Log_Msg.h" + +int ACE_TMAIN (int, ACE_TCHAR *argv[]) +{ + ACE_LOG_MSG->open (argv[0], + ACE_Log_Msg::LOGGER, + ACE_DEFAULT_LOGGER_KEY); + + ACE_TRACE ("main"); + + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("%IHi Mom\n"))); + ACE_DEBUG ((LM_INFO, ACE_TEXT ("%IGoodnight\n"))); + + return 0; +} diff --git a/ACE/examples/APG/Logging/Use_Logging_Server.cpp b/ACE/examples/APG/Logging/Use_Logging_Server.cpp new file mode 100644 index 00000000000..eaad6bf7a6b --- /dev/null +++ b/ACE/examples/APG/Logging/Use_Logging_Server.cpp @@ -0,0 +1,20 @@ +// $Id$ + +#include "ace/Log_Msg.h" +#include "Callback-3.h" + +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + Callback *callback = new Callback; + + ACE_LOG_MSG->set_flags (ACE_Log_Msg::MSG_CALLBACK); + ACE_LOG_MSG->clr_flags (ACE_Log_Msg::STDERR); + ACE_LOG_MSG->msg_callback (callback); + + ACE_TRACE ("main"); + + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("%IHi Mom\n"))); + ACE_DEBUG ((LM_INFO, ACE_TEXT ("%IGoodnight\n"))); + + return 0; +} diff --git a/ACE/examples/APG/Logging/Use_Logging_Strategy.cpp b/ACE/examples/APG/Logging/Use_Logging_Strategy.cpp new file mode 100644 index 00000000000..559d85d65ae --- /dev/null +++ b/ACE/examples/APG/Logging/Use_Logging_Strategy.cpp @@ -0,0 +1,33 @@ +// $Id$ + +#include "ace/Log_Msg.h" +#include "ace/Service_Config.h" + +/* + Put the following in your svc.conf: + + dynamic Logger Service_Object * ACE:_make_ACE_Logging_Strategy() "-s log.out -f STDERR|OSTREAM -p DEBUG|NOTICE" + + There seems to be a bug in ACE_Logging_Strategy in that the priority + flags are not propagated to spawned threads. +*/ + +// Listing 1 code/ch03 +int ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + if (ACE_Service_Config::open (argc, + argv, + ACE_DEFAULT_LOGGER_KEY, + 1, + 0, + 1) < 0) + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), + ACE_TEXT ("Service Config open")), + 1); + ACE_TRACE ("main"); + ACE_DEBUG ((LM_NOTICE, ACE_TEXT ("%t%IHowdy Pardner\n"))); + ACE_DEBUG ((LM_INFO, ACE_TEXT ("%t%IGoodnight\n"))); + + return 0; +} +// Listing 1 diff --git a/ACE/examples/APG/Logging/Use_Multiple_Sinks.cpp b/ACE/examples/APG/Logging/Use_Multiple_Sinks.cpp new file mode 100644 index 00000000000..352a598b4e2 --- /dev/null +++ b/ACE/examples/APG/Logging/Use_Multiple_Sinks.cpp @@ -0,0 +1,34 @@ +// $Id$ + +#include "ace/Log_Msg.h" +#include "ace/streams.h" + +int ACE_TMAIN (int, ACE_TCHAR *argv[]) +{ + // Output to default destination (stderr) + ACE_LOG_MSG->open (argv[0]); + + ACE_TRACE ("main"); + + ACE_OSTREAM_TYPE *output = + (ACE_OSTREAM_TYPE *) new ofstream ("ostream.output.test"); + + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("%IThis will go to STDERR\n"))); + + ACE_LOG_MSG->open + (argv[0], ACE_Log_Msg::SYSLOG, ACE_TEXT ("syslogTest")); + ACE_LOG_MSG->set_flags (ACE_Log_Msg::STDERR); + ACE_DEBUG + ((LM_DEBUG, ACE_TEXT ("%IThis goes to STDERR & syslog\n"))); + + ACE_LOG_MSG->msg_ostream (output, 0); + ACE_LOG_MSG->set_flags (ACE_Log_Msg::OSTREAM); + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("%IThis will go to STDERR, ") + ACE_TEXT ("syslog & an ostream\n"))); + + ACE_LOG_MSG->clr_flags (ACE_Log_Msg::OSTREAM); + delete output; + + return 0; +} diff --git a/ACE/examples/APG/Logging/Use_Ostream.cpp b/ACE/examples/APG/Logging/Use_Ostream.cpp new file mode 100644 index 00000000000..28a2fefcc1c --- /dev/null +++ b/ACE/examples/APG/Logging/Use_Ostream.cpp @@ -0,0 +1,36 @@ +// $Id$ + +#include "ace/Log_Msg.h" +#include "ace/streams.h" + +void foo (void); + +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_TRACE ("main"); + + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("%IHi Mom\n"))); + + /* Alternatively, you can use the set_flags() method to do the same + thing after the singleton has been created: + */ + // Listing 2 code/ch03 + ACE_OSTREAM_TYPE *output = + (ACE_OSTREAM_TYPE *) new ofstream ("ostream.output.test"); + ACE_LOG_MSG->msg_ostream (output, 1); + ACE_LOG_MSG->set_flags (ACE_Log_Msg::OSTREAM); + ACE_LOG_MSG->clr_flags (ACE_Log_Msg::STDERR); + // Listing 2 + + foo (); + ACE_DEBUG ((LM_INFO, ACE_TEXT ("%IGoodnight\n"))); + + return 0; +} + +void foo (void) +{ + ACE_TRACE ("foo"); + + ACE_DEBUG ((LM_INFO, ACE_TEXT ("%IHowdy Pardner\n"))); +} diff --git a/ACE/examples/APG/Logging/Use_Stderr.cpp b/ACE/examples/APG/Logging/Use_Stderr.cpp new file mode 100644 index 00000000000..e0418c4d362 --- /dev/null +++ b/ACE/examples/APG/Logging/Use_Stderr.cpp @@ -0,0 +1,38 @@ +// $Id$ + +#include "ace/Log_Msg.h" + +void foo (void); + +// Listing 1 code/ch03 +int ACE_TMAIN (int, ACE_TCHAR *argv[]) +{ + // open() requires the name of the application + // (e.g. -- argv[0]) because the underlying + // implementation may use it in the log output. + ACE_LOG_MSG->open (argv[0], ACE_Log_Msg::STDERR); + // Listing 1 + + /* Alternatively, you can use the set_flags() method to do the same + thing after the singleton has been created: + */ + + ACE_TRACE ("main"); + + // Listing 2 code/ch03 + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("%IHi Mom\n"))); + ACE_LOG_MSG->set_flags (ACE_Log_Msg::STDERR); + foo (); + // Listing 2 + + ACE_DEBUG ((LM_INFO, ACE_TEXT ("%IGoodnight\n"))); + + return 0; +} + +void foo (void) +{ + ACE_TRACE ("foo"); + + ACE_DEBUG ((LM_INFO, ACE_TEXT ("%IHowdy Pardner\n"))); +} diff --git a/ACE/examples/APG/Logging/Use_Syslog.cpp b/ACE/examples/APG/Logging/Use_Syslog.cpp new file mode 100644 index 00000000000..dce4a1fe6b0 --- /dev/null +++ b/ACE/examples/APG/Logging/Use_Syslog.cpp @@ -0,0 +1,32 @@ +// $Id$ + +#include "ace/Log_Msg.h" + +void foo (void); + +int ACE_TMAIN (int, ACE_TCHAR *argv[]) +{ + // This will be directed to stderr (the default ACE_Log_Msg + // behavior). + ACE_TRACE ("main"); + + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("%IHi Mom\n"))); + + // Everything from foo() will be directed to the system logger + ACE_LOG_MSG->open + (argv[0], ACE_Log_Msg::SYSLOG, ACE_TEXT ("syslogTest")); + foo (); + + // Now we reset the log output to default (stderr) + ACE_LOG_MSG->open (argv[0]); + ACE_DEBUG ((LM_INFO, ACE_TEXT ("%IGoodnight\n"))); + + return 0; +} + +void foo (void) +{ + ACE_TRACE ("foo"); + + ACE_DEBUG ((LM_INFO, ACE_TEXT ("%IHowdy Pardner\n"))); +} diff --git a/ACE/examples/APG/Logging/Wrap_Macros.cpp b/ACE/examples/APG/Logging/Wrap_Macros.cpp new file mode 100644 index 00000000000..9e88d3e11e0 --- /dev/null +++ b/ACE/examples/APG/Logging/Wrap_Macros.cpp @@ -0,0 +1,38 @@ +// $Id$ + +#include "Trace.h" + +#if defined (__GNUC__) && (__GNUC__ >= 3 || __GNUC_MINOR__ > 95) && \ + (!defined (VXWORKS) || !(__GNUC__ == 2 && __GNUC_MINOR__ == 96)) +// The macros in Trace.h only work on g++ 2.96 and later. +// But not with VxWorks g++ 2.96. + +// Listing 1 code/ch03 +void foo (void); + +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_TRACE ("main"); + MY_DEBUG (ACE_TEXT ("Hi Mom\n")); + foo (); + MY_DEBUG (ACE_TEXT ("Goodnight\n")); + return 0; +} + +void foo (void) +{ + ACE_TRACE ("foo"); + MY_DEBUG (ACE_TEXT ("Howdy Pardner\n")); +} +// Listing 1 + +#else +#include <stdio.h> + +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + puts ("This example only works on g++ 2.96 and later.\n"); + return 0; +} + +#endif /* __GNUC__ */ diff --git a/ACE/examples/APG/Logging/Wrap_Macros_Alt.cpp b/ACE/examples/APG/Logging/Wrap_Macros_Alt.cpp new file mode 100644 index 00000000000..306eefcd83a --- /dev/null +++ b/ACE/examples/APG/Logging/Wrap_Macros_Alt.cpp @@ -0,0 +1,18 @@ +// $Id$ + +#include "Log_Msg_Alt.h" + +void foo (void); + +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_TRACE ("main"); + + // Listing 1 code/ch03 + ACE_DEBUG ((MY_DEBUG ACE_TEXT ("Hi Mom\n"))); + + ACE_DEBUG ((MY_DEBUG ACE_TEXT ("Goodnight\n"))); + // Listing 1 + + return 0; +} diff --git a/ACE/examples/APG/Logging/client.conf b/ACE/examples/APG/Logging/client.conf new file mode 100644 index 00000000000..1007e3aa7f6 --- /dev/null +++ b/ACE/examples/APG/Logging/client.conf @@ -0,0 +1 @@ +dynamic Client_Logging_Service Service_Object * netsvcs:_make_ACE_Client_Logging_Acceptor() active "-p 20009 -h localhost" diff --git a/ACE/examples/APG/Logging/logging.mpc b/ACE/examples/APG/Logging/logging.mpc new file mode 100644 index 00000000000..d40c2ae2704 --- /dev/null +++ b/ACE/examples/APG/Logging/logging.mpc @@ -0,0 +1,128 @@ +// -*- MPC -*- +// $Id$ + +project(Simple1) : aceexe { + exename = Simple1 + Source_Files { + Simple1.cpp + } +} + +project(Simple2) : aceexe { + exename = Simple2 + Source_Files { + Simple2.cpp + } +} + +project(Change Mask) : aceexe { + exename = Change_Mask + Source_Files { + Change_Mask.cpp + } +} + +project(Change Instance Default) : aceexe { + exename = Change_Instance_Default + Source_Files { + Change_Instance_Default.cpp + } +} + +project(Wrap Macros) : aceexe { + exename = Wrap_Macros + Source_Files { + Wrap_Macros.cpp + } +} + +project(Wrap Macros Alt) : aceexe { + exename = Wrap_Macros_Alt + Source_Files { + Wrap_Macros_Alt.cpp + } +} + +project(Trace Return) : aceexe { + exename = Trace_Return + Source_Files { + Trace_Return.cpp + } +} + +project(Use Stderr) : aceexe { + exename = Use_Stderr + Source_Files { + Use_Stderr.cpp + } +} + +project(Howto Syslog) : aceexe { + exename = Howto_Syslog + Source_Files { + Howto_Syslog.cpp + } +} + +project(Use Syslog) : aceexe { + exename = Use_Syslog + Source_Files { + Use_Syslog.cpp + } +} + +project(Use Ostream) : aceexe { + exename = Use_Ostream + Source_Files { + Use_Ostream.cpp + } +} + +project(Use Multiple Sinks) : aceexe { + exename = Use_Multiple_Sinks + Source_Files { + Use_Multiple_Sinks.cpp + } +} + +project(Use Callback) : aceexe { + exename = Use_Callback + Source_Files { + Use_Callback.cpp + } +} + +project(Use Callback2) : aceexe { + exename = Use_Callback2 + Source_Files { + Use_Callback2.cpp + } +} + +project(Use Logger) : aceexe { + exename = Use_Logger + Source_Files { + Use_Logger.cpp + } +} + +project(Use Logging Server) : aceexe { + exename = Use_Logging_Server + Source_Files { + Use_Logging_Server.cpp + } +} + +project(Use LogManager) : aceexe { + exename = Use_LogManager + Source_Files { + Use_LogManager.cpp + } +} + +project(Use Logging Strategy) : aceexe { + exename = Use_Logging_Strategy + Source_Files { + Use_Logging_Strategy.cpp + } +} diff --git a/ACE/examples/APG/Logging/logging_strategy.conf b/ACE/examples/APG/Logging/logging_strategy.conf new file mode 100644 index 00000000000..b63501ee185 --- /dev/null +++ b/ACE/examples/APG/Logging/logging_strategy.conf @@ -0,0 +1 @@ +dynamic Logger Service_Object * ACE:_make_ACE_Logging_Strategy() "-s log.out -f STDERR|OSTREAM -p INFO" diff --git a/ACE/examples/APG/Logging/server.conf b/ACE/examples/APG/Logging/server.conf new file mode 100644 index 00000000000..31f8fd95d9d --- /dev/null +++ b/ACE/examples/APG/Logging/server.conf @@ -0,0 +1,3 @@ +dynamic Logger Service_Object * ACE:_make_ACE_Logging_Strategy() "-s foobar -f STDERR|OSTREAM|VERBOSE" + +dynamic Server_Logging_Service Service_Object * netsvcs:_make_ACE_Server_Logging_Acceptor() active "-p 20009" diff --git a/ACE/examples/APG/Makefile.am b/ACE/examples/APG/Makefile.am new file mode 100644 index 00000000000..f79765c9348 --- /dev/null +++ b/ACE/examples/APG/Makefile.am @@ -0,0 +1,31 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +SUBDIRS = \ + Active_Objects \ + Config \ + Containers \ + Logging \ + Misc_IPC \ + Naming \ + Proactor \ + Processes \ + Reactor \ + Shared_Memory \ + Signals \ + Sockets \ + Streams \ + Svc_Config \ + ThreadManagement \ + ThreadPools \ + ThreadSafety \ + Threads \ + Timers + diff --git a/ACE/examples/APG/Misc_IPC/.cvsignore b/ACE/examples/APG/Misc_IPC/.cvsignore new file mode 100644 index 00000000000..155f8a18824 --- /dev/null +++ b/ACE/examples/APG/Misc_IPC/.cvsignore @@ -0,0 +1,6 @@ +UDP_Broadcast +UDP_Broadcast +UDP_Multicast +UDP_Multicast +UDP_Unicast +UDP_Unicast diff --git a/ACE/examples/APG/Misc_IPC/Makefile.am b/ACE/examples/APG/Misc_IPC/Makefile.am new file mode 100644 index 00000000000..656f63fb00c --- /dev/null +++ b/ACE/examples/APG/Misc_IPC/Makefile.am @@ -0,0 +1,69 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +ACE_BUILDDIR = $(top_builddir) +ACE_ROOT = $(top_srcdir) + +noinst_PROGRAMS = + +## Makefile.UDP_Broadcast.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS += UDP_Broadcast + +UDP_Broadcast_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +UDP_Broadcast_SOURCES = \ + UDP_Broadcast.cpp + +UDP_Broadcast_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Makefile.UDP_Multicast.am +noinst_PROGRAMS += UDP_Multicast + +UDP_Multicast_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +UDP_Multicast_SOURCES = \ + UDP_Multicast.cpp + +UDP_Multicast_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.UDP_Unicast.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS += UDP_Unicast + +UDP_Unicast_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +UDP_Unicast_SOURCES = \ + UDP_Unicast.cpp + +UDP_Unicast_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Clean up template repositories, etc. +clean-local: + -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.* + -rm -f gcctemp.c gcctemp so_locations *.ics + -rm -rf cxx_repository ptrepository ti_files + -rm -rf templateregistry ir.out + -rm -rf ptrepository SunWS_cache Templates.DB diff --git a/ACE/examples/APG/Misc_IPC/UDP_Broadcast.cpp b/ACE/examples/APG/Misc_IPC/UDP_Broadcast.cpp new file mode 100644 index 00000000000..318be67b19c --- /dev/null +++ b/ACE/examples/APG/Misc_IPC/UDP_Broadcast.cpp @@ -0,0 +1,34 @@ +/** + * $Id$ + * + * Sample code from The ACE Programmer's Guide, + * Copyright 2003 Addison-Wesley. All Rights Reserved. + */ + +// Listing 1 code/ch09 +#include "ace/OS_NS_string.h" +#include "ace/Log_Msg.h" +#include "ace/INET_Addr.h" +#include "ace/SOCK_Dgram_Bcast.h" + +int send_broadcast (u_short to_port) +{ + const char *message = "this is the message!\n"; + ACE_INET_Addr my_addr (static_cast<u_short> (10101)); + ACE_SOCK_Dgram_Bcast udp (my_addr); + ssize_t sent = udp.send (message, + ACE_OS::strlen (message) + 1, + to_port); + udp.close (); + if (sent == -1) + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), + ACE_TEXT ("send")), -1); + return 0; +} +// Listing 1 + +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + send_broadcast (10); + return 0; +} diff --git a/ACE/examples/APG/Misc_IPC/UDP_Multicast.cpp b/ACE/examples/APG/Misc_IPC/UDP_Multicast.cpp new file mode 100644 index 00000000000..feb2baafc57 --- /dev/null +++ b/ACE/examples/APG/Misc_IPC/UDP_Multicast.cpp @@ -0,0 +1,37 @@ +/** + * $Id$ + * + * Sample code from The ACE Programmer's Guide, + * Copyright 2003 Addison-Wesley. All Rights Reserved. + */ + +// Listing 1 code/ch09 +#include "ace/OS_NS_string.h" +#include "ace/Log_Msg.h" +#include "ace/INET_Addr.h" +#include "ace/SOCK_Dgram_Mcast.h" + +int send_multicast (const ACE_INET_Addr &mcast_addr) +{ + const char *message = "this is the message!\n"; + ACE_SOCK_Dgram_Mcast udp; + if (-1 == udp.join (mcast_addr)) + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), + ACE_TEXT ("join")), -1); + + ssize_t sent = udp.send (message, + ACE_OS::strlen (message) + 1); + udp.close (); + if (sent == -1) + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), + ACE_TEXT ("send")), -1); + return 0; +} +// Listing 1 + +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_INET_Addr nop; + send_multicast (nop); + return 0; +} diff --git a/ACE/examples/APG/Misc_IPC/UDP_Unicast.cpp b/ACE/examples/APG/Misc_IPC/UDP_Unicast.cpp new file mode 100644 index 00000000000..ac3d4d00488 --- /dev/null +++ b/ACE/examples/APG/Misc_IPC/UDP_Unicast.cpp @@ -0,0 +1,71 @@ +/** + * $Id$ + * + * Sample code from The ACE Programmer's Guide, + * Copyright 2003 Addison-Wesley. All Rights Reserved. + */ + +// Listing 1 code/ch09 +#include "ace/OS_NS_string.h" +#include "ace/Log_Msg.h" +#include "ace/INET_Addr.h" +#include "ace/SOCK_Dgram.h" + +int send_unicast (const ACE_INET_Addr &to) +{ + const char *message = "this is the message!\n"; + ACE_INET_Addr my_addr (static_cast<u_short> (10101)); + ACE_SOCK_Dgram udp (my_addr); + ssize_t sent = udp.send (message, + ACE_OS::strlen (message) + 1, + to); + udp.close (); + if (sent == -1) + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), + ACE_TEXT ("send")), -1); + return 0; +} +// Listing 1 + +// Listing 2 code/ch09 +void echo_dgram (void) +{ + ACE_INET_Addr my_addr (static_cast<u_short> (10102)); + ACE_INET_Addr your_addr; + ACE_SOCK_Dgram udp (my_addr); + char buff[BUFSIZ]; + size_t buflen = sizeof (buff); + ssize_t recv_cnt = udp.recv (buff, buflen, your_addr); + if (recv_cnt > 0) + udp.send (buff, static_cast<size_t> (buflen), your_addr); + udp.close (); + return; +} +// Listing 2 + +// Listing 3 code/ch09 +#include "ace/SOCK_CODgram.h" +// Exclude 3 +static void show_codgram (void) +{ + char buff[BUFSIZ]; + size_t buflen = sizeof (buff); + // Exclude 3 + const ACE_TCHAR *peer = ACE_TEXT ("other_host:8042"); + ACE_INET_Addr peer_addr (peer); + ACE_SOCK_CODgram udp; + if (0 != udp.open (peer_addr)) + ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), peer)); + + // ... + + if (-1 == udp.send (buff, buflen)) + ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("send"))); + // Listing 3 +} + +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + show_codgram (); + return 0; +} diff --git a/ACE/examples/APG/Misc_IPC/misc_ipc.mpc b/ACE/examples/APG/Misc_IPC/misc_ipc.mpc new file mode 100644 index 00000000000..47e1c34758b --- /dev/null +++ b/ACE/examples/APG/Misc_IPC/misc_ipc.mpc @@ -0,0 +1,25 @@ +// -*- MPC -*- +// $Id$ + +project(UDP Broadcast) : aceexe { + avoids += ace_for_tao + exename = UDP_Broadcast + Source_Files { + UDP_Broadcast.cpp + } +} + +project(UDP Multicast) : aceexe { + exename = UDP_Multicast + Source_Files { + UDP_Multicast.cpp + } +} + +project(UDP Unicast) : aceexe { + avoids += ace_for_tao + exename = UDP_Unicast + Source_Files { + UDP_Unicast.cpp + } +} diff --git a/ACE/examples/APG/Naming/.cvsignore b/ACE/examples/APG/Naming/.cvsignore new file mode 100644 index 00000000000..e5fd579f85d --- /dev/null +++ b/ACE/examples/APG/Naming/.cvsignore @@ -0,0 +1,10 @@ +Netlocal +Netlocal +Netlocal_reader +Netlocal_reader +Nodelocal +Nodelocal +Nodelocal_shared +Nodelocal_shared +Nodelocal_shared_reader +Nodelocal_shared_reader diff --git a/ACE/examples/APG/Naming/EMail.h b/ACE/examples/APG/Naming/EMail.h new file mode 100644 index 00000000000..fc38913a10a --- /dev/null +++ b/ACE/examples/APG/Naming/EMail.h @@ -0,0 +1,28 @@ +// $Id$ + +#ifndef EMAIL_H +#define EMAIL_H + +#include "ace/Log_Msg.h" + +class EMail + { + public: + EMail() + { } + + int send (const char *to, + const char *from, + const char *subject, + const char *message) + { + ACE_DEBUG ((LM_ERROR, ACE_TEXT ("To:\t%s\n"), to)); + ACE_DEBUG ((LM_ERROR, ACE_TEXT ("From:\t%s\n"), from)); + ACE_DEBUG ((LM_ERROR, ACE_TEXT ("Subject:\t%s\n"), subject)); + ACE_DEBUG ((LM_ERROR, ACE_TEXT ("\n%s\n"), message)); + + return 0; + } + }; + +#endif /* EMAIL_H */ diff --git a/ACE/examples/APG/Naming/Graph.cpp b/ACE/examples/APG/Naming/Graph.cpp new file mode 100644 index 00000000000..62ca52afd0d --- /dev/null +++ b/ACE/examples/APG/Naming/Graph.cpp @@ -0,0 +1,47 @@ +// $Id$ + +#include "ace/Log_Msg.h" +#include "Graph.h" + +void Graph::graph (char *filename, Graphable_Element_List &data) +{ + data.sort (); + + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Save graph to %C\n"), filename)); + + char h[10][10]; + for (int n = 0 ; n < 10 ; ++n ) + { + for (int j = 0; j < 10; ++j ) + { + h[n][j] = ' '; + } + } + + int l[10]; + int k = 0; + for (Graphable_Element_List::iterator i = data.begin (); + i != data.end (); + ++i, ++k ) + { + l[k] = (*i).when (); + + int temp = (int)((*i).temp () - 80.0); + + for (int j = 0; j <= temp; ++j) + { + h[k][j] = '#'; + } + } + + for (int m = 0 ; m < 10 ; ++m) + { + ACE_DEBUG ((LM_INFO, ACE_TEXT ("%d "), l[m])); + + for (int j = 0; j < 10; ++j) + { + ACE_DEBUG ((LM_INFO, ACE_TEXT ("%c"), h[m][j])); + } + ACE_DEBUG ((LM_INFO, ACE_TEXT ("\n"))); + } +} diff --git a/ACE/examples/APG/Naming/Graph.h b/ACE/examples/APG/Naming/Graph.h new file mode 100644 index 00000000000..135b7d14f77 --- /dev/null +++ b/ACE/examples/APG/Naming/Graph.h @@ -0,0 +1,18 @@ +// $Id$ + +#ifndef GRAPH_H +#define GRAPH_H + +#include "Graphable_Element.h" + +class Graph + { + public: + Graph() + { + } + + void graph( char * filename, Graphable_Element_List & data ); + }; + +#endif /* GRAPH_H */ diff --git a/ACE/examples/APG/Naming/Graphable_Element.cpp b/ACE/examples/APG/Naming/Graphable_Element.cpp new file mode 100644 index 00000000000..c3ff6ee7b41 --- /dev/null +++ b/ACE/examples/APG/Naming/Graphable_Element.cpp @@ -0,0 +1,4 @@ +// $Id$ + +#include "Graphable_Element.h" + diff --git a/ACE/examples/APG/Naming/Graphable_Element.h b/ACE/examples/APG/Naming/Graphable_Element.h new file mode 100644 index 00000000000..42758934993 --- /dev/null +++ b/ACE/examples/APG/Naming/Graphable_Element.h @@ -0,0 +1,53 @@ +/* -*- C++ -*- */ +// $Id$ + +#ifndef GRAPHABLE_ELEMENT_H +#define GRAPHABLE_ELEMENT_H + +#include "Name_Binding.h" +#include <list> + +// A helper class that knows how to sort two ACE_Name_Binding objects +// which contain temperature metrics. The value stored in the binding +// is expected to be of the format "time|temp". +// +// Listing 1 code/ch21 +class Graphable_Element : public Name_Binding +{ +public: + Graphable_Element (ACE_Name_Binding *entry) + : Name_Binding(entry) + { + sscanf (this->value (), "%d|%f", &this->when_, &this->temp_); + } + // Listing 1 + + // Listing 2 code/ch21 + inline int when (void) const + { + return this->when_; + } + + inline float temp (void) + { + return this->temp_; + } + // Listing 2 + + // Listing 3 code/ch21 + inline bool operator< (const Graphable_Element &other) const + { + return this->when () < other.when (); + } + // Listing 3 + + // Listing 4 code/ch21 +private: + int when_; + float temp_; +}; + +typedef std::list<Graphable_Element> Graphable_Element_List; +// Listing 4 + +#endif /* GRAPHABLE_ELEMENT_H */ diff --git a/ACE/examples/APG/Naming/Makefile.am b/ACE/examples/APG/Naming/Makefile.am new file mode 100644 index 00000000000..f73b1258348 --- /dev/null +++ b/ACE/examples/APG/Naming/Makefile.am @@ -0,0 +1,123 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +ACE_BUILDDIR = $(top_builddir) +ACE_ROOT = $(top_srcdir) + +noinst_PROGRAMS = + +## Makefile.Netlocal.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS += Netlocal + +Netlocal_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +Netlocal_SOURCES = \ + Netlocal.cpp \ + Temperature_Monitor2.cpp \ + Temperature_Monitor2.h + +Netlocal_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Makefile.Netlocal_Reader.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS += Netlocal_reader + +Netlocal_reader_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +Netlocal_reader_SOURCES = \ + Graph.cpp \ + Netlocal_reader.cpp \ + Temperature_Grapher.cpp \ + Graph.h \ + Temperature_Grapher.h + +Netlocal_reader_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Makefile.Nodelocal.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS += Nodelocal + +Nodelocal_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +Nodelocal_SOURCES = \ + Nodelocal.cpp \ + Temperature_Monitor.cpp \ + Temperature_Monitor.h + +Nodelocal_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Makefile.Nodelocal_Shared.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS += Nodelocal_shared + +Nodelocal_shared_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +Nodelocal_shared_SOURCES = \ + Nodelocal_shared.cpp \ + Temperature_Monitor2.cpp \ + Temperature_Monitor2.h + +Nodelocal_shared_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Makefile.Nodelocal_Shared_Reader.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS += Nodelocal_shared_reader + +Nodelocal_shared_reader_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +Nodelocal_shared_reader_SOURCES = \ + Graph.cpp \ + Nodelocal_shared_reader.cpp \ + Temperature_Grapher.cpp \ + Temperature_Monitor.cpp \ + Graph.h \ + Temperature_Grapher.h \ + Temperature_Monitor.h + +Nodelocal_shared_reader_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Clean up template repositories, etc. +clean-local: + -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.* + -rm -f gcctemp.c gcctemp so_locations *.ics + -rm -rf cxx_repository ptrepository ti_files + -rm -rf templateregistry ir.out + -rm -rf ptrepository SunWS_cache Templates.DB diff --git a/ACE/examples/APG/Naming/Name_Binding.h b/ACE/examples/APG/Naming/Name_Binding.h new file mode 100644 index 00000000000..6c093a941f2 --- /dev/null +++ b/ACE/examples/APG/Naming/Name_Binding.h @@ -0,0 +1,61 @@ +/* -*- C++ -*- */ +// $Id$ + +#ifndef NAME_BINDING_H +#define NAME_BINDING_H + +#include "ace/OS_NS_stdlib.h" +#include "ace/OS_NS_string.h" +#include "ace/Auto_Ptr.h" +#include "ace/Name_Space.h" + +// Listing 1 code/ch21 +class Name_Binding +{ +public: + Name_Binding (ACE_Name_Binding *entry) + { + this->name_ = entry->name_.char_rep (); + this->value_ = entry->value_.char_rep (); + this->type_ = ACE_OS::strdup (entry->type_); + } + + Name_Binding (const ACE_NS_WString &n, + const ACE_NS_WString &v, + const char *t) + { + this->name_ = n.char_rep (); + this->value_ = v.char_rep (); + this->type_ = ACE_OS::strdup (t); + } + + ~Name_Binding () + { + delete this->name_; + delete this->value_; + ACE_OS::free (const_cast<char*> (this->type_)); + this->type_ = 0; + } + + char *name (void) + { return this->name_; } + + char *value (void) + { return this->value_; } + + const char *type (void) + { return this->type_; } + + int int_value (void) + { return ACE_OS::atoi (this->value ()); } + +private: + char *name_; + char *value_; + char *type_; +}; + +typedef auto_ptr<Name_Binding> Name_Binding_Ptr; +// Listing 1 + +#endif /* NAME_BINDING_H */ diff --git a/ACE/examples/APG/Naming/Naming_Context.h b/ACE/examples/APG/Naming/Naming_Context.h new file mode 100644 index 00000000000..abcf793b2b6 --- /dev/null +++ b/ACE/examples/APG/Naming/Naming_Context.h @@ -0,0 +1,68 @@ +/* -*- C++ -*- */ +// $Id$ + +#ifndef NAMING_CONTEXT_H +#define NAMING_CONTEXT_H + +#include "ace/Naming_Context.h" +#include "ace/OS_NS_stdio.h" +#include "Name_Binding.h" + +// Listing 1 code/ch21 +class Naming_Context : public ACE_Naming_Context +{ +public: + typedef ACE_Naming_Context inherited; + + int rebind (const char *name_in, + const char *value_in, + const char *type_in = "") + { + return this->inherited::rebind (name_in, value_in, type_in); + } + + int rebind (const char *name_in, + float value_in, + const char *type_in = "") + { + char buf[BUFSIZ]; + ACE_OS::sprintf (buf, "%2f", value_in); + return this->inherited::rebind (name_in, + (const char *)buf, + type_in); + } + + int rebind (const char *name_in, + int value_in, + const char *type_in = "") + { + char buf[BUFSIZ]; + ACE_OS::sprintf (buf, "%d", value_in ); + return this->inherited::rebind (name_in, + (const char *)buf, + type_in); + } + // Listing 1 + + // Listing 2 code/ch21 + Name_Binding *fetch (const char *name) + { + ACE_NS_WString value; + char *type; + + if (this->resolve (name, value, type) != 0 || + value.length () < 1) + { + return 0; + } + + Name_Binding *rval = + new Name_Binding (ACE_NS_WString (name), + value, + type); + return rval; + } +// Listing 2 +}; + +#endif /* NAMING_CONTEXT_H */ diff --git a/ACE/examples/APG/Naming/Netlocal.cpp b/ACE/examples/APG/Naming/Netlocal.cpp new file mode 100644 index 00000000000..f1799ab3882 --- /dev/null +++ b/ACE/examples/APG/Naming/Netlocal.cpp @@ -0,0 +1,40 @@ +// $Id$ + +#include "Naming_Context.h" +#include "Temperature_Monitor2.h" +#include "Temperature_Monitor_Options.h" + +// Listing 1 code/ch21 +int ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + Temperature_Monitor_Options opt (argc, argv); + + Naming_Context process_context; + { + ACE_Name_Options *name_options = + process_context.name_options (); + name_options->context (ACE_Naming_Context::PROC_LOCAL); + ACE_TCHAR *nargv[] = { argv[0] }; + name_options->parse_args (sizeof(nargv) / sizeof(ACE_TCHAR*), + nargv); + process_context.open (name_options->context ()); + } + + Naming_Context shared_context; + { + ACE_Name_Options *name_options = + shared_context.name_options (); + name_options->process_name (argv[0]); + name_options->context (ACE_Naming_Context::NET_LOCAL); + shared_context.open (name_options->context ()); + } + + Temperature_Monitor2 temperature_monitor (opt, + process_context, + shared_context); + temperature_monitor.monitor (); + process_context.close (); + shared_context.close (); + return 0; +} +// Listing 1 diff --git a/ACE/examples/APG/Naming/Netlocal_reader.cpp b/ACE/examples/APG/Naming/Netlocal_reader.cpp new file mode 100644 index 00000000000..f77724aabbe --- /dev/null +++ b/ACE/examples/APG/Naming/Netlocal_reader.cpp @@ -0,0 +1,23 @@ +// $Id$ + +#include "Naming_Context.h" +#include "Temperature_Grapher.h" +#include "Temperature_Grapher_Options.h" + +// Listing 1 code/ch21 +int ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + Temperature_Grapher_Options opt (argc, argv); + + Naming_Context naming_context; + ACE_Name_Options *name_options = naming_context.name_options (); + name_options->process_name (argv[0]); + name_options->context (ACE_Naming_Context::NET_LOCAL); + naming_context.open (name_options->context ()); + + Temperature_Grapher grapher (opt, naming_context); + grapher.monitor (); + naming_context.close (); + return 0; +} +// Listing 1 diff --git a/ACE/examples/APG/Naming/Nodelocal.cpp b/ACE/examples/APG/Naming/Nodelocal.cpp new file mode 100644 index 00000000000..ca37a27e374 --- /dev/null +++ b/ACE/examples/APG/Naming/Nodelocal.cpp @@ -0,0 +1,37 @@ +// $Id$ + +#include "Naming_Context.h" +#include "Temperature_Monitor.h" +#include "Temperature_Monitor_Options.h" + +// Listing 1 code/ch21 +int ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + Temperature_Monitor_Options opt (argc, argv); + // Listing 1 + + // Listing 2 code/ch21 + Naming_Context naming_context; + + ACE_Name_Options *name_options = naming_context.name_options(); + // Listing 2 + + // Listing 3 code/ch21 + ACE_TCHAR *naming_options_argv[] = { argv[0] }; + name_options->parse_args + (sizeof(naming_options_argv) / sizeof(ACE_TCHAR*), + naming_options_argv); + name_options->context (ACE_Naming_Context::PROC_LOCAL); + naming_context.open (name_options->context ()); + // Listing 3 + + // Listing 4 code/ch21 + Temperature_Monitor temperature_monitor (opt, naming_context); + temperature_monitor.monitor (); + // Listing 4 + + // Listing 5 code/ch21 + naming_context.close (); + return 0; + // Listing 5 +} diff --git a/ACE/examples/APG/Naming/Nodelocal_shared.cpp b/ACE/examples/APG/Naming/Nodelocal_shared.cpp new file mode 100644 index 00000000000..34ea87aab2d --- /dev/null +++ b/ACE/examples/APG/Naming/Nodelocal_shared.cpp @@ -0,0 +1,43 @@ +// $Id$ + +#include "Naming_Context.h" +#include "Temperature_Monitor2.h" +#include "Temperature_Monitor_Options.h" + +// Listing 1 code/ch21 +int ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + Temperature_Monitor_Options opt (argc, argv); + Naming_Context process_context; + { + ACE_Name_Options *name_options = + process_context.name_options (); + name_options->context (ACE_Naming_Context::PROC_LOCAL); + ACE_TCHAR *nargv[] = { argv[0] }; + name_options->parse_args (sizeof(nargv) / sizeof(ACE_TCHAR*) , + nargv); + process_context.open (name_options->context ()); + } + + Naming_Context shared_context; + { + ACE_Name_Options *name_options = + shared_context.name_options (); + name_options->process_name (argv[0]); + name_options->context (ACE_Naming_Context::NODE_LOCAL); + shared_context.open (name_options->context ()); + } + + Temperature_Monitor2 temperature_monitor (opt, + process_context, + shared_context); + temperature_monitor.monitor (); + + process_context.close (); + shared_context.close (); + + return 0; +} +// Listing 1 + + diff --git a/ACE/examples/APG/Naming/Nodelocal_shared_reader.cpp b/ACE/examples/APG/Naming/Nodelocal_shared_reader.cpp new file mode 100644 index 00000000000..7385f09a496 --- /dev/null +++ b/ACE/examples/APG/Naming/Nodelocal_shared_reader.cpp @@ -0,0 +1,23 @@ +// $Id$ + +#include "Naming_Context.h" +#include "Temperature_Grapher.h" +#include "Temperature_Grapher_Options.h" + +// Listing 1 code/ch21 +int ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + Temperature_Grapher_Options opt (argc, argv); + + Naming_Context naming_context; + ACE_Name_Options *name_options = naming_context.name_options (); + name_options->process_name (argv[0]); + name_options->context (ACE_Naming_Context::NODE_LOCAL); + naming_context.open (name_options->context ()); + + Temperature_Grapher grapher (opt, naming_context); + grapher.monitor (); + naming_context.close (); + return 0; +} +// Listing 1 diff --git a/ACE/examples/APG/Naming/Temperature_Grapher.cpp b/ACE/examples/APG/Naming/Temperature_Grapher.cpp new file mode 100644 index 00000000000..e11367af4a0 --- /dev/null +++ b/ACE/examples/APG/Naming/Temperature_Grapher.cpp @@ -0,0 +1,81 @@ +// $Id$ + +#include "ace/OS_NS_unistd.h" +#include "ace/Log_Msg.h" + +#include "Graph.h" +#include "Graphable_Element.h" +#include "Temperature_Grapher.h" + +// Listing 1 code/ch21 +void Temperature_Grapher::monitor (void) +{ + for (;;) + { + this->update_graph (); + ACE_OS::sleep (this->opt_.poll_interval ()); + } +} +// Listing 1 + +// Listing 2 code/ch21 +void Temperature_Grapher::update_graph (void) +{ + Name_Binding_Ptr lastUpdate + (this->naming_context_.fetch ("lastUpdate")); + + if (!lastUpdate.get ()) + { + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("No data to graph\n"))); + return; + } + // Listing 2 + + // Listing 3 code/ch21 + Name_Binding_Ptr lastGraphed + (this->naming_context_.fetch ("lastGraphed")); + + if (lastGraphed.get () && + lastGraphed->int_value () == lastUpdate->int_value ()) + { + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Data already graphed\n"))); + return; + } + // Listing 3 + + // Listing 4 code/ch21 + ACE_BINDING_SET set; + if (this->naming_context_.list_name_entries + (set, "history[") != 0) + { + ACE_DEBUG ((LM_INFO, + ACE_TEXT ("There's nothing to graph\n"))); + return; + } + // Listing 4 + + // Listing 5 code/ch21 + Graphable_Element_List graphable; + ACE_BINDING_ITERATOR set_iterator (set); + for (ACE_Name_Binding *entry = 0; + set_iterator.next (entry) != 0; + set_iterator.advance ()) + { + Name_Binding binding (entry); + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("%s\t%s\t%s\n"), + binding.type (), + binding.name (), + binding.value ())); + + Graphable_Element *ge = new Graphable_Element (entry); + graphable.push_back (*ge); + } + // Listing 5 + + // Listing 6 code/ch21 + Graph g; + g.graph (lastUpdate->value (), graphable); + this->naming_context_.rebind ("lastGraphed", + lastUpdate->int_value ()); + // Listing 6 +} diff --git a/ACE/examples/APG/Naming/Temperature_Grapher.h b/ACE/examples/APG/Naming/Temperature_Grapher.h new file mode 100644 index 00000000000..610dac6a578 --- /dev/null +++ b/ACE/examples/APG/Naming/Temperature_Grapher.h @@ -0,0 +1,30 @@ +// $Id$ + +#ifndef TEMPERATURE_GRAPHER_H +#define TEMPERATURE_GRAPHER_H + +#include "Thermometer.h" +#include "Temperature_Grapher_Options.h" +#include "Naming_Context.h" + +class Temperature_Grapher + { + public: + Temperature_Grapher( Temperature_Grapher_Options & opt, + Naming_Context & naming_context ) + : opt_(opt), naming_context_(naming_context) + { + } + + void monitor(); + + protected: + void update_graph(); + + private: + Thermometer * thermometer_; + Temperature_Grapher_Options & opt_; + Naming_Context & naming_context_; + }; + +#endif /* TEMPERATURE_GRAPHER_H */ diff --git a/ACE/examples/APG/Naming/Temperature_Grapher_Options.h b/ACE/examples/APG/Naming/Temperature_Grapher_Options.h new file mode 100644 index 00000000000..e7a2dbe7c94 --- /dev/null +++ b/ACE/examples/APG/Naming/Temperature_Grapher_Options.h @@ -0,0 +1,21 @@ +// $Id$ + +#ifndef TEMPERATURE_GRAPHER_OPTIONS_H +#define TEMPERATURE_GRAPHER_OPTIONS_H + +class Temperature_Grapher_Options + { + public: + Temperature_Grapher_Options( int argc, ACE_TCHAR ** argv ) + { + ACE_UNUSED_ARG(argc); + ACE_UNUSED_ARG(argv); + } + + int poll_interval() + { + return 20; // every 20 seconds + } + }; + +#endif /* TEMPERATURE_GRAPHER_OPTIONS_H */ diff --git a/ACE/examples/APG/Naming/Temperature_Monitor.cpp b/ACE/examples/APG/Naming/Temperature_Monitor.cpp new file mode 100644 index 00000000000..8ac841b4108 --- /dev/null +++ b/ACE/examples/APG/Naming/Temperature_Monitor.cpp @@ -0,0 +1,133 @@ +// $Id$ + +#include "ace/OS_NS_time.h" +#include "ace/OS_NS_unistd.h" +#include "ace/Log_Msg.h" + +#include "Thermometer.h" +#include "Temperature_Monitor.h" +#include "EMail.h" + +// Listing 1 code/ch21 +Temperature_Monitor::Temperature_Monitor + (Temperature_Monitor_Options &opt, + Naming_Context &naming_context) + : opt_(opt), naming_context_(naming_context) +{ } +// Listing 1 + +// Listing 31 code/ch21 +void Temperature_Monitor::record_temperature (float temp) +{ + Name_Binding_Ptr current + (this->naming_context_.fetch ("current")); + if (current.get()) + { + this->naming_context_.rebind ("previous", + current->value ()); + } +// Listing 31 + +// Listing 32 code/ch21 + this->naming_context_.rebind ("current", temp); +// Listing 32 + +// Listing 33 code/ch21 + this->naming_context_.unbind ("lastReset"); + this->naming_context_.unbind ("resetCount"); +// Listing 33 +} + +// Listing 41 code/ch21 +void Temperature_Monitor::record_failure (void) +{ + Name_Binding_Ptr lastReset + (this->naming_context_.fetch ("lastReset")); + Name_Binding_Ptr resetCount + (this->naming_context_.fetch ("resetCount")); +// Listing 41 + +// Listing 42 code/ch21 + int now = ACE_OS::time (); + int lastResetTime; + if (lastReset.get ()) + { + lastResetTime = lastReset->int_value (); + } + else + { + this->naming_context_.rebind ("lastReset", now); + lastResetTime = now; + } + // Listing 42 + + // Listing 43 code/ch21 + if (now - lastResetTime > this->opt_.reset_interval ()) + { + this->reset_device (resetCount); + } + // Listing 43 +} + +// Listing 5 code/ch21 +void +Temperature_Monitor::reset_device (Name_Binding_Ptr &resetCount) +{ + int number_of_resets = 1; + if (resetCount.get ()) + { + number_of_resets = resetCount->int_value () + 1; + if (number_of_resets > this->opt_.excessive_resets ()) + { + // Exclude 5 + EMail notification; + + char message[BUFSIZ]; + ACE_OS::sprintf (message, + "Thermometer: %s\n" + "Reset Count: %d\n", + this->thermometer_->address(), + number_of_resets); + + notification.send (this->opt_.admin_email (), + this->opt_.email_from (), + "Excessive number of thermometer resets", + message); + // Exclude 5 + } + } + this->thermometer_->reset (); + this->naming_context_.rebind ("lastReset", + (int) ACE_OS::time ()); + this->naming_context_.rebind ("resetCount", + number_of_resets); +} +// Listing 5 + +// Listing 2 code/ch21 +void Temperature_Monitor::monitor (void) +{ + this->thermometer_ = + new Thermometer (this->opt_.thermometer_address ()); + + for(;;) + { + float temp = this->thermometer_->temperature (); + ACE_DEBUG ((LM_INFO, ACE_TEXT ("Read temperature %.2f\n"), + temp)); + + if (temp >= 0) + { + this->record_temperature (temp); + } + else + { + this->record_failure (); + } + + ACE_OS::sleep (this->opt_.poll_interval ()); + } + + delete this->thermometer_; +} +// Listing 2 diff --git a/ACE/examples/APG/Naming/Temperature_Monitor.h b/ACE/examples/APG/Naming/Temperature_Monitor.h new file mode 100644 index 00000000000..3b85b100fa1 --- /dev/null +++ b/ACE/examples/APG/Naming/Temperature_Monitor.h @@ -0,0 +1,29 @@ +// $Id$ + +#ifndef TEMPERATURE_MONITOR_H +#define TEMPERATURE_MONITOR_H + +#include "Thermometer.h" +#include "Temperature_Monitor_Options.h" +#include "Naming_Context.h" + +class Temperature_Monitor + { + public: + Temperature_Monitor( Temperature_Monitor_Options & opt, + Naming_Context & naming_context ); + + void monitor(); + + protected: + void record_temperature(float temp); + void record_failure(); + void reset_device(Name_Binding_Ptr & resetCount); + + private: + Thermometer * thermometer_; + Temperature_Monitor_Options & opt_; + Naming_Context & naming_context_; + }; + +#endif /* TEMPERATURE_MONITOR_H */ diff --git a/ACE/examples/APG/Naming/Temperature_Monitor2.cpp b/ACE/examples/APG/Naming/Temperature_Monitor2.cpp new file mode 100644 index 00000000000..b24f1c1f329 --- /dev/null +++ b/ACE/examples/APG/Naming/Temperature_Monitor2.cpp @@ -0,0 +1,145 @@ +// $Id$ + +#include "ace/OS_NS_time.h" +#include "ace/OS_NS_unistd.h" +#include "ace/Log_Msg.h" + +#include "Thermometer.h" +#include "Temperature_Monitor2.h" +#include "EMail.h" + +// Listing 1 code/ch21 +void Temperature_Monitor2::record_temperature (float temp) +{ + Name_Binding_Ptr current + (this->naming_context_.fetch ("current")); + if (current.get ()) + { + this->naming_context_.rebind ("previous", + current->value ()); + } + + this->record_history (temp); + + this->naming_context_.unbind ("lastFailure"); + this->naming_context_.unbind ("lastReset"); + this->naming_context_.unbind ("resetCount"); +} +// Listing 1 + +// Listing 2 code/ch21 +void Temperature_Monitor2::record_history (float temp) +{ + int now = (int)ACE_OS::time (); + this->shared_context_.rebind ("lastUpdate", now); + + Name_Binding_Ptr counter + (this->shared_context_.fetch ("counter")); + int counterValue = counter.get () ? counter->int_value () : 0; + + char name[BUFSIZ]; + ACE_OS::sprintf (name, "history[%d]", counterValue); + + char value[BUFSIZ]; + ACE_OS::sprintf (value, "%d|%.2f", now, temp); + + this->shared_context_.rebind (name, value); + + ++counterValue; + counterValue %= this->opt_.history_size (); + this->shared_context_.rebind ("counter", counterValue); +} +// Listing 2 + +void Temperature_Monitor2::reset_device (Name_Binding_Ptr &resetCount) +{ + int number_of_resets = 1; + + if (resetCount.get ()) + { + number_of_resets = resetCount->int_value () + 1; + + if (number_of_resets > this->opt_.excessive_resets ()) + { + EMail notification; + + char message[BUFSIZ]; + ACE_OS::sprintf (message, + "Thermometer: %s\n" + "Reset Count: %d\n", + this->thermometer_->address (), + number_of_resets); + + notification.send (this->opt_.admin_email (), + this->opt_.email_from (), + "Excessive number of thermometer resets", + message); + } + } + + this->thermometer_->reset (); + + this->naming_context_.rebind ("lastReset", (int)ACE_OS::time ()); + this->naming_context_.rebind ("resetCount", number_of_resets); +} + +void Temperature_Monitor2::record_failure (void) +{ + Name_Binding_Ptr lastFailure (this->naming_context_.fetch ("lastFailure")); + Name_Binding_Ptr lastReset (this->naming_context_.fetch ("lastReset")); + Name_Binding_Ptr resetCount (this->naming_context_.fetch ("resetCount")); + + int now = ACE_OS::time (); + + int lastFailureTime; + int lastResetTime = 0; + + if (lastFailure.get ()) + { + lastFailureTime = lastFailure->int_value (); + } + else + { + this->naming_context_.rebind ("firstFailure", now); + this->naming_context_.rebind ("lastReset", now); + lastFailureTime = now; + lastResetTime = now; + } + + if (lastReset.get ()) + { + lastResetTime = lastReset->int_value (); + } + + if (now - lastResetTime > this->opt_.reset_interval ()) + { + this->reset_device (resetCount); + } + + this->naming_context_.rebind ("lastFailure", now); +} + +void Temperature_Monitor2::monitor (void) +{ + this->thermometer_ = new Thermometer (this->opt_.thermometer_address ()); + + for (;;) + { + float temp = this->thermometer_->temperature (); + + ACE_DEBUG ((LM_INFO, ACE_TEXT ("Read temperature %.2f\n"), temp)); + + if (temp >= 0) + { + this->record_temperature (temp); + } + else + { + this->record_failure (); + } + + ACE_OS::sleep (this->opt_.poll_interval ()); + } + + delete this->thermometer_; +} diff --git a/ACE/examples/APG/Naming/Temperature_Monitor2.h b/ACE/examples/APG/Naming/Temperature_Monitor2.h new file mode 100644 index 00000000000..b887e5c8e4c --- /dev/null +++ b/ACE/examples/APG/Naming/Temperature_Monitor2.h @@ -0,0 +1,36 @@ +// $Id$ + +#ifndef TEMPERATURE_MONITOR_H +#define TEMPERATURE_MONITOR_H + +#include "Thermometer.h" +#include "Temperature_Monitor_Options.h" +#include "Naming_Context.h" + +class Temperature_Monitor2 +{ +public: + Temperature_Monitor2 (Temperature_Monitor_Options & opt, + Naming_Context & naming_context, + Naming_Context & shared_context) + : opt_(opt), + naming_context_(naming_context), + shared_context_(shared_context) + { } + + void monitor (void); + +protected: + void record_temperature (float temp); + void record_history (float temp); + void record_failure (void); + void reset_device (Name_Binding_Ptr & resetCount); + +private: + Thermometer *thermometer_; + Temperature_Monitor_Options &opt_; + Naming_Context &naming_context_; + Naming_Context &shared_context_; +}; + +#endif /* TEMPERATURE_MONITOR_H */ diff --git a/ACE/examples/APG/Naming/Temperature_Monitor_Options.h b/ACE/examples/APG/Naming/Temperature_Monitor_Options.h new file mode 100644 index 00000000000..95fb82faa9b --- /dev/null +++ b/ACE/examples/APG/Naming/Temperature_Monitor_Options.h @@ -0,0 +1,48 @@ +// $Id$ + +#ifndef TEMPERATURE_MONITOR_OPTIONS_H +#define TEMPERATURE_MONITOR_OPTIONS_H + +class Temperature_Monitor_Options + { + public: + Temperature_Monitor_Options (int, ACE_TCHAR *[]) + { } + + const char *thermometer_address (void) + { + return "serial:// s0/0x3e52"; + } + + int poll_interval (void) + { + return 10; // every 10 seconds + } + + int reset_interval (void) + { + return 60; // sixty seconds + } + + int excessive_resets (void) + { + return 5; // no response in 5 minutes + } + + const char *admin_email (void) + { + return "root@localhost"; + } + + const char *email_from (void) + { + return "temperature monitor"; + } + + int history_size() + { + return 10; + } + }; + +#endif /* TEMPERATURE_MONITOR_OPTIONS_H */ diff --git a/ACE/examples/APG/Naming/Thermometer.h b/ACE/examples/APG/Naming/Thermometer.h new file mode 100644 index 00000000000..cfdf1ca0f3d --- /dev/null +++ b/ACE/examples/APG/Naming/Thermometer.h @@ -0,0 +1,48 @@ +/* -*- C++ -*- */ +// $Id$ + +#ifndef THERMOMETER_H +#define THERMOMETER_H + +#include "ace/OS_NS_stdlib.h" +#include "ace/Log_Msg.h" + +class Thermometer +{ +public: + Thermometer (const char *addr) + : addr_(addr), threshold_(5) + { } + + float temperature (void) + { + int success = ACE_OS::rand () % 10; + if (success < this->threshold_) + { + this->threshold_ = 7; + return -1.0; + } + + this->threshold_ = 3; + int itemp = 80 + ACE_OS::rand () % 10; // 80 <= t <= 90 + return (float)itemp; + } + + const char *address (void) + { + return this->addr_; + } + + void reset (void) + { + this->threshold_ = 4; + ACE_DEBUG ((LM_ERROR, ACE_TEXT ("Resetting thermometer %C\n"), + this->address ())); + } + +private: + const char *addr_; + int threshold_; +}; + +#endif /* THERMOMETER_H */ diff --git a/ACE/examples/APG/Naming/naming.mpc b/ACE/examples/APG/Naming/naming.mpc new file mode 100644 index 00000000000..fda823954fc --- /dev/null +++ b/ACE/examples/APG/Naming/naming.mpc @@ -0,0 +1,50 @@ +// -*- MPC -*- +// $Id$ + +project(Netlocal) : aceexe { + avoids += ace_for_tao + exename = Netlocal + Source_Files { + Netlocal.cpp + Temperature_Monitor2.cpp + } +} + +project(Netlocal Reader) : aceexe { + avoids += ace_for_tao + exename = Netlocal_reader + Source_Files { + Netlocal_reader.cpp + Graph.cpp + Temperature_Grapher.cpp + } +} + +project(Nodelocal) : aceexe { + avoids += ace_for_tao + exename = Nodelocal + Source_Files { + Nodelocal.cpp + Temperature_Monitor.cpp + } +} + +project(Nodelocal Shared) : aceexe { + avoids += ace_for_tao + exename = Nodelocal_shared + Source_Files { + Nodelocal_shared.cpp + Temperature_Monitor2.cpp + } +} + +project(Nodelocal Shared Reader) : aceexe { + avoids += ace_for_tao + exename = Nodelocal_shared_reader + Source_Files { + Nodelocal_shared_reader.cpp + Graph.cpp + Temperature_Grapher.cpp + Temperature_Monitor.cpp + } +} diff --git a/ACE/examples/APG/Naming/svc.conf b/ACE/examples/APG/Naming/svc.conf new file mode 100644 index 00000000000..550ef992177 --- /dev/null +++ b/ACE/examples/APG/Naming/svc.conf @@ -0,0 +1 @@ +dynamic Name_Server Service_Object * netsvcs:_make_ACE_Name_Acceptor() "-p 20012" diff --git a/ACE/examples/APG/Proactor/.cvsignore b/ACE/examples/APG/Proactor/.cvsignore new file mode 100644 index 00000000000..64b35fb3d57 --- /dev/null +++ b/ACE/examples/APG/Proactor/.cvsignore @@ -0,0 +1,2 @@ +HA_Proactive_Status +HA_Proactive_Status diff --git a/ACE/examples/APG/Proactor/HA_Proactive_Status.cpp b/ACE/examples/APG/Proactor/HA_Proactive_Status.cpp new file mode 100644 index 00000000000..9d9b9dfb0e5 --- /dev/null +++ b/ACE/examples/APG/Proactor/HA_Proactive_Status.cpp @@ -0,0 +1,163 @@ +/* +** $Id$ +** +** Example program from The ACE Programmer's Guide, Chapter 8. +** Copyright 2003 Addison-Wesley. All Rights Reserved. +*/ + +#include "HA_Proactive_Status.h" +#include "ace/Log_Msg.h" +#include "ace/Message_Block.h" +#include "ace/Proactor.h" +#include "ace/os_include/arpa/os_inet.h" + +#if (defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)) || (defined (ACE_HAS_AIO_CALLS)) + +// Listing 1 code/ch08 +void +HA_Proactive_Service::open (ACE_HANDLE h, ACE_Message_Block&) +{ + this->handle (h); + if (this->reader_.open (*this) != 0 || + this->writer_.open (*this) != 0 ) + { + ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), + ACE_TEXT ("HA_Proactive_Service open"))); + delete this; + return; + } + + ACE_Message_Block *mb; + ACE_NEW_NORETURN (mb, ACE_Message_Block (1024)); + if (this->reader_.read (*mb, mb->space ()) != 0) + { + ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), + ACE_TEXT ("HA_Proactive_Service begin read"))); + mb->release (); + delete this; + return; + } + + // mb is now controlled by Proactor framework. + return; +} +// Listing 1 + +// Listing 2 code/ch08 +void +HA_Proactive_Service::handle_read_stream + (const ACE_Asynch_Read_Stream::Result &result) +{ + ACE_Message_Block &mb = result.message_block (); + if (!result.success () || result.bytes_transferred () == 0) + { + mb.release (); + delete this; + } + else + { + if (this->writer_.write (mb, mb.length ()) != 0) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("starting write"))); + mb.release (); + } + else + { + ACE_Message_Block *new_mb; + ACE_NEW_NORETURN (new_mb, ACE_Message_Block (1024)); + this->reader_.read (*new_mb, new_mb->space ()); + } + } + return; +} +// Listing 2 + +// Listing 3 code/ch08 +void +HA_Proactive_Service::handle_write_stream +(const ACE_Asynch_Write_Stream::Result &result) +{ + result.message_block ().release (); + return; +} +// Listing 3 + +// The network address check only works for BSD-ish systems. This +// sort of network number accessor should be added to ACE_INET_Addr +// at some point... +#if defined (ACE_WIN32) +int +HA_Proactive_Acceptor::validate_connection +(const ACE_Asynch_Accept::Result&, + const ACE_INET_Addr&, + const ACE_INET_Addr&) +{ + return 0; +} +#else + +// Listing 4 code/ch08 +int +HA_Proactive_Acceptor::validate_connection ( + const ACE_Asynch_Accept::Result&, + const ACE_INET_Addr& remote, + const ACE_INET_Addr& local) +{ + struct in_addr *remote_addr = + reinterpret_cast<struct in_addr*> (remote.get_addr ()); + struct in_addr *local_addr = + reinterpret_cast<struct in_addr*> (local.get_addr ()); + if (inet_netof (*local_addr) == inet_netof (*remote_addr)) + return 0; + + return -1; +} +// Listing 4 + +#endif /* ACE_WIN32 */ + +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + // Listing 5 code/ch08 + ACE_INET_Addr listen_addr; // Set up with listen port + HA_Proactive_Acceptor aio_acceptor; + if (0 != aio_acceptor.open (listen_addr, + 0, // bytes_to_read + 0, // pass_addresses + ACE_DEFAULT_BACKLOG, + 1, // reuse_addr + 0, // proactor + 1)) // validate_new_connection + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), + ACE_TEXT ("acceptor open")), 1); + // Listing 5 + +#if 0 + // Listing 6 code/ch08 + ACE_INET_Addr peer_addr; // Set up peer addr + ACE_Asynch_Connector<HA_Proactive_Service> aio_connect; + aio_connect.connect (peer_addr); + // Listing 6 +#endif + + // Listing 7 code/ch08 + ACE_Proactor::instance ()->proactor_run_event_loop (); + // Listing 7 + return 0; +} + +#else + +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("This example requires asynchronous I/O support.\n"))); + return 1; +} + +#endif /* (ACE_WIN32 && != ACE_HAS_WINCE) || ACE_HAS_AIO_CALLS*/ + diff --git a/ACE/examples/APG/Proactor/HA_Proactive_Status.h b/ACE/examples/APG/Proactor/HA_Proactive_Status.h new file mode 100644 index 00000000000..f66080b62cd --- /dev/null +++ b/ACE/examples/APG/Proactor/HA_Proactive_Status.h @@ -0,0 +1,87 @@ +/* -*- C++ -*- */ +/* +** $Id$ +** +** Example program from The ACE Programmer's Guide, Chapter 8. +** Copyright 2003 Addison-Wesley. All Rights Reserved. +*/ + +#ifndef __HA_PROACTIVE_STATUS_H +#define __HA_PROACTIVE_STATUS_H + +#include "ace/OS_NS_sys_socket.h" +#include "ace/Asynch_IO.h" +#include "ace/Service_Object.h" +// Listing 1 code/ch08 +#include "ace/Asynch_IO.h" + +#if (defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)) || (defined (ACE_HAS_AIO_CALLS)) + +class HA_Proactive_Service : public ACE_Service_Handler +{ +public: + ~HA_Proactive_Service () + { + if (this->handle () != ACE_INVALID_HANDLE) + ACE_OS::closesocket (this->handle ()); + } + + virtual void open (ACE_HANDLE h, ACE_Message_Block&); + + // This method will be called when an asynchronous read + // completes on a stream. + virtual void handle_read_stream + (const ACE_Asynch_Read_Stream::Result &result); + + // This method will be called when an asynchronous write + // completes on a stream. + virtual void handle_write_stream + (const ACE_Asynch_Write_Stream::Result &result); + +private: + ACE_Asynch_Read_Stream reader_; + ACE_Asynch_Write_Stream writer_; +}; +// Listing 1 + +// Listing 2 code/ch08 +#include "ace/Asynch_Acceptor.h" +#include "ace/INET_Addr.h" + +class HA_Proactive_Acceptor : + public ACE_Asynch_Acceptor<HA_Proactive_Service> +{ +public: + virtual int validate_connection + (const ACE_Asynch_Accept::Result& result, + const ACE_INET_Addr &remote, + const ACE_INET_Addr &local); +}; +// Listing 2 + +#endif /* (ACE_WIN32 && != ACE_HAS_WINCE) || ACE_HAS_AIO_CALLS*/ + +#if 0 +// Listing 3 code/ch08 +template <class HANDLER> +class ACE_Asynch_Acceptor : public ACE_Handler + ... +protected: + virtual HANDLER *make_handler (void) + { + return new HANDLER; + } +// Listing 3 +#endif + +class HA_Proactive_Status : public ACE_Service_Object +{ +public: + // Initializes object when dynamic linking occurs. + virtual int init (int argc, ACE_TCHAR *argv[]); + + // Terminates object when dynamic unlinking occurs. + virtual int fini (void); +}; + +#endif /* __HA_PROACTIVE_STATUS_H */ diff --git a/ACE/examples/APG/Proactor/Makefile.am b/ACE/examples/APG/Proactor/Makefile.am new file mode 100644 index 00000000000..a7632af1d4f --- /dev/null +++ b/ACE/examples/APG/Proactor/Makefile.am @@ -0,0 +1,39 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +ACE_BUILDDIR = $(top_builddir) +ACE_ROOT = $(top_srcdir) + + +## Makefile.HA_Proactive_Status.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS = HA_Proactive_Status + +HA_Proactive_Status_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +HA_Proactive_Status_SOURCES = \ + HA_Proactive_Status.cpp \ + HA_Proactive_Status.h + +HA_Proactive_Status_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Clean up template repositories, etc. +clean-local: + -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.* + -rm -f gcctemp.c gcctemp so_locations *.ics + -rm -rf cxx_repository ptrepository ti_files + -rm -rf templateregistry ir.out + -rm -rf ptrepository SunWS_cache Templates.DB diff --git a/ACE/examples/APG/Proactor/proactor.mpc b/ACE/examples/APG/Proactor/proactor.mpc new file mode 100644 index 00000000000..85ef950ae66 --- /dev/null +++ b/ACE/examples/APG/Proactor/proactor.mpc @@ -0,0 +1,10 @@ +// -*- MPC -*- +// $Id$ + +project(HA Proactive Status) : aceexe { + avoids += ace_for_tao + exename = HA_Proactive_Status + Source_Files { + HA_Proactive_Status.cpp + } +} diff --git a/ACE/examples/APG/Processes/.cvsignore b/ACE/examples/APG/Processes/.cvsignore new file mode 100644 index 00000000000..187cf413af2 --- /dev/null +++ b/ACE/examples/APG/Processes/.cvsignore @@ -0,0 +1,8 @@ +Process_Manager_Death +Process_Manager_Death +Process_Manager_Spawn +Process_Manager_Spawn +Process_Mutex +Process_Mutex +Spawn +Spawn diff --git a/ACE/examples/APG/Processes/Makefile.am b/ACE/examples/APG/Processes/Makefile.am new file mode 100644 index 00000000000..5c45a506304 --- /dev/null +++ b/ACE/examples/APG/Processes/Makefile.am @@ -0,0 +1,90 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +ACE_BUILDDIR = $(top_builddir) +ACE_ROOT = $(top_srcdir) + +noinst_PROGRAMS = + +## Makefile.Process_Manager_Death.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS += Process_Manager_Death + +Process_Manager_Death_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +Process_Manager_Death_SOURCES = \ + Process_Manager_Death.cpp + +Process_Manager_Death_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Makefile.Process_Manager_Spawn.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS += Process_Manager_Spawn + +Process_Manager_Spawn_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +Process_Manager_Spawn_SOURCES = \ + Process_Manager_Spawn.cpp + +Process_Manager_Spawn_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Makefile.Process_Mutex.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS += Process_Mutex + +Process_Mutex_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +Process_Mutex_SOURCES = \ + Process_Mutex.cpp + +Process_Mutex_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Makefile.Spawn.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS += Spawn + +Spawn_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +Spawn_SOURCES = \ + Spawn.cpp + +Spawn_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Clean up template repositories, etc. +clean-local: + -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.* + -rm -f gcctemp.c gcctemp so_locations *.ics + -rm -rf cxx_repository ptrepository ti_files + -rm -rf templateregistry ir.out + -rm -rf ptrepository SunWS_cache Templates.DB diff --git a/ACE/examples/APG/Processes/Process_Manager_Death.cpp b/ACE/examples/APG/Processes/Process_Manager_Death.cpp new file mode 100644 index 00000000000..51a8d911458 --- /dev/null +++ b/ACE/examples/APG/Processes/Process_Manager_Death.cpp @@ -0,0 +1,67 @@ +// $Id$ + +#include "ace/Log_Msg.h" +#include "ace/Process_Manager.h" +#include "ace/Reactor.h" + +static const int NCHILDREN = 2; + +// Listing 1 code/ch10 +class DeathHandler: public ACE_Event_Handler +{ +public: + DeathHandler () : count_(0) + { + ACE_TRACE (ACE_TEXT ("DeathHandler::DeathHandler")); + } + + virtual int handle_exit (ACE_Process * process) + { + ACE_TRACE (ACE_TEXT ("DeathHandler::handle_exit")); + + ACE_DEBUG + ((LM_DEBUG, + ACE_TEXT ("Process %d exited with exit code %d\n"), + process->getpid (), process->return_value ())); + + if (++count_ == NCHILDREN) + ACE_Reactor::instance ()->end_reactor_event_loop (); + + return 0; + } + +private: + int count_; +}; +// Listing 1 +// Listing 0 code/ch10 +int ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + if (argc > 1) // Running as a child. + return 0; + + // Instantiate a process manager with space for + // 10 processes. + ACE_Process_Manager pm (10, ACE_Reactor::instance ()); + + // Create a process termination handler. + DeathHandler handler; + + // Specify the options for the new processes to be spawned. + ACE_Process_Options options; + options.command_line (ACE_TEXT ("%s a"), argv[0]); + + // Spawn two child processes. + pid_t pids[NCHILDREN]; + pm.spawn_n (NCHILDREN, options, pids); + + // Register handler to be called when these processes exit. + for (int i = 0; i < NCHILDREN; i++) + pm.register_handler (&handler, pids[i]); + + // Run the reactor event loop waiting for events to occur. + ACE_Reactor::instance ()->run_reactor_event_loop (); + + return 0; +} +// Listing 0 diff --git a/ACE/examples/APG/Processes/Process_Manager_Spawn.cpp b/ACE/examples/APG/Processes/Process_Manager_Spawn.cpp new file mode 100644 index 00000000000..dd61ae9bae8 --- /dev/null +++ b/ACE/examples/APG/Processes/Process_Manager_Spawn.cpp @@ -0,0 +1,59 @@ +// $Id$ + +#include "ace/OS_NS_unistd.h" +#include "ace/Log_Msg.h" +// Listing 0 code/ch10 +#include "ace/Process_Manager.h" + +static const int NCHILDREN = 2; + +int ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + if (argc > 1) // Running as a child. + { + ACE_OS::sleep (10); + } + else // Running as a parent. + { + // Get the processwide process manager. + ACE_Process_Manager* pm = ACE_Process_Manager::instance (); + + // Specify the options for the new processes + // to be spawned. + ACE_Process_Options options; + options.command_line (ACE_TEXT ("%s a"), argv[0]); + + // Spawn two child processes. + pid_t pids[NCHILDREN]; + pm->spawn_n (NCHILDREN, options, pids); + + // Destroy the first child. + pm->terminate (pids[0]); + + // Wait for the child we just terminated. + ACE_exitcode status; + pm->wait (pids[0], &status); + + // Get the results of the termination. + +#if !defined(ACE_WIN32) + if (WIFSIGNALED (status) != 0) + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("%d died because of a signal ") + ACE_TEXT ("of type %d\n"), + pids[0], WTERMSIG (status))); +#else + ACE_DEBUG + ((LM_DEBUG, + ACE_TEXT ("The process terminated with exit code %d\n"), + status)); +#endif /*ACE_WIN32*/ + + // Wait for all (only one left) of the + // children to exit. + pm->wait (0); + } + + return 0; +} +// Listing 0 diff --git a/ACE/examples/APG/Processes/Process_Mutex.cpp b/ACE/examples/APG/Processes/Process_Mutex.cpp new file mode 100644 index 00000000000..2afb89803b9 --- /dev/null +++ b/ACE/examples/APG/Processes/Process_Mutex.cpp @@ -0,0 +1,79 @@ +// $Id$ + +#include "ace/OS_NS_unistd.h" +#include "ace/Log_Msg.h" +#include "ace/Process.h" +#include "ace/Process_Mutex.h" + +// Listing 1 code/ch10 +class GResourceUser +{ +public: + GResourceUser (ACE_Process_Mutex &mutex) : gmutex_(mutex) + { + ACE_TRACE (ACE_TEXT ("GResourceUser::GResourceUser")); + } + + void run (void) + { + ACE_TRACE (ACE_TEXT ("GResourceUser::run")); + + int count = 0; + while (count++ < 10) + { + int result = this->gmutex_.acquire (); + ACE_ASSERT (result == 0); + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P| %t) has the mutex\n"))); + + // Access Global resource + ACE_OS::sleep (1); + + result = this->gmutex_.release (); + ACE_ASSERT (result == 0); + ACE_OS::sleep (1); // Give other process a chance. + } + } + +private: + ACE_Process_Mutex &gmutex_; +}; +// Listing 1 + +// Listing 0 code/ch10 +int ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + if (argc > 1) // Run as the child. + { + // Create or get the global mutex. + ACE_Process_Mutex mutex ("GlobalMutex"); + + GResourceUser acquirer (mutex); + acquirer.run (); + } + else // Run as the parent. + { + ACE_Process_Options options; + options.command_line (ACE_TEXT ("%s a"), argv[0]); + ACE_Process processa, processb; + + pid_t pida = processa.spawn (options); + pid_t pidb = processb.spawn (options); + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("Spawned processes; pids %d:%d\n"), + pida, pidb)); + + if (processa.wait() == -1) + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), + ACE_TEXT ("processa wait")), -1); + + if (processb.wait() == -1) + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), + ACE_TEXT ("processb wait")), -1); + } + + return 0; +} +// Listing 0 diff --git a/ACE/examples/APG/Processes/Spawn.cpp b/ACE/examples/APG/Processes/Spawn.cpp new file mode 100644 index 00000000000..0776a44a8ec --- /dev/null +++ b/ACE/examples/APG/Processes/Spawn.cpp @@ -0,0 +1,206 @@ +// $Id$ + +#include "ace/OS_NS_stdio.h" +#include "ace/OS_NS_fcntl.h" +#include "ace/OS_NS_pwd.h" +#include "ace/os_include/os_pwd.h" +#include "ace/OS_NS_stdlib.h" +#include "ace/OS_NS_string.h" +#include "ace/OS_NS_unistd.h" +#include "ace/Process.h" +#include "ace/Log_Msg.h" + +// Listing 1 code/ch10 +class Manager : public ACE_Process +{ +public: + Manager (const ACE_TCHAR* program_name) + { + ACE_TRACE ("Manager::Manager"); + ACE_OS::strcpy (programName_, program_name); + } + + int doWork (void) + { + ACE_TRACE ("Manager::doWork"); + + // Spawn the new process; prepare() hook is called first. + ACE_Process_Options options; + pid_t pid = this->spawn (options); + if (pid == ACE_INVALID_PID) + ACE_ERROR_RETURN((LM_ERROR, ACE_TEXT ("%p\n"), + ACE_TEXT ("spawn")), -1); + + // Wait forever for my child to exit. + if (this->wait () == -1) + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), + ACE_TEXT ("wait")), -1); + + // Dump whatever happened. + this->dumpRun (); + return 0; + } +// Listing 1 + +private: + // Listing 3 code/ch10 + int dumpRun (void) + { + ACE_TRACE ("Manager::dumpRun"); + + if (ACE_OS::lseek (this->outputfd_, 0, SEEK_SET) == -1) + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), + ACE_TEXT ("lseek")), -1); + + char buf[1024]; + ssize_t length = 0; + + // Read the contents of the error stream written + // by the child and print it out. + while ((length = ACE_OS::read (this->outputfd_, + buf, sizeof(buf)-1)) > 0) + { + buf[length] = 0; + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("%C\n"), buf)); + } + + ACE_OS::close (this->outputfd_); + return 0; + } + // Listing 3 + + // Listing 2 code/ch10 + // prepare() is inherited from ACE_Process. + int prepare (ACE_Process_Options &options) + { + ACE_TRACE ("Manager::prepare"); + + options.command_line (ACE_TEXT ("%s 1"), this->programName_); + if (this->setStdHandles (options) == -1 || + this->setEnvVariable (options) == -1) + return -1; +#if !defined (ACE_WIN32) && !defined (ACE_LACKS_PWD_FUNCTIONS) + return this->setUserID (options); +#else + return 0; +#endif + } + + int setStdHandles (ACE_Process_Options &options) + { + ACE_TRACE ("Manager::setStdHandles"); + + ACE_OS::unlink ("output.dat"); + this->outputfd_ = + ACE_OS::open ("output.dat", O_RDWR | O_CREAT); + return options.set_handles + (ACE_STDIN, ACE_STDOUT, this->outputfd_); + } + + int setEnvVariable (ACE_Process_Options &options) + { + ACE_TRACE ("Manager::setEnvVariables"); + return options.setenv + (ACE_TEXT ("PRIVATE_VAR=/that/seems/to/be/it")); + } + // Listing 2 + +#if !defined (ACE_LACKS_PWD_FUNCTIONS) + // Listing 10 code/ch10 + int setUserID (ACE_Process_Options &options) + { + ACE_TRACE ("Manager::setUserID"); + passwd* pw = ACE_OS::getpwnam ("nobody"); + if (pw == 0) + return -1; + options.seteuid (pw->pw_uid); + return 0; + } + // Listing 10 +#endif /* !ACE_LACKS_PWD_FUNCTIONS */ + +private: + ACE_HANDLE outputfd_; + ACE_TCHAR programName_[256]; +}; + +// Listing 4 code/ch10 +class Slave +{ +public: + Slave () + { + ACE_TRACE ("Slave::Slave"); + } + + int doWork (void) + { + ACE_TRACE ("Slave::doWork"); + + ACE_DEBUG ((LM_INFO, + ACE_TEXT ("(%P) started at %T, parent is %d\n"), + ACE_OS::getppid ())); + this->showWho (); + ACE_DEBUG ((LM_INFO, + ACE_TEXT ("(%P) the private environment is %s\n"), + ACE_OS::getenv ("PRIVATE_VAR"))); + + ACE_TCHAR str[128]; + ACE_OS::sprintf (str, ACE_TEXT ("(%d) Enter your command\n"), + static_cast<int>(ACE_OS::getpid ())); + ACE_OS::write (ACE_STDOUT, str, ACE_OS::strlen (str)); + this->readLine (str); + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P) Executed: %C\n"), + str)); + return 0; + } +// Listing 4 + + void showWho (void) + { + ACE_TRACE ("Slave::showWho"); +#if !defined (ACE_LACKS_PWD_FUNCTIONS) + passwd *pw = ::getpwuid (::geteuid ()); + ACE_DEBUG ((LM_INFO, + ACE_TEXT ("(%P) Running this process as:%s\n"), + pw->pw_name)); +#endif + } + + ACE_TCHAR* readLine (ACE_TCHAR* str) + { + ACE_TRACE ("Slave::readLine"); + + int i = 0; + while (true) + { + ssize_t retval = ACE_OS::read (ACE_STDIN, &str[i], 1); + if (retval > 0) + { + if (str[i] == '\n') + { + str[++i] = 0; + return str; + } + i++; + } + else + return str; + } + } +}; + +// Listing 0 code/ch10 +int ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + if (argc > 1) // Slave mode + { + Slave s; + return s.doWork (); + } + + // Else, Master mode + Manager m (argv[0]); + return m.doWork (); +} +// Listing 0 diff --git a/ACE/examples/APG/Processes/processes.mpc b/ACE/examples/APG/Processes/processes.mpc new file mode 100644 index 00000000000..a7cb01040bb --- /dev/null +++ b/ACE/examples/APG/Processes/processes.mpc @@ -0,0 +1,34 @@ +// -*- MPC -*- +// $Id$ + +project(Process Manager Death) : aceexe { + avoids += ace_for_tao + exename = Process_Manager_Death + Source_Files { + Process_Manager_Death.cpp + } +} + +project(Process Manager Spawn) : aceexe { + avoids += ace_for_tao + exename = Process_Manager_Spawn + Source_Files { + Process_Manager_Spawn.cpp + } +} + +project(Process Mutex) : aceexe { + avoids += ace_for_tao + exename = Process_Mutex + Source_Files { + Process_Mutex.cpp + } +} + +project(Spawn) : aceexe { + avoids += ace_for_tao + exename = Spawn + Source_Files { + Spawn.cpp + } +} diff --git a/ACE/examples/APG/Reactor/.cvsignore b/ACE/examples/APG/Reactor/.cvsignore new file mode 100644 index 00000000000..c2d63b45dcf --- /dev/null +++ b/ACE/examples/APG/Reactor/.cvsignore @@ -0,0 +1,16 @@ +Client +Client +HAStatus +HAStatus +HAStatus-AC +HAStatus-AC +Reschedule +Reschedule +Schedule_Timers +Schedule_Timers +Timer_Cancel +Timer_Cancel +Timer_State_Data +Timer_State_Data +Timers +Timers diff --git a/ACE/examples/APG/Reactor/Client.cpp b/ACE/examples/APG/Reactor/Client.cpp new file mode 100644 index 00000000000..b2773bbf7f3 --- /dev/null +++ b/ACE/examples/APG/Reactor/Client.cpp @@ -0,0 +1,118 @@ +/** + * $Id$ + * + * A simple client program using ACE_Svc_Handler and ACE_Connector. + */ + +#include "ace/OS_NS_stdio.h" +#include "ace/OS_NS_errno.h" +#include "ace/OS_NS_string.h" +#include "ace/OS_NS_sys_time.h" +#include "Client.h" + +// Listing 2 code/ch07 +int Client::open (void *p) +{ + ACE_Time_Value iter_delay (2); // Two seconds + if (super::open (p) == -1) + return -1; + this->notifier_.reactor (this->reactor ()); + this->msg_queue ()->notification_strategy (&this->notifier_); + this->iterations_ = 0; + return this->reactor ()->schedule_timer + (this, 0, ACE_Time_Value::zero, iter_delay); +} +// Listing 2 + +// Listing 3 code/ch07 +int Client::handle_input (ACE_HANDLE) +{ + char buf[64]; + ssize_t recv_cnt = this->peer ().recv (buf, sizeof (buf) - 1); + if (recv_cnt > 0) + { + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("%.*C"), + static_cast<int> (recv_cnt), + buf)); + return 0; + } + + if (recv_cnt == 0 || ACE_OS::last_error () != EWOULDBLOCK) + { + this->reactor ()->end_reactor_event_loop (); + return -1; + } + return 0; +} +// Listing 3 + +// Listing 4 code/ch07 +int Client::handle_timeout(const ACE_Time_Value &, const void *) +{ + if (++this->iterations_ >= ITERATIONS) + { + this->peer ().close_writer (); + return 0; + } + + ACE_Message_Block *mb; + ACE_NEW_RETURN (mb, ACE_Message_Block (128), -1); + int nbytes = ACE_OS::sprintf + (mb->wr_ptr (), "Iteration %d\n", this->iterations_); + ACE_ASSERT (nbytes > 0); + mb->wr_ptr (static_cast<size_t> (nbytes)); + this->putq (mb); + return 0; +} +// Listing 4 + +// Listing 5 code/ch07 +int Client::handle_output (ACE_HANDLE) +{ + ACE_Message_Block *mb; + ACE_Time_Value nowait (ACE_OS::gettimeofday ()); + while (-1 != this->getq (mb, &nowait)) + { + ssize_t send_cnt = + this->peer ().send (mb->rd_ptr (), mb->length ()); + if (send_cnt == -1) + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("(%P|%t) %p\n"), + ACE_TEXT ("send"))); + else + mb->rd_ptr (static_cast<size_t> (send_cnt)); + if (mb->length () > 0) + { + this->ungetq (mb); + break; + } + mb->release (); + } + if (this->msg_queue ()->is_empty ()) + this->reactor ()->cancel_wakeup + (this, ACE_Event_Handler::WRITE_MASK); + else + this->reactor ()->schedule_wakeup + (this, ACE_Event_Handler::WRITE_MASK); + return 0; +} +// Listing 5 + +// Listing 6 code/ch07 +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_INET_Addr port_to_connect (ACE_TEXT ("HAStatus"), ACE_LOCALHOST); + ACE_Connector<Client, ACE_SOCK_CONNECTOR> connector; + Client client; + Client *pc = &client; + if (connector.connect (pc, port_to_connect) == -1) + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), + ACE_TEXT ("connect")), 1); + + ACE_Reactor::instance ()->run_reactor_event_loop (); + return (0); +} +// Listing 6 + +// Listing 7 code/ch07 +// Listing 7 diff --git a/ACE/examples/APG/Reactor/Client.h b/ACE/examples/APG/Reactor/Client.h new file mode 100644 index 00000000000..9aba262151a --- /dev/null +++ b/ACE/examples/APG/Reactor/Client.h @@ -0,0 +1,52 @@ +/** + * $Id$ + * + * Sample code from The ACE Programmer's Guide, + * copyright 2003 Addison-Wesley. All Rights Reserved. + */ + +#ifndef __CLIENT_H_ +#define __CLIENT_H_ + +#include "ace/Synch_Traits.h" +#include "ace/Null_Condition.h" +#include "ace/Null_Mutex.h" + +// Listing 1 code/ch07 +#include "ace/Reactor.h" +#include "ace/INET_Addr.h" +#include "ace/SOCK_Stream.h" +#include "ace/SOCK_Connector.h" +#include "ace/Connector.h" +#include "ace/Svc_Handler.h" +#include "ace/Reactor_Notification_Strategy.h" + +class Client : + public ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH> +{ + typedef ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH> super; + +public: + Client () : notifier_ (0, this, ACE_Event_Handler::WRITE_MASK) + {} + + virtual int open (void * = 0); + + // Called when input is available from the client. + virtual int handle_input (ACE_HANDLE fd = ACE_INVALID_HANDLE); + + // Called when output is possible. + virtual int handle_output (ACE_HANDLE fd = ACE_INVALID_HANDLE); + + // Called when a timer expires. + virtual int handle_timeout (const ACE_Time_Value ¤t_time, + const void *act = 0); + +private: + enum { ITERATIONS = 5 }; + int iterations_; + ACE_Reactor_Notification_Strategy notifier_; +}; +// Listing 1 + +#endif /* __CLIENT_H_ */ diff --git a/ACE/examples/APG/Reactor/ClientService.h b/ACE/examples/APG/Reactor/ClientService.h new file mode 100644 index 00000000000..f6ac96e9286 --- /dev/null +++ b/ACE/examples/APG/Reactor/ClientService.h @@ -0,0 +1,40 @@ +/** + * $Id$ + * + * Sample code from The ACE Programmer's Guide, + * copyright 2003 Addison-Wesley. All Rights Reserved. + */ + +#ifndef __CLIENTSERVICE_H_ +#define __CLIENTSERVICE_H_ + +#include "ace/Synch_Traits.h" +#include "ace/Null_Condition.h" +#include "ace/Null_Mutex.h" + +// Listing 3 code/ch07 +#include "ace/Message_Block.h" +#include "ace/SOCK_Stream.h" +#include "ace/Svc_Handler.h" + +class ClientService : + public ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH> +{ + typedef ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH> super; + +public: + int open (void * = 0); + + // Called when input is available from the client. + virtual int handle_input (ACE_HANDLE fd = ACE_INVALID_HANDLE); + + // Called when output is possible. + virtual int handle_output (ACE_HANDLE fd = ACE_INVALID_HANDLE); + + // Called when this handler is removed from the ACE_Reactor. + virtual int handle_close (ACE_HANDLE handle, + ACE_Reactor_Mask close_mask); +}; +// Listing 3 + +#endif /* __CLIENTSERVICE_H_ */ diff --git a/ACE/examples/APG/Reactor/HAStatus-AC.cpp b/ACE/examples/APG/Reactor/HAStatus-AC.cpp new file mode 100644 index 00000000000..c99a1c5036c --- /dev/null +++ b/ACE/examples/APG/Reactor/HAStatus-AC.cpp @@ -0,0 +1,139 @@ +// $Id$ + +#include "ace/OS_NS_errno.h" +#include "ace/OS_NS_sys_time.h" +#include "ace/os_include/os_netdb.h" +#include "ClientService.h" + +// Listing 1 code/ch07 +#include "ace/Log_Msg.h" +#include "ace/INET_Addr.h" +#include "ace/SOCK_Acceptor.h" +#include "ace/Reactor.h" +#include "ace/Acceptor.h" + +typedef ACE_Acceptor<ClientService, ACE_SOCK_ACCEPTOR> + ClientAcceptor; +// Listing 1 + +// Listing 4 code/ch07 +int +ClientService::open (void *p) +{ + if (super::open (p) == -1) + return -1; + + ACE_TCHAR peer_name[MAXHOSTNAMELEN]; + ACE_INET_Addr peer_addr; + if (this->peer ().get_remote_addr (peer_addr) == 0 && + peer_addr.addr_to_string (peer_name, MAXHOSTNAMELEN) == 0) + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Connection from %s\n"), + peer_name)); + return 0; +} +// Listing 4 + +// Listing 5 code/ch07 +int +ClientService::handle_input (ACE_HANDLE) +{ + const size_t INPUT_SIZE = 4096; + char buffer[INPUT_SIZE]; + ssize_t recv_cnt, send_cnt; + + recv_cnt = this->peer ().recv (buffer, sizeof(buffer)); + if (recv_cnt <= 0) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Connection closed\n"))); + return -1; + } + + send_cnt = + this->peer ().send (buffer, + static_cast<size_t> (recv_cnt)); + if (send_cnt == recv_cnt) + return 0; + if (send_cnt == -1 && ACE_OS::last_error () != EWOULDBLOCK) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("(%P|%t) %p\n"), + ACE_TEXT ("send")), + 0); + if (send_cnt == -1) + send_cnt = 0; + ACE_Message_Block *mb; + size_t remaining = + static_cast<size_t> ((recv_cnt - send_cnt)); + ACE_NEW_RETURN (mb, ACE_Message_Block (remaining), -1); + mb->copy (&buffer[send_cnt], remaining); + int output_off = this->msg_queue ()->is_empty (); + ACE_Time_Value nowait (ACE_OS::gettimeofday ()); + if (this->putq (mb, &nowait) == -1) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("(%P|%t) %p; discarding data\n"), + ACE_TEXT ("enqueue failed"))); + mb->release (); + return 0; + } + if (output_off) + return this->reactor ()->register_handler + (this, ACE_Event_Handler::WRITE_MASK); + return 0; +} +// Listing 5 + +// Listing 6 code/ch07 +int +ClientService::handle_output (ACE_HANDLE) +{ + ACE_Message_Block *mb; + ACE_Time_Value nowait (ACE_OS::gettimeofday ()); + while (-1 != this->getq (mb, &nowait)) + { + ssize_t send_cnt = + this->peer ().send (mb->rd_ptr (), mb->length ()); + if (send_cnt == -1) + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("(%P|%t) %p\n"), + ACE_TEXT ("send"))); + else + mb->rd_ptr (static_cast<size_t> (send_cnt)); + if (mb->length () > 0) + { + this->ungetq (mb); + break; + } + mb->release (); + } + return (this->msg_queue ()->is_empty ()) ? -1 : 0; +} +// Listing 6 + +// Listing 7 code/ch07 +int +ClientService::handle_close (ACE_HANDLE h, ACE_Reactor_Mask mask) +{ + if (mask == ACE_Event_Handler::WRITE_MASK) + return 0; + return super::handle_close (h, mask); +} +// Listing 7 + +// Listing 2 code/ch07 +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_INET_Addr port_to_listen ("HAStatus"); + ClientAcceptor acceptor; + if (acceptor.open (port_to_listen) == -1) + return 1; + + ACE_Reactor::instance ()->run_reactor_event_loop (); + + return (0); +} +// Listing 2 + +// Listing 8 code/ch07 +// Listing 8 diff --git a/ACE/examples/APG/Reactor/HAStatus.cpp b/ACE/examples/APG/Reactor/HAStatus.cpp new file mode 100644 index 00000000000..fb32aa61632 --- /dev/null +++ b/ACE/examples/APG/Reactor/HAStatus.cpp @@ -0,0 +1,332 @@ +// $Id$ + +#include "ace/OS_NS_sys_time.h" +#include "ace/os_include/os_netdb.h" + +// Listing 1 code/ch07 +#include "ace/Auto_Ptr.h" +#include "ace/Log_Msg.h" +#include "ace/INET_Addr.h" +#include "ace/SOCK_Acceptor.h" +#include "ace/Reactor.h" + +class ClientAcceptor : public ACE_Event_Handler +{ +public: + virtual ~ClientAcceptor (); + + int open (const ACE_INET_Addr &listen_addr); + + // Get this handler's I/O handle. + virtual ACE_HANDLE get_handle (void) const + { return this->acceptor_.get_handle (); } + + // Called when a connection is ready to accept. + virtual int handle_input (ACE_HANDLE fd = ACE_INVALID_HANDLE); + + // Called when this handler is removed from the ACE_Reactor. + virtual int handle_close (ACE_HANDLE handle, + ACE_Reactor_Mask close_mask); + +protected: + ACE_SOCK_Acceptor acceptor_; +}; +// Listing 1 + +// Listing 6 code/ch07 +#include "ace/Message_Block.h" +#include "ace/Message_Queue.h" +#include "ace/SOCK_Stream.h" +#include "ace/Synch.h" + +class ClientService : public ACE_Event_Handler +{ +public: + ACE_SOCK_Stream &peer (void) { return this->sock_; } + + int open (void); + + // Get this handler's I/O handle. + virtual ACE_HANDLE get_handle (void) const + { return this->sock_.get_handle (); } + + // Called when input is available from the client. + virtual int handle_input (ACE_HANDLE fd = ACE_INVALID_HANDLE); + + // Called when output is possible. + virtual int handle_output (ACE_HANDLE fd = ACE_INVALID_HANDLE); + + // Called when this handler is removed from the ACE_Reactor. + virtual int handle_close (ACE_HANDLE handle, + ACE_Reactor_Mask close_mask); + +protected: + ACE_SOCK_Stream sock_; + ACE_Message_Queue<ACE_NULL_SYNCH> output_queue_; +}; +// Listing 6 + +// Listing 5 code/ch07 +ClientAcceptor::~ClientAcceptor () +{ + this->handle_close (ACE_INVALID_HANDLE, 0); +} +// Listing 5 + +// Listing 2 code/ch07 +int +ClientAcceptor::open (const ACE_INET_Addr &listen_addr) +{ + if (this->acceptor_.open (listen_addr, 1) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("acceptor.open")), + -1); + return this->reactor ()->register_handler + (this, ACE_Event_Handler::ACCEPT_MASK); +} +// Listing 2 + +// Listing 3 code/ch07 +int +ClientAcceptor::handle_input (ACE_HANDLE) +{ + ClientService *client; + ACE_NEW_RETURN (client, ClientService, -1); + auto_ptr<ClientService> p (client); + + if (this->acceptor_.accept (client->peer ()) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("(%P|%t) %p\n"), + ACE_TEXT ("Failed to accept ") + ACE_TEXT ("client connection")), + -1); + p.release (); + client->reactor (this->reactor ()); + if (client->open () == -1) + client->handle_close (ACE_INVALID_HANDLE, 0); + return 0; +} +// Listing 3 + +// Listing 4 code/ch07 +int +ClientAcceptor::handle_close (ACE_HANDLE, ACE_Reactor_Mask) +{ + if (this->acceptor_.get_handle () != ACE_INVALID_HANDLE) + { + ACE_Reactor_Mask m = ACE_Event_Handler::ACCEPT_MASK | + ACE_Event_Handler::DONT_CALL; + this->reactor ()->remove_handler (this, m); + this->acceptor_.close (); + } + return 0; +} +// Listing 4 + +// Listing 7 code/ch07 +int +ClientService::open (void) +{ + ACE_TCHAR peer_name[MAXHOSTNAMELEN]; + ACE_INET_Addr peer_addr; + if (this->sock_.get_remote_addr (peer_addr) == 0 && + peer_addr.addr_to_string (peer_name, MAXHOSTNAMELEN) == 0) + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Connection from %s\n"), + peer_name)); + return this->reactor ()->register_handler + (this, ACE_Event_Handler::READ_MASK); +} +// Listing 7 + +// Listing 8 code/ch07 +int +ClientService::handle_input (ACE_HANDLE) +{ + const size_t INPUT_SIZE = 4096; + char buffer[INPUT_SIZE]; + ssize_t recv_cnt, send_cnt; + + if ((recv_cnt = this->sock_.recv (buffer, sizeof(buffer))) <= 0) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Connection closed\n"))); + return -1; + } + + send_cnt = + this->sock_.send (buffer, static_cast<size_t> (recv_cnt)); + if (send_cnt == recv_cnt) + return 0; + if (send_cnt == -1 && ACE_OS::last_error () != EWOULDBLOCK) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("(%P|%t) %p\n"), + ACE_TEXT ("send")), + 0); + if (send_cnt == -1) + send_cnt = 0; + ACE_Message_Block *mb; + size_t remaining = + static_cast<size_t> ((recv_cnt - send_cnt)); + ACE_NEW_RETURN (mb, ACE_Message_Block (remaining), -1); + mb->copy (&buffer[send_cnt], remaining); + int output_off = this->output_queue_.is_empty (); + ACE_Time_Value nowait (ACE_OS::gettimeofday ()); + if (this->output_queue_.enqueue_tail (mb, &nowait) == -1) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("(%P|%t) %p; discarding data\n"), + ACE_TEXT ("enqueue failed"))); + mb->release (); + return 0; + } + if (output_off) + return this->reactor ()->register_handler + (this, ACE_Event_Handler::WRITE_MASK); + return 0; +} +// Listing 8 + +// Listing 9 code/ch07 +int +ClientService::handle_output (ACE_HANDLE) +{ + ACE_Message_Block *mb; + ACE_Time_Value nowait (ACE_OS::gettimeofday ()); + while (0 == this->output_queue_.dequeue_head + (mb, &nowait)) + { + ssize_t send_cnt = + this->sock_.send (mb->rd_ptr (), mb->length ()); + if (send_cnt == -1) + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("(%P|%t) %p\n"), + ACE_TEXT ("send"))); + else + mb->rd_ptr (static_cast<size_t> (send_cnt)); + if (mb->length () > 0) + { + this->output_queue_.enqueue_head (mb); + break; + } + mb->release (); + } + return (this->output_queue_.is_empty ()) ? -1 : 0; +} +// Listing 9 + +// Listing 10 code/ch07 +int +ClientService::handle_close (ACE_HANDLE, ACE_Reactor_Mask mask) +{ + if (mask == ACE_Event_Handler::WRITE_MASK) + return 0; + mask = ACE_Event_Handler::ALL_EVENTS_MASK | + ACE_Event_Handler::DONT_CALL; + this->reactor ()->remove_handler (this, mask); + this->sock_.close (); + this->output_queue_.flush (); + delete this; + return 0; +} +// Listing 10 + +// Listing 12 code/ch07 +class LoopStopper : public ACE_Event_Handler +{ +public: + LoopStopper (int signum = SIGINT); + + // Called when object is signaled by OS. + virtual int handle_signal (int signum, + siginfo_t * = 0, + ucontext_t * = 0); +}; + +LoopStopper::LoopStopper (int signum) +{ + ACE_Reactor::instance ()->register_handler (signum, this); +} + +int +LoopStopper::handle_signal (int, siginfo_t *, ucontext_t *) +{ + ACE_Reactor::instance ()->end_reactor_event_loop (); + return 0; +} +// Listing 12 + +// Listing 13 code/ch07 +#include "ace/Signal.h" + +class LogSwitcher : public ACE_Event_Handler +{ +public: + LogSwitcher (int on_sig, int off_sig); + + // Called when object is signaled by OS. + virtual int handle_signal (int signum, + siginfo_t * = 0, + ucontext_t * = 0); + + // Called when an exceptional event occurs. + virtual int handle_exception (ACE_HANDLE fd = ACE_INVALID_HANDLE); + +private: + LogSwitcher () {} + + int on_sig_; // Signal to turn logging on + int off_sig_; // Signal to turn logging off + int on_off_; // 1 == turn on, 0 == turn off +}; + +LogSwitcher::LogSwitcher (int on_sig, int off_sig) + : on_sig_ (on_sig), off_sig_ (off_sig) +{ + ACE_Sig_Set sigs; + sigs.sig_add (on_sig); + sigs.sig_add (off_sig); + ACE_Reactor::instance ()->register_handler (sigs, this); +} +// Listing 13 + +// Listing 14 code/ch07 +int +LogSwitcher::handle_signal (int signum, siginfo_t *, ucontext_t *) +{ + if (signum == this->on_sig_ || signum == this->off_sig_) + { + this->on_off_ = signum == this->on_sig_; + ACE_Reactor::instance ()->notify (this); + } + return 0; +} +// Listing 14 + +// Listing 15 code/ch07 +int +LogSwitcher::handle_exception (ACE_HANDLE) +{ + if (this->on_off_) + ACE_LOG_MSG->clr_flags (ACE_Log_Msg::SILENT); + else + ACE_LOG_MSG->set_flags (ACE_Log_Msg::SILENT); + return 0; +} +// Listing 15 + +// Listing 11 code/ch07 +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_INET_Addr port_to_listen ("HAStatus"); + ClientAcceptor acceptor; + acceptor.reactor (ACE_Reactor::instance ()); + if (acceptor.open (port_to_listen) == -1) + return 1; + + ACE_Reactor::instance ()->run_reactor_event_loop (); + + return (0); +} +// Listing 11 diff --git a/ACE/examples/APG/Reactor/Makefile.am b/ACE/examples/APG/Reactor/Makefile.am new file mode 100644 index 00000000000..789c0ce7785 --- /dev/null +++ b/ACE/examples/APG/Reactor/Makefile.am @@ -0,0 +1,139 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +ACE_BUILDDIR = $(top_builddir) +ACE_ROOT = $(top_srcdir) + +## Makefile.Client.am +noinst_PROGRAMS = Client + +Client_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +Client_SOURCES = \ + Client.cpp \ + Client.h + +Client_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.HAStatus.am +noinst_PROGRAMS += HAStatus + +HAStatus_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +HAStatus_SOURCES = \ + HAStatus.cpp \ + Client.h \ + ClientService.h + +HAStatus_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.HAStatus_AC.am +noinst_PROGRAMS += HAStatus-AC + +HAStatus_AC_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +HAStatus_AC_SOURCES = \ + HAStatus-AC.cpp \ + Client.h \ + ClientService.h + +HAStatus_AC_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Reactor_Timers.am +noinst_PROGRAMS += Timers + +Timers_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +Timers_SOURCES = \ + Timers.cpp \ + Client.h \ + ClientService.h + +Timers_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Reschedule.am +noinst_PROGRAMS += Reschedule + +Reschedule_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +Reschedule_SOURCES = \ + Reschedule.cpp \ + Client.h \ + ClientService.h + +Reschedule_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Schedule_Timers.am +noinst_PROGRAMS += Schedule_Timers + +Schedule_Timers_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +Schedule_Timers_SOURCES = \ + Schedule_Timers.cpp \ + Client.h \ + ClientService.h + +Schedule_Timers_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Timer_Cancel.am +noinst_PROGRAMS += Timer_Cancel + +Timer_Cancel_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +Timer_Cancel_SOURCES = \ + Timer_Cancel.cpp \ + Client.h \ + ClientService.h + +Timer_Cancel_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Timer_State_Data.am +noinst_PROGRAMS += Timer_State_Data + +Timer_State_Data_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +Timer_State_Data_SOURCES = \ + Timer_State_Data.cpp \ + Client.h \ + ClientService.h + +Timer_State_Data_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Clean up template repositories, etc. +clean-local: + -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.* + -rm -f gcctemp.c gcctemp so_locations *.ics + -rm -rf cxx_repository ptrepository ti_files + -rm -rf templateregistry ir.out + -rm -rf ptrepository SunWS_cache Templates.DB diff --git a/ACE/examples/APG/Reactor/Reschedule.cpp b/ACE/examples/APG/Reactor/Reschedule.cpp new file mode 100644 index 00000000000..55ce1f74143 --- /dev/null +++ b/ACE/examples/APG/Reactor/Reschedule.cpp @@ -0,0 +1,83 @@ +/** + * $Id$ + * + * Changing the interval + */ + +#include "ace/OS_NS_time.h" +#include "ace/Log_Msg.h" +#include "ace/Reactor.h" +#include "ace/Event_Handler.h" + +class MyTimerHandler : public ACE_Event_Handler +{ +public: + int handle_timeout (const ACE_Time_Value ¤t_time, + const void * = 0 ) + { + time_t epoch = ((timespec_t)current_time).tv_sec; + ACE_DEBUG ((LM_INFO, + ACE_TEXT ("handle_timeout: %s"), + ACE_OS::ctime(&epoch))); + return 0; + } + +}; + +// Listing 1 code/ch07 +class SigintHandler : public ACE_Event_Handler +{ +public: + SigintHandler (long timerId, int currentInterval) + : ACE_Event_Handler(), + timerId_(timerId), + currentInterval_(currentInterval) + { + } + + int handle_signal (int, + siginfo_t * = 0, + ucontext_t * = 0) + { + ACE_DEBUG ((LM_INFO, + ACE_TEXT ("Resetting interval of timer ") + ACE_TEXT ("%d to %d\n"), + this->timerId_, + ++this->currentInterval_)); + ACE_Time_Value newInterval (this->currentInterval_); + ACE_Reactor::instance()-> + reset_timer_interval (this->timerId_, newInterval); + return 0; + } + +private: + long timerId_; + int currentInterval_; +}; +// Listing 1 + +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_Time_Value initialDelay (3); + ACE_Time_Value interval (5); + + // Listing 2 code/ch07 + MyTimerHandler *handler = new MyTimerHandler (); + + long timerId = + ACE_Reactor::instance ()->schedule_timer (handler, + 0, + initialDelay, + interval); + // Listing 2 + + // Listing 3 code/ch07 + SigintHandler *handleSigint = + new SigintHandler (timerId, 5); + ACE_Reactor::instance ()->register_handler (SIGINT, + handleSigint); + // Listing 3 + + ACE_Reactor::instance ()->run_reactor_event_loop (); + return 0; +} diff --git a/ACE/examples/APG/Reactor/Schedule_Timers.cpp b/ACE/examples/APG/Reactor/Schedule_Timers.cpp new file mode 100644 index 00000000000..5fa57ebfa07 --- /dev/null +++ b/ACE/examples/APG/Reactor/Schedule_Timers.cpp @@ -0,0 +1,65 @@ +/** + * $Id$ + * + * Scheduling timers with the Reactor + */ + +#include "ace/OS_NS_time.h" +#include "ace/Log_Msg.h" +#include "ace/Reactor.h" +#include "ace/Event_Handler.h" + +// Listing 1 code/ch07 +class MyTimerHandler : public ACE_Event_Handler +{ +public: + int handle_timeout (const ACE_Time_Value ¤t_time, + const void * = 0) + { + time_t epoch = ((timespec_t)current_time).tv_sec; + + ACE_DEBUG ((LM_INFO, + ACE_TEXT ("handle_timeout: %s\n"), + ACE_OS::ctime (&epoch))); + + return 0; + } +}; +// Listing 1 + +// Create a SIGINT handler so that we can exit +// the program politely +class SigintHandler : public ACE_Event_Handler +{ +public: + int handle_signal (int signum, siginfo_t * = 0, + ucontext_t * = 0) + { + if (signum == SIGINT) + { + ACE_Reactor::instance ()->end_reactor_event_loop (); + } + return 0; + } +}; + +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + // Listing 2 code/ch07 + MyTimerHandler * timer = new MyTimerHandler (); + ACE_Time_Value initialDelay (3); + ACE_Time_Value interval (5); + ACE_Reactor::instance()->schedule_timer (timer, + 0, + initialDelay, + interval); + // Listing 2 + + // Exclude 1 + SigintHandler * handleExit = new SigintHandler (); + ACE_Reactor::instance()->register_handler (SIGINT, + handleExit); + // Exclude 1 + ACE_Reactor::instance ()->run_reactor_event_loop (); + return 0; +} diff --git a/ACE/examples/APG/Reactor/Timer_Cancel.cpp b/ACE/examples/APG/Reactor/Timer_Cancel.cpp new file mode 100644 index 00000000000..3e6a0f2ec61 --- /dev/null +++ b/ACE/examples/APG/Reactor/Timer_Cancel.cpp @@ -0,0 +1,106 @@ +/** + * $Id$ + * + * Changing the interval and canceling + */ + +#include "ace/OS_NS_time.h" +#include "ace/Log_Msg.h" +#include "ace/Reactor.h" +#include "ace/Event_Handler.h" + +class MyTimerHandler : public ACE_Event_Handler +{ +public: + int handle_timeout (const ACE_Time_Value ¤t_time, + const void * = 0) + { + time_t epoch = ((timespec_t)current_time).tv_sec; + ACE_DEBUG ((LM_INFO, + ACE_TEXT ("handle_timeout: %s"), + ACE_OS::ctime(&epoch))); + return 0; + } + +}; + +#if !defined (ACE_LACKS_UNIX_SIGNALS) + +// Listing 1 code/ch07 +class SignalHandler : public ACE_Event_Handler +{ +public: + SignalHandler (long timerId, int currentInterval) + : ACE_Event_Handler(), + timerId_(timerId), + currentInterval_(currentInterval) + { + } + + int handle_signal (int sig, + siginfo_t * = 0, + ucontext_t * = 0) + { + if (sig == SIGINT) + { + ACE_DEBUG ((LM_INFO, + ACE_TEXT ("Resetting interval of timer ") + ACE_TEXT ("%d to %d\n"), + this->timerId_, + ++this->currentInterval_)); + ACE_Time_Value newInterval (this->currentInterval_); + ACE_Reactor::instance ()-> + reset_timer_interval (this->timerId_, newInterval); + } + else if (sig == SIGTSTP) + { + ACE_DEBUG ((LM_INFO, + ACE_TEXT ("Canceling timer %d\n"), + this->timerId_)); + ACE_Reactor::instance ()->cancel_timer (this->timerId_); + } + + return 0; + } + +private: + long timerId_; + int currentInterval_; +}; +// Listing 1 + +#endif /* ACE_LACKS_UNIX_SIGNALS */ + + +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_Time_Value initialDelay (3); + ACE_Time_Value interval (5); + + // Listing 2 code/ch07 + MyTimerHandler *handler = new MyTimerHandler (); + long timerId = + ACE_Reactor::instance ()->schedule_timer (handler, + 0, + initialDelay, + interval); + // Listing 2 + +#if !defined (ACE_LACKS_UNIX_SIGNALS) + + // Listing 3 code/ch07 + SignalHandler *mutateTimer = + new SignalHandler (timerId, 5); + ACE_Reactor::instance ()->register_handler (SIGINT, + mutateTimer); + ACE_Reactor::instance ()->register_handler (SIGTSTP, + mutateTimer); + // Listing 3 + +#else + ACE_UNUSED_ARG (timerId); +#endif /* ACE_LACKS_UNIX_SIGNALS */ + + ACE_Reactor::instance ()->run_reactor_event_loop (); + return 0; +} diff --git a/ACE/examples/APG/Reactor/Timer_State_Data.cpp b/ACE/examples/APG/Reactor/Timer_State_Data.cpp new file mode 100644 index 00000000000..215381df394 --- /dev/null +++ b/ACE/examples/APG/Reactor/Timer_State_Data.cpp @@ -0,0 +1,153 @@ +/** + * $Id$ + * + * Reactor examples + * + * Timers & state data + */ + +#include "ace/OS_NS_time.h" +#include "ace/Log_Msg.h" +#include "ace/Reactor.h" +#include "ace/Event_Handler.h" + +// Listing 0 code/ch07 +class TemperatureSensor +{ +public: + TemperatureSensor (const char *location) + : location_(location), + count_(0), + temperature_(0.0) + // ... + { } + + const char *location () const + { + return this->location_; + } + + int querySensor (void) + { + // ... + return ++this->count_; + } + + float temperature (void) const + { + return this->temperature_; + } + +private: + const char *location_; + int count_; + float temperature_; + // ... +}; +// Listing 0 + +// Listing 1 code/ch07 +class TemperatureQueryHandler : public ACE_Event_Handler +{ +public: + TemperatureQueryHandler () + : ACE_Event_Handler(), + counter_(0), + averageTemperature_(0.0) + // ... + { + } + + int handle_timeout (const ACE_Time_Value ¤t_time, + const void *arg) + { + time_t epoch = ((timespec_t)current_time).tv_sec; + + const TemperatureSensor *const_sensor = + reinterpret_cast<const TemperatureSensor *> (arg); + TemperatureSensor *sensor = + const_cast<TemperatureSensor *> (const_sensor); + + int queryCount = sensor->querySensor (); + this->updateAverageTemperature (sensor); + + ACE_DEBUG ((LM_INFO, + ACE_TEXT ("%s\t") + ACE_TEXT ("%d/%d\t") + ACE_TEXT ("%.2f/%.2f\t") + ACE_TEXT ("%s\n"), + sensor->location (), + ++this->counter_, + queryCount, + this->averageTemperature_, + sensor->temperature (), + ACE_OS::ctime(&epoch))); + return 0; + } + +private: + void updateAverageTemperature (TemperatureSensor *) + { + // ... + } + + int counter_; + float averageTemperature_; +}; +// Listing 1 + +// Create a SIGINT handler so that we can exit +// the program politely +class SigintHandler : public ACE_Event_Handler +{ +public: + int handle_signal (int signum, siginfo_t * = 0, + ucontext_t * = 0) + { + if (signum == SIGINT) + { + ACE_Reactor::instance ()->end_reactor_event_loop (); + } + return 0; + } +}; + +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + // Listing 2 code/ch07 + TemperatureQueryHandler *temperatureMonitor = + new TemperatureQueryHandler (); + // Listing 2 + + ACE_Time_Value initialDelay (3); + ACE_Time_Value intervalOne (5); + // Listing 3 code/ch07 + TemperatureSensor *sensorOne = + new TemperatureSensor ("Kitchen"); + + ACE_Reactor::instance ()->schedule_timer (temperatureMonitor, + sensorOne, + initialDelay, + intervalOne); + // Listing 3 + + ACE_Time_Value intervalTwo (4); + // Listing 4 code/ch07 + TemperatureSensor *sensorTwo = + new TemperatureSensor ("Foyer"); + + ACE_Reactor::instance ()->schedule_timer (temperatureMonitor, + sensorTwo, + initialDelay, + intervalTwo); + // Listing 4 + + SigintHandler *handleExit = new SigintHandler (); + + ACE_Reactor::instance ()->register_handler (SIGINT, + handleExit); + + ACE_Reactor::instance ()->run_reactor_event_loop (); + + return 0; +} diff --git a/ACE/examples/APG/Reactor/Timers.cpp b/ACE/examples/APG/Reactor/Timers.cpp new file mode 100644 index 00000000000..c603b86bef4 --- /dev/null +++ b/ACE/examples/APG/Reactor/Timers.cpp @@ -0,0 +1,81 @@ +// $Id$ + +#include "ace/config-all.h" +#include "ace/OS_main.h" + +#if !defined (ACE_LACKS_FORK) + +#include "ace/streams.h" + +#include <signal.h> +#include <sys/types.h> +#include <unistd.h> +#include <time.h> + +typedef void (*timerTask_t)(void); + +// Listing 1 code/ch07 +pid_t timerTask (int initialDelay, + int interval, + timerTask_t task) +{ + if (initialDelay < 1 && interval < 1) + return -1; + + pid_t pid = fork (); + + if (pid < 0) + return -1; + + if (pid > 0) + return pid; + + if (initialDelay > 0) + sleep (initialDelay); + + if (interval < 1) + return 0; + + while (1) + { + (*task) (); + sleep (interval); + } + + ACE_NOTREACHED (return 0); +} +// Listing 1 + +// Listing 2 code/ch07 +void foo () +{ + time_t now = time (0); + cerr << "The time is " << ctime (&now) << endl; +} +// Listing 2 + +void programMainLoop (void) +{ + sleep (30); +} + +// Listing 3 code/ch07 +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + pid_t timerId = timerTask (3, 5, foo); + programMainLoop (); + kill (timerId, SIGINT); + return 0; +} +// Listing 3 + +#else +#include <stdio.h> + +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + puts ("This very unportable example requires fork().\n"); + return 0; +} + +#endif /* ACE_LACKS_FORK */ diff --git a/ACE/examples/APG/Reactor/reactor.mpc b/ACE/examples/APG/Reactor/reactor.mpc new file mode 100644 index 00000000000..7454f9d5c9f --- /dev/null +++ b/ACE/examples/APG/Reactor/reactor.mpc @@ -0,0 +1,58 @@ +// -*- MPC -*- +// $Id$ + +project(Client) : aceexe { + exename = Client + Source_Files { + Client.cpp + } +} + +project(HAStatus) : aceexe { + exename = HAStatus + Source_Files { + HAStatus.cpp + } +} + +project(HAStatus AC) : aceexe { + exename = HAStatus-AC + Source_Files { + HAStatus-AC.cpp + } +} + +project(Reschedule) : aceexe { + exename = Reschedule + Source_Files { + Reschedule.cpp + } +} + +project(Schedule Timers) : aceexe { + exename = Schedule_Timers + Source_Files { + Schedule_Timers.cpp + } +} + +project(Timer Cancel) : aceexe { + exename = Timer_Cancel + Source_Files { + Timer_Cancel.cpp + } +} + +project(*Timers) : aceexe { + exename = Timers + Source_Files { + Timers.cpp + } +} + +project(Timer State Data) : aceexe { + exename = Timer_State_Data + Source_Files { + Timer_State_Data.cpp + } +} diff --git a/ACE/examples/APG/Shared_Memory/.cvsignore b/ACE/examples/APG/Shared_Memory/.cvsignore new file mode 100644 index 00000000000..4fbe7c66db3 --- /dev/null +++ b/ACE/examples/APG/Shared_Memory/.cvsignore @@ -0,0 +1,10 @@ +Hash_Map +Hash_Map +Malloc +Malloc +Mem_Map +Mem_Map +PI_Malloc +PI_Malloc +Pool_Growth +Pool_Growth diff --git a/ACE/examples/APG/Shared_Memory/Hash_Map.cpp b/ACE/examples/APG/Shared_Memory/Hash_Map.cpp new file mode 100644 index 00000000000..b8d73e0045c --- /dev/null +++ b/ACE/examples/APG/Shared_Memory/Hash_Map.cpp @@ -0,0 +1,250 @@ +// $Id$ + +#include "ace/OS_NS_stdio.h" + +// Listing 1 code/ch17 +#include "ace/MMAP_Memory_Pool.h" +#include "ace/Hash_Map_With_Allocator_T.h" +#include "ace/Malloc_T.h" +#include "ace/PI_Malloc.h" +#include "ace/Process_Mutex.h" +#include "ace/Process.h" + +#define BACKING_STORE "map.store" +#define MAP_NAME "records.db" + +#include "Record.h" + +typedef ACE_Allocator_Adapter<ACE_Malloc_T <ACE_MMAP_MEMORY_POOL, + ACE_Process_Mutex, + ACE_Control_Block> + > ALLOCATOR; +typedef ACE_Hash_Map_With_Allocator<int, Record> HASH_MAP; + +ACE_Process_Mutex coordMutex("Coord-Mutex"); +// Listing 1 + +// Listing 2 code/ch17 +HASH_MAP* smap (ALLOCATOR *shmem_allocator) +{ + void *db = 0; + if (shmem_allocator->find (MAP_NAME, db) == 0) + return (HASH_MAP *) db; + size_t hash_table_size = sizeof (HASH_MAP); + void *hash_map = shmem_allocator->malloc (hash_table_size); + if (hash_map == 0) + return 0; + new (hash_map) HASH_MAP (hash_table_size, shmem_allocator); + if (shmem_allocator->bind (MAP_NAME, hash_map) == -1) + { + ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), + ACE_TEXT ("allocate_map"))); + shmem_allocator->remove (); + return 0; + } + return (HASH_MAP*)hash_map; +} +// Listing 2 +// Listing 6 code/ch17 +int processRecords (HASH_MAP *map, ALLOCATOR *shmem_allocator) +{ + ACE_TRACE ("processRecords"); + + size_t mapLength = map->current_size (); + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Found %d records\n\n"), + mapLength)); + + int *todelete = new int[mapLength]; + int i = 0; + + for (HASH_MAP::iterator iter = map->begin (); + iter != map->end (); + iter++) + { + int key = (*iter).ext_id_; + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) [%d] Preprocessing %d:%@\n"), + i+1, key, &(*iter).ext_id_)); + + todelete[i++] = key; // Mark message for deletion. + + // Illustrate the find feature of the map. + Record record; + int result = map->find (key, record, shmem_allocator); + if (result == -1) + ACE_DEBUG ((LM_ERROR, + ACE_TEXT ("Could not find record for %d\n"), + key)); + else + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("Record name: %C|id1:%d|id2:%d\n"), + record.name (), record.id1(), record.id2())); + } + + // Delete everything we processed. + for (int j = 0; j < i ; j++) + { + int result = map->unbind (todelete[j], + shmem_allocator); + if (result == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("Failed on key %d: %p\n"), + ACE_TEXT ("unbind"), + todelete[j]), + -1); + else + ACE_DEBUG ((LM_INFO, + ACE_TEXT ("Fully processed and removed %d\n"), + j)); + } + + delete [] todelete; + + return 0; +} +// Listing 6 +// Listing 4 code/ch17 +int addRecords(HASH_MAP *map, ALLOCATOR *shmem_allocator) +{ + ACE_TRACE ("addRecords"); + + char buf[32]; + int mapLength = static_cast<int> (map->current_size ()); + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("Map has %d entries; adding 20 more\n"), + mapLength)); + + for (int i = mapLength ; i < mapLength + 20; i++) + { + ACE_OS::sprintf (buf, "%s:%d", "Record", i); + + // Allocate new record on stack; + Record newRecord (i, i+1, buf); + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("Adding a record for %d\n"), i)); + + int result = map->bind (i, newRecord, shmem_allocator); + if (result == -1) + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), + ACE_TEXT ("bind failed")), -1); + } + + return 0; +} +// Listing 4 +// Listing 5 code/ch17 +int handle_child (void) +{ + ACE_TRACE ("handle_child"); + + ACE_GUARD_RETURN (ACE_Process_Mutex, ace_mon, coordMutex, -1); + + ALLOCATOR * shmem_allocator = 0; + ACE_MMAP_Memory_Pool_Options options + (ACE_DEFAULT_BASE_ADDR, + ACE_MMAP_Memory_Pool_Options::ALWAYS_FIXED); + + ACE_NEW_RETURN (shmem_allocator, + ALLOCATOR (BACKING_STORE, + BACKING_STORE, + &options), + -1); + + HASH_MAP *map = smap (shmem_allocator); + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Map has %d entries\n"), + map->current_size ())); + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("In child, map is located at %@\n"), + map)); + + processRecords (map, shmem_allocator); + shmem_allocator->sync (); + delete shmem_allocator; + + return 0; +} +// Listing 5 +// Listing 3 code/ch17 +int handle_parent (ACE_TCHAR *cmdLine) +{ + ACE_TRACE ("handle_parent"); + + ALLOCATOR * shmem_allocator = 0; + ACE_MMAP_Memory_Pool_Options options + (ACE_DEFAULT_BASE_ADDR, + ACE_MMAP_Memory_Pool_Options::ALWAYS_FIXED); + + ACE_NEW_RETURN + (shmem_allocator, + ALLOCATOR (BACKING_STORE, BACKING_STORE, &options), + -1); + + HASH_MAP *map = smap (shmem_allocator); + + ACE_Process processa, processb; + ACE_Process_Options poptions; + const ACE_TCHAR *args[3]; + args[0] = cmdLine; + args[1] = ACE_TEXT ("a"); + args[2] = 0; + poptions.command_line (args); + { + ACE_GUARD_RETURN (ACE_Process_Mutex, ace_mon, + coordMutex, -1); + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Map has %d entries\n"), + map->current_size ())); + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("In parent, map is located at %@\n"), + map)); + + // Then have the child show and eat them up. + processa.spawn (poptions); + + // First append a few records. + addRecords (map, shmem_allocator); + } + + + { + ACE_GUARD_RETURN (ACE_Process_Mutex, ace_mon, + coordMutex, -1); + + // Add a few more records.. + addRecords (map, shmem_allocator); + + // Let's see what's left. + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Parent finished adding, ") + ACE_TEXT ("map has %d entries\n"), + map->current_size ())); + + // Have another child try to eat them up. + processb.spawn (poptions); + } + + processa.wait (); + processb.wait (); + + // No processes are left and we don't want to keep the data + // around anymore; it's now safe to remove it. + // !!This will remove the backing store.!! + shmem_allocator->remove (); + delete shmem_allocator; + return 0; +} + +int ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + if (argc == 1) // parent + ACE_ASSERT (handle_parent (argv[0]) == 0); + else + ACE_ASSERT (handle_child () == 0); + + ACE_UNUSED_ARG (argv); + return 0; +} +// Listing 3 diff --git a/ACE/examples/APG/Shared_Memory/Makefile.am b/ACE/examples/APG/Shared_Memory/Makefile.am new file mode 100644 index 00000000000..b114eb0153a --- /dev/null +++ b/ACE/examples/APG/Shared_Memory/Makefile.am @@ -0,0 +1,112 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +ACE_BUILDDIR = $(top_builddir) +ACE_ROOT = $(top_srcdir) + +noinst_PROGRAMS = + +## Makefile.Malloc.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS += Malloc + +Malloc_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +Malloc_SOURCES = \ + Malloc.cpp \ + Record.h + +Malloc_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Makefile.Mem_Map.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS += Mem_Map + +Mem_Map_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +Mem_Map_SOURCES = \ + Mem_Map.cpp \ + Record.h + +Mem_Map_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Makefile.PI_Malloc.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS += PI_Malloc + +PI_Malloc_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +PI_Malloc_SOURCES = \ + PI_Malloc.cpp \ + Record.h + +PI_Malloc_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Makefile.Pool_Growth.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS += Pool_Growth + +Pool_Growth_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +Pool_Growth_SOURCES = \ + Pool_Growth.cpp \ + Record.h + +Pool_Growth_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Makefile.Shared_Memory_Hash_Map.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS += Hash_Map + +Hash_Map_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +Hash_Map_SOURCES = \ + Hash_Map.cpp \ + Record.h + +Hash_Map_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Clean up template repositories, etc. +clean-local: + -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.* + -rm -f gcctemp.c gcctemp so_locations *.ics + -rm -rf cxx_repository ptrepository ti_files + -rm -rf templateregistry ir.out + -rm -rf ptrepository SunWS_cache Templates.DB diff --git a/ACE/examples/APG/Shared_Memory/Malloc.cpp b/ACE/examples/APG/Shared_Memory/Malloc.cpp new file mode 100644 index 00000000000..7f1ef3a3579 --- /dev/null +++ b/ACE/examples/APG/Shared_Memory/Malloc.cpp @@ -0,0 +1,113 @@ +// $Id$ + +#include "ace/OS_NS_stdio.h" +#include "ace/OS_NS_string.h" + +// Listing 1 code/ch17 +#include "ace/MMAP_Memory_Pool.h" +#include "ace/Malloc_T.h" +#include "ace/Null_Mutex.h" + +typedef ACE_Malloc<ACE_MMAP_MEMORY_POOL, ACE_Null_Mutex> + ALLOCATOR; +typedef ACE_Malloc_LIFO_Iterator <ACE_MMAP_MEMORY_POOL, + ACE_Null_Mutex> + MALLOC_LIFO_ITERATOR; + +ALLOCATOR *g_allocator; +// Listing 1 + +// Listing 2 code/ch17 +class Record +{ +public: + Record (int id1, int id2, char *name) + : id1_(id1), id2_(id2), name_(0) + { + size_t len = ACE_OS::strlen (name) + 1; + this->name_ = + reinterpret_cast<char *> (g_allocator->malloc (len)); + ACE_OS::strcpy (this->name_, name); + } + + ~Record () { g_allocator->free (name_); } + char* name(void) { return name_; } + int id1 (void) { return id1_; } + int id2 (void) { return id2_; } + +private: + int id1_; + int id2_; + char *name_; +}; +// Listing 2 +// Listing 5 code/ch17 +void showRecords () +{ + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("The following records were found:\n"))); + { + MALLOC_LIFO_ITERATOR iter (*g_allocator); + + for (void *temp = 0; iter.next (temp) != 0; iter.advance ()) + { + Record *record = + reinterpret_cast<Record *> (temp); + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("Record name: %C|id1:%d|id2:%d\n"), + record->name (), + record->id1 (), + record->id2 ())); + } + } +} +// Listing 5 +// Listing 3 code/ch17 +int addRecords () +{ + char buf[32]; + + for (int i = 0; i < 10; i++) + { + ACE_OS::sprintf (buf, "%s:%d", "Record", i); + void *memory = g_allocator->malloc (sizeof (Record)); + if (memory == 0) + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), + ACE_TEXT ("Unable to malloc")), + -1); + + // Allocate and place record + Record* newRecord = new (memory) Record (i, i+1, buf); + if (g_allocator->bind (buf, newRecord) == -1) + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), + ACE_TEXT ("bind failed")), + -1); + } + + return 0; +} +// Listing 3 +// Listing 4 code/ch17 +// Backing file where the data is kept. +#define BACKING_STORE ACE_TEXT("backing.store") + +int ACE_TMAIN (int argc, ACE_TCHAR *[]) +{ + ACE_NEW_RETURN (g_allocator, + ALLOCATOR (BACKING_STORE), + -1); + if (argc > 1) + { + showRecords (); + } + else + { + addRecords (); + } + + g_allocator->sync (); + delete g_allocator; + return 0; +} +// Listing 4 + diff --git a/ACE/examples/APG/Shared_Memory/Mem_Map.cpp b/ACE/examples/APG/Shared_Memory/Mem_Map.cpp new file mode 100644 index 00000000000..c96cd0b0f45 --- /dev/null +++ b/ACE/examples/APG/Shared_Memory/Mem_Map.cpp @@ -0,0 +1,35 @@ +// $Id$ + +#include "ace/OS_NS_fcntl.h" +#include "ace/OS_NS_string.h" +#include "ace/Mem_Map.h" +#include "ace/Log_Msg.h" + +// Listing 1 code/ch17 +int ACE_TMAIN (int, ACE_TCHAR *argv[]) +{ + ACE_HANDLE srcHandle = ACE_OS::open (argv[1], O_RDONLY); + ACE_ASSERT(srcHandle != ACE_INVALID_HANDLE); + + ACE_Mem_Map srcMap (srcHandle, -1, PROT_READ, ACE_MAP_PRIVATE); + ACE_ASSERT(srcMap.addr () != 0); + + ACE_Mem_Map destMap (argv[2], + srcMap.size (), + O_RDWR | O_CREAT, + ACE_DEFAULT_FILE_PERMS, + PROT_RDWR, + ACE_MAP_SHARED); + ACE_ASSERT(destMap.addr () != 0); + + ACE_OS::memcpy (destMap.addr (), + srcMap.addr (), + srcMap.size ()); + destMap.sync (); + + srcMap.close (); + destMap.close (); + return 0; +} +// Listing 1 + diff --git a/ACE/examples/APG/Shared_Memory/PI_Malloc.cpp b/ACE/examples/APG/Shared_Memory/PI_Malloc.cpp new file mode 100644 index 00000000000..2d31ba96f35 --- /dev/null +++ b/ACE/examples/APG/Shared_Memory/PI_Malloc.cpp @@ -0,0 +1,140 @@ +// $Id$ + +#include "ace/OS_NS_stdio.h" +#include "ace/OS_NS_string.h" + +// Listing 1 code/ch17 +#include "ace/MMAP_Memory_Pool.h" +#include "ace/Malloc_T.h" +#include "ace/Null_Mutex.h" +#include "ace/PI_Malloc.h" + +typedef ACE_Malloc_T <ACE_MMAP_MEMORY_POOL, + ACE_Null_Mutex, + ACE_PI_Control_Block> + ALLOCATOR; +typedef ACE_Malloc_LIFO_Iterator_T<ACE_MMAP_MEMORY_POOL, + ACE_Null_Mutex, + ACE_PI_Control_Block> + MALLOC_LIFO_ITERATOR; + +ALLOCATOR *g_allocator; +// Listing 1 +// Listing 2 code/ch17 +class Record +{ +public: + Record (int id1, int id2, char *name) + : id1_(id1), id2_(id2) + { + size_t len = ACE_OS::strlen (name) + 1; + char *buf = + reinterpret_cast<char *> (g_allocator->malloc (len)); + ACE_OS::strcpy (buf, name); + name_ = buf; + } + + ~Record() { g_allocator->free (name_.addr ()); } + + char *name (void) { return name_; } + int id1 (void) { return id1_; } + int id2 (void) { return id2_; } + +private: + int id1_; + int id2_; + ACE_Based_Pointer_Basic<char> name_; +}; +// Listing 2 + +void showRecords (void) +{ + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("The following records were found:\n"))); + + { + MALLOC_LIFO_ITERATOR iter (*g_allocator); + + for (void *temp = 0; iter.next (temp) != 0; iter.advance ()) + { + Record *record = + reinterpret_cast<Record *> (temp); + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("Record name: %C|id1:%d|id2:%d\n"), + record->name(), record->id1(), record->id2())); + } + } +} + +int addRecords (void) +{ + char buf[32]; + + for (int i = 0; i < 10; i++) + { + ACE_OS::sprintf (buf, "%s:%d", "Record", i); + + void *memory = g_allocator->malloc (sizeof (Record)); + if (memory == NULL) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("Unable to malloc")), + -1); + + // Allocate and place record + Record* newRecord = new (memory) Record (i, i+1, buf); + if (g_allocator->bind (buf, newRecord) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("bind failed")), + -1); + } + + return 0; +} + +// Listing 3 code/ch17 +// Backing file where the data is kept. +#define BACKING_STORE ACE_TEXT("backing2.store") + +int ACE_TMAIN (int argc, ACE_TCHAR *[]) +{ + if (argc > 1) + { + ACE_MMAP_Memory_Pool_Options options + (ACE_DEFAULT_BASE_ADDR, + ACE_MMAP_Memory_Pool_Options::ALWAYS_FIXED); + ACE_NEW_RETURN (g_allocator, + ALLOCATOR (BACKING_STORE, + BACKING_STORE, + &options), + -1); + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("Mapped to base address %@\n"), + g_allocator->base_addr ())); + + showRecords (); + } + else + { + ACE_MMAP_Memory_Pool_Options options + (0, ACE_MMAP_Memory_Pool_Options::NEVER_FIXED); + ACE_NEW_RETURN (g_allocator, + ALLOCATOR (BACKING_STORE, + BACKING_STORE, + &options), + -1); + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("Mapped to base address %@\n"), + g_allocator->base_addr ())); + + addRecords(); + } + + g_allocator->sync (); + delete g_allocator; + return 0; +} +// Listing 3 + diff --git a/ACE/examples/APG/Shared_Memory/Pool_Growth.cpp b/ACE/examples/APG/Shared_Memory/Pool_Growth.cpp new file mode 100644 index 00000000000..c354b098242 --- /dev/null +++ b/ACE/examples/APG/Shared_Memory/Pool_Growth.cpp @@ -0,0 +1,261 @@ +// $Id$ + +#include "ace/OS_NS_stdio.h" +#include "ace/OS_NS_unistd.h" +#include "ace/Malloc_T.h" +#include "ace/PI_Malloc.h" +#include "ace/Process_Mutex.h" +#include "ace/Process.h" +#include "ace/Unbounded_Queue.h" +#include "ace/MMAP_Memory_Pool.h" + +#define BACKING_STORE "queue.dat" +#define QUEUE_NAME "queue.db" + +typedef ACE_Allocator_Adapter<ACE_Malloc <ACE_MMAP_MEMORY_POOL, ACE_Process_Mutex> > ALLOCATOR; + +ACE_Process_Mutex coordMutex("Coord-Mutex"); + +// Listing 1 code/ch17 +template <class T> +class Unbounded_Queue : public ACE_Unbounded_Queue<T> +{ +public: + typedef ACE_Unbounded_Queue<T> BASE; + + Unbounded_Queue(ACE_Allocator* allocator) + : ACE_Unbounded_Queue<T> (allocator) + { } + + int enqueue_tail (const T &new_item, ACE_Allocator* allocator) + { + this->allocator_ = allocator; + return BASE::enqueue_tail (new_item); + } + + int dequeue_head (T &item, ACE_Allocator* allocator) + { + this->allocator_ = allocator; + return BASE::dequeue_head (item); + } + + void delete_nodes (ACE_Allocator* allocator) + { + this->allocator_ = allocator; + delete_nodes (); + } +}; +// Listing 1 + +#include "Record.h" + +typedef Unbounded_Queue<Record> QUEUE; + +QUEUE* squeue(ALLOCATOR* shmem_allocator) +{ + void *queue = 0; + + // This is the easy case since if we find hash table in the + // memory-mapped file we know it's already initialized. + if (shmem_allocator->find (QUEUE_NAME, queue) == 0) + return (QUEUE *) queue; + + // Create a new map (because we've just created a new + // memory-mapped file). + size_t queue_size = sizeof (QUEUE); + + queue = shmem_allocator->malloc (queue_size); + + // If allocation failed ... + if (queue == 0) + return 0; + + new (queue) QUEUE (shmem_allocator); + + if (shmem_allocator->bind (QUEUE_NAME, queue) == -1) + { + // Attempt to clean up. + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("squeue bind\n"))); + shmem_allocator->remove(); + + return 0; + } + + return (QUEUE*)queue; +} + +static ALLOCATOR * g_shmem_allocator = 0; + +// Listing 4 code/ch17 +int processRecord (ALLOCATOR *shmem_allocator) +{ + ACE_GUARD_RETURN (ACE_Process_Mutex, ace_mon, coordMutex, -1); + + QUEUE* queue = squeue (shmem_allocator); + if (queue == 0) + { + delete shmem_allocator; + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), + ACE_TEXT ("Could not obtain queue")), + -1); + } + + if (queue->is_empty ()) // Check for anything to process. + return 0; + + Record record; + if (queue->dequeue_head (record, shmem_allocator) == -1) + { + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), + ACE_TEXT ("dequeue_head\n")), + -1); + } + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Processing record|name: %C") + ACE_TEXT ("|Record id1:%d|Record id2:%d\n"), + record.name (), record.id1 (), record.id2 ())); + if (record.id1 () == -1) + queue->enqueue_tail (record, shmem_allocator); + return record.id1 (); +} +// Listing 4 +// Listing 5 code/ch17 +#if defined(WIN32) + +int handle_remap (EXCEPTION_POINTERS *ep) +{ + ACE_DEBUG ((LM_INFO, ACE_TEXT ("Handle a remap\n"))); + + DWORD ecode = ep->ExceptionRecord->ExceptionCode; + if (ecode != EXCEPTION_ACCESS_VIOLATION) + return EXCEPTION_CONTINUE_SEARCH; + + void *addr = + (void *) ep->ExceptionRecord->ExceptionInformation[1]; + if (g_shmem_allocator->alloc().memory_pool().remap (addr) == -1) + return EXCEPTION_CONTINUE_SEARCH; +#if __X86__ + // This is 80x86-specific. + ep->ContextRecord->Edi = (DWORD) addr; +#elif __MIPS__ + ep->ContextRecord->IntA0 = + ep->ContextRecord->IntV0 = (DWORD) addr; + ep->ContextRecord->IntT5 = + ep->ContextRecord->IntA0 + 3; +#endif /* __X86__ */ + + return EXCEPTION_CONTINUE_EXECUTION; +} + +int processWin32Record (ALLOCATOR *shmem_allocator) +{ + ACE_SEH_TRY + { + return processRecord (shmem_allocator); + } + + ACE_SEH_EXCEPT (handle_remap (GetExceptionInformation ())) + { } + + return 0; +} +#endif /*WIN32*/ +// Listing 5 + +int sendRecord (int recordId, ALLOCATOR *shmem_allocator) +{ + ACE_GUARD_RETURN (ACE_Process_Mutex, ace_mon, coordMutex, -1); + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Sending record %d\n"), + recordId)); + + QUEUE * queue = squeue (shmem_allocator); + char buf[128]; + ACE_OS::sprintf (buf, "%s:%d", "Record", recordId); + Record newRecord (recordId, recordId+1, buf); + + int result = queue->enqueue_tail (newRecord, shmem_allocator); + if (result == -1) + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), + ACE_TEXT ("enqueue failed\n")), + -1); + return 0; +} + +// Listing 2 code/ch17 +int handle_parent (ACE_TCHAR *cmdLine) +{ + ALLOCATOR *shmem_allocator = 0; + ACE_MMAP_Memory_Pool_Options options + (ACE_DEFAULT_BASE_ADDR, + ACE_MMAP_Memory_Pool_Options::ALWAYS_FIXED); + + // Create the allocator. + ACE_NEW_RETURN (shmem_allocator, + ALLOCATOR (BACKING_STORE, + BACKING_STORE, + &options), + -1); + + ACE_Process processa, processb; + ACE_Process_Options poptions; + const ACE_TCHAR *args[3]; + args[0] = cmdLine; + args[1] = ACE_TEXT ("a"); + args[2] = 0; + poptions.command_line (args); + processa.spawn (poptions); + processb.spawn (poptions); + + // Make sure the child does map a partial pool in memory. + ACE_OS::sleep (2); + + for (int i = 0; i < 100; i++) + sendRecord (i, shmem_allocator); + sendRecord (-1, shmem_allocator); + + processa.wait (); + processb.wait (); + shmem_allocator->remove (); + return 0; +} +// Listing 2 + +// Listing 3 code/ch17 +int handle_child (void) +{ + ALLOCATOR *shmem_allocator = 0; + ACE_MMAP_Memory_Pool_Options options + (ACE_DEFAULT_BASE_ADDR, + ACE_MMAP_Memory_Pool_Options::ALWAYS_FIXED); + ACE_NEW_RETURN (shmem_allocator, + ALLOCATOR (BACKING_STORE, + BACKING_STORE, + &options), + -1); + g_shmem_allocator = shmem_allocator; + +#if defined (WIN32) + while (processWin32Record (shmem_allocator) != -1) + ; +#else + while (processRecord (shmem_allocator) != -1) + ; +#endif + return 0; +} +// Listing 3 + +int ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + if (argc == 1) + handle_parent(argv[0]); + else + handle_child(); + + return 0; +} + diff --git a/ACE/examples/APG/Shared_Memory/Record.h b/ACE/examples/APG/Shared_Memory/Record.h new file mode 100644 index 00000000000..f3a63e1298b --- /dev/null +++ b/ACE/examples/APG/Shared_Memory/Record.h @@ -0,0 +1,45 @@ +/** + * $Id$ + * + * Sample code from The ACE Programmer's Guide, + * copyright 2003 Addison-Wesley. All Rights Reserved. + */ + +#ifndef __RECORD_H_ +#define __RECORD_H_ + +#include "ace/OS_NS_string.h" +#include "ace/Based_Pointer_T.h" + +// Listing 11 code/ch17 +class Record +{ +public: + Record () { } + ~Record () { } + + Record (const Record& rec) + : id1_(rec.id1_), id2_(rec.id2_) + { + ACE_OS::strcpy (recName_, rec.name_); + this->name_ = recName_; + } + Record (int id1, int id2, char *name) + : id1_(id1), id2_(id2) + { + ACE_OS::strcpy (recName_, name); + this->name_ = recName_; + } + char *name (void) { return recName_; } + int id1 (void) { return id1_; } + int id2 (void) { return id2_; } + +private: + int id1_; + int id2_; + char recName_[128]; + ACE_Based_Pointer_Basic<char> name_; +}; +// Listing 11 + +#endif /* __RECORD_H_ */ diff --git a/ACE/examples/APG/Shared_Memory/shared_memory.mpc b/ACE/examples/APG/Shared_Memory/shared_memory.mpc new file mode 100644 index 00000000000..2cf2400ef8e --- /dev/null +++ b/ACE/examples/APG/Shared_Memory/shared_memory.mpc @@ -0,0 +1,42 @@ +// -*- MPC -*- +// $Id$ + +project(*Hash Map) : aceexe { + avoids += ace_for_tao + exename = Hash_Map + Source_Files { + Hash_Map.cpp + } +} + +project(Malloc) : aceexe { + avoids += ace_for_tao + exename = Malloc + Source_Files { + Malloc.cpp + } +} + +project(Mem Map) : aceexe { + avoids += ace_for_tao + exename = Mem_Map + Source_Files { + Mem_Map.cpp + } +} + +project(PI Malloc) : aceexe { + avoids += ace_for_tao + exename = PI_Malloc + Source_Files { + PI_Malloc.cpp + } +} + +project(Pool Growth) : aceexe { + avoids += ace_for_tao + exename = Pool_Growth + Source_Files { + Pool_Growth.cpp + } +} diff --git a/ACE/examples/APG/Signals/.cvsignore b/ACE/examples/APG/Signals/.cvsignore new file mode 100644 index 00000000000..23774a5d6a0 --- /dev/null +++ b/ACE/examples/APG/Signals/.cvsignore @@ -0,0 +1,10 @@ +SigAction +SigAction +SigGuard +SigGuard +SigHandler +SigHandler +SigHandlers +SigHandlers +SigInfo +SigInfo diff --git a/ACE/examples/APG/Signals/Makefile.am b/ACE/examples/APG/Signals/Makefile.am new file mode 100644 index 00000000000..ffc67bdd0f0 --- /dev/null +++ b/ACE/examples/APG/Signals/Makefile.am @@ -0,0 +1,85 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +ACE_BUILDDIR = $(top_builddir) +ACE_ROOT = $(top_srcdir) + +## Makefile.SigAction.am +noinst_PROGRAMS = SigAction + +SigAction_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +SigAction_SOURCES = \ + SigAction.cpp + +SigAction_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.SigGuard.am +noinst_PROGRAMS += SigGuard + +SigGuard_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +SigGuard_SOURCES = \ + SigGuard.cpp + +SigGuard_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.SigHandler.am +noinst_PROGRAMS += SigHandler + +SigHandler_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +SigHandler_SOURCES = \ + SigHandler.cpp + +SigHandler_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.SigHandlers.am +noinst_PROGRAMS += SigHandlers + +SigHandlers_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +SigHandlers_SOURCES = \ + SigHandlers.cpp + +SigHandlers_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.SigInfo.am +noinst_PROGRAMS += SigInfo + +SigInfo_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +SigInfo_SOURCES = \ + SigInfo.cpp + +SigInfo_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Clean up template repositories, etc. +clean-local: + -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.* + -rm -f gcctemp.c gcctemp so_locations *.ics + -rm -rf cxx_repository ptrepository ti_files + -rm -rf templateregistry ir.out + -rm -rf ptrepository SunWS_cache Templates.DB diff --git a/ACE/examples/APG/Signals/SigAction.cpp b/ACE/examples/APG/Signals/SigAction.cpp new file mode 100644 index 00000000000..6d818ae9400 --- /dev/null +++ b/ACE/examples/APG/Signals/SigAction.cpp @@ -0,0 +1,75 @@ +// $Id$ + +#include "ace/OS_NS_unistd.h" +#include "ace/OS_NS_stdlib.h" +#include "ace/Log_Msg.h" +// Listing 1 code/ch11 +#include "ace/Signal.h" + +// Forward declaration. +static void register_actions (); + +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_TRACE (ACE_TEXT ("::main")); + + ::register_actions (); // Register actions to happen. + + // This will be raised immediately. + ACE_OS::kill (ACE_OS::getpid(), SIGUSR2); + + // This will pend until the first signal is completely + // handled and returns, because we masked it out + // in the registerAction call. + ACE_OS::kill (ACE_OS::getpid (), SIGUSR1); + + while (ACE_OS::sleep (100) == -1) + { + if (errno == EINTR) + continue; + else + ACE_OS::exit (1); + } + return 0; +} +// Listing 1 +#if defined (ACE_HAS_SIG_C_FUNC) +extern "C" { +#endif +// Listing 3 code/ch11 +static void my_sighandler (int signo) +{ + ACE_TRACE (ACE_TEXT ("::my_sighandler")); + + ACE_OS::kill (ACE_OS::getpid (), SIGUSR1); + + if (signo == SIGUSR1) + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Signal SIGUSR1\n"))); + else + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Signal SIGUSR2\n"))); + + ACE_OS::sleep (10); +} +#if defined (ACE_HAS_SIG_C_FUNC) +} +#endif +// Listing 3 +// Listing 2 code/ch11 +static void register_actions () +{ + ACE_TRACE (ACE_TEXT ("::register_actions")); + + ACE_Sig_Action sa (reinterpret_cast <ACE_SignalHandler> (my_sighandler)); + + // Make sure we specify that SIGUSR1 will be masked out + // during the signal handler's execution. + ACE_Sig_Set ss; + ss.sig_add (SIGUSR1); + sa.mask (ss); + + // Register the same handler function for these + // two signals. + sa.register_action (SIGUSR1); + sa.register_action (SIGUSR2); +} +// Listing 2 diff --git a/ACE/examples/APG/Signals/SigGuard.cpp b/ACE/examples/APG/Signals/SigGuard.cpp new file mode 100644 index 00000000000..679af032904 --- /dev/null +++ b/ACE/examples/APG/Signals/SigGuard.cpp @@ -0,0 +1,43 @@ +// $Id$ + +#include "ace/OS_NS_unistd.h" +#include "ace/Log_Msg.h" +#include "ace/Signal.h" +#include "ace/Sig_Handler.h" + +// Listing 1 +class MySignalHandler : public ACE_Event_Handler + { + public: + virtual int handle_signal(int signo, + siginfo_t * = 0, ucontext_t * = 0) + { + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Signal %d\n"), signo)); + return 0; + } + }; + +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + + MySignalHandler sighandler; + ACE_Sig_Handler sh; + sh.register_handler (SIGUSR1, &sighandler); + + ACE_Sig_Set ss; + ss.sig_add (SIGUSR1); + + ACE_Sig_Guard guard (&ss); + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("Entering critical region\n"))); + ACE_OS::sleep (10); + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("Leaving critical region\n"))); + } + + // Do other stuff. + + return 0; +} +// Listing 1 diff --git a/ACE/examples/APG/Signals/SigHandler.cpp b/ACE/examples/APG/Signals/SigHandler.cpp new file mode 100644 index 00000000000..b7068c9dea6 --- /dev/null +++ b/ACE/examples/APG/Signals/SigHandler.cpp @@ -0,0 +1,60 @@ +// $Id$ + +#include "ace/OS_NS_unistd.h" +#include "ace/Log_Msg.h" +#include "ace/Signal.h" +#include "ace/Sig_Handler.h" + +// Listing 1 code/ch11 +class MySignalHandler : public ACE_Event_Handler +{ +public: + MySignalHandler (int signum) : signum_(signum) + { } + + virtual ~MySignalHandler() + { } + + virtual int handle_signal (int signum, + siginfo_t * = 0, + ucontext_t * = 0) + { + ACE_TRACE (ACE_TEXT ("MySignalHandler::handle_signal")); + + // Make sure the right handler was called back. + ACE_ASSERT (signum == this->signum_); + + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("%S occured\n"), signum)); + return 0; + } + +private: + int signum_; +}; +// Listing 1 +// Listing 2 code/ch11 +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + MySignalHandler h1 (SIGUSR1), h2 (SIGUSR2); + ACE_Sig_Handler handler; + handler.register_handler (SIGUSR1, &h1); + handler.register_handler (SIGUSR2, &h2); + + ACE_OS::kill (ACE_OS::getpid (), SIGUSR1); + ACE_OS::kill (ACE_OS::getpid (), SIGUSR2); + + int time = 10; + while ((time = ACE_OS::sleep (time)) == -1) + { + if (errno == EINTR) + continue; + else + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("sleep")), -1); + } + } + return 0; +} +// Listing 2 diff --git a/ACE/examples/APG/Signals/SigHandlers.cpp b/ACE/examples/APG/Signals/SigHandlers.cpp new file mode 100644 index 00000000000..19634b50d72 --- /dev/null +++ b/ACE/examples/APG/Signals/SigHandlers.cpp @@ -0,0 +1,54 @@ +// $Id$ + +#include "ace/OS_NS_unistd.h" +#include "ace/Log_Msg.h" +#include "ace/Signal.h" +#include "ace/Sig_Handler.h" + +class MySignalHandler : public ACE_Event_Handler +{ +public: + MySignalHandler (int signum) : signum_(signum) + { } + + virtual ~MySignalHandler () + { } + + virtual int handle_signal (int signum, siginfo_t * = 0, ucontext_t * = 0) + { + ACE_TRACE (ACE_TEXT ("MySignalHandler::handle_signal")); + + // Make sure the right handler was called back.. + ACE_ASSERT(signum == this->signum_); + + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("%d occured\n"), signum)); + + return 0; + } + +private: + int signum_; +}; + +// Listing 1 code/ch11 +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + MySignalHandler h1 (SIGUSR1), h2 (SIGUSR1); + ACE_Sig_Handlers handler; + handler.register_handler (SIGUSR1, &h1); + handler.register_handler (SIGUSR1, &h2); + + ACE_OS::kill (ACE_OS::getpid (), SIGUSR1); + + int time = 10; + while ((time = ACE_OS::sleep (time)) == -1) + { + if (errno == EINTR) + continue; + else + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), + ACE_TEXT ("sleep")), -1); + } + return 0; +} +// Listing 1 diff --git a/ACE/examples/APG/Signals/SigInfo.cpp b/ACE/examples/APG/Signals/SigInfo.cpp new file mode 100644 index 00000000000..0a3186e6099 --- /dev/null +++ b/ACE/examples/APG/Signals/SigInfo.cpp @@ -0,0 +1,167 @@ +// $Id$ + +#include "ace/Log_Msg.h" +#include "ace/Reactor.h" +#include "ace/Event_Handler.h" +#include "ace/Signal.h" +#include "ace/OS_NS_unistd.h" +#include "ace/OS_NS_string.h" + +#if !defined (ACE_LACKS_UNIX_SIGNALS) + +// Listing 1 code/ch11 +class MySignalHandler : public ACE_Event_Handler +{ +public: + MySignalHandler () : ACE_Event_Handler() + { } + + // Listing A code/ch11 + int handle_signal (int signum, + siginfo_t * siginfo = 0, + ucontext_t * = 0) + { + ACE_DEBUG ((LM_INFO, ACE_TEXT ("Received signal [%S]\n"), + signum)); + if (siginfo == 0) + { + ACE_DEBUG ((LM_INFO, + ACE_TEXT ("No siginfo_t available for ") + ACE_TEXT ("signal [%S]\n"), + signum)); + return 0; + } + // Listing A +#if defined (__linux__) + // Listing B code/ch11 + ACE_DEBUG ((LM_INFO, + ACE_TEXT ("errno for this signal is %d [%s]\n"), + siginfo->si_errno, + ACE_OS::strerror (siginfo->si_errno))); + ACE_DEBUG ((LM_INFO, + ACE_TEXT ("signal was sent by process %d") + ACE_TEXT (" / user %d\n"), + siginfo->si_pid, + siginfo->si_uid)); + + switch (siginfo->si_code) + { + case SI_TIMER: + ACE_DEBUG ((LM_INFO, ACE_TEXT ("Timer expiration\n"))); + break; + + case SI_USER: + ACE_DEBUG ((LM_INFO, + ACE_TEXT ("Sent by kill, sigsend or raise\n"))); + break; + + case SI_KERNEL: + ACE_DEBUG ((LM_INFO, + ACE_TEXT ("Sent by kernel\n"))); + break; + // ... + }; + + // Listing B + + // Listing C code/ch11 + switch (signum) + { + case SIGFPE: + switch (siginfo->si_code) + { + case FPE_INTDIV: + case FPE_FLTDIV: + ACE_DEBUG ((LM_INFO, + ACE_TEXT ("Divide by zero at %@\n"), + siginfo->si_addr)); + break; + + case FPE_INTOVF: + case FPE_FLTOVF: + ACE_DEBUG ((LM_INFO, + ACE_TEXT ("Numeric overflow at %@\n"), + siginfo->si_addr)); + break; + + // ... + } + break; + + // Listing C + // Listing D code/ch11 + case SIGSEGV: + switch (siginfo->si_code) + { + // ... + }; + break; + // Listing D + + // Listing E code/ch11 + case SIGCHLD: + ACE_DEBUG ((LM_INFO, + ACE_TEXT ("A child process has exited\n"))); + ACE_DEBUG ((LM_INFO, + ACE_TEXT ("The child consumed %l/%l time\n"), + siginfo->si_utime, + siginfo->si_stime)); + ACE_DEBUG ((LM_INFO, + ACE_TEXT ("and exited with value %d\n"), + siginfo->si_status)); + break; + // ... + } + // Listing E +#endif /* __linux__ */ + return 0; + } +}; +// Listing 1 + +#endif /* ACE_LACKS_UNIX_SIGNALS */ + +#if !defined (ACE_LACKS_UNIX_SIGNALS) + +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ +#if defined (ACE_LACKS_FORK) + ACE_DEBUG ((LM_DEBUG, + "This example requires fork()\n")); +#else + // Create a child process so that we can test our + // ability to handle SIGCHLD + + // Listing 2 code/ch11 + ACE_Sig_Set signalSet; + signalSet.fill_set (); + + MySignalHandler h1; + ACE_Reactor::instance ()->register_handler (signalSet, &h1); + pid_t childPid = ACE_OS::fork (); + if (childPid == 0) // This is the parent process. + { + // Exclude B + ACE_OS::sleep (10); + return 100; + // Exclude B + } + ACE_Reactor::instance ()->run_reactor_event_loop (); + // Listing 2 + +#endif /* ACE_LACKS_FORK */ + + return 0; +} + +#else + +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_DEBUG ((LM_DEBUG, + "This example does not work on this platform.\n")); + return 1; +} + +#endif /* !ACE_LACKS_UNIX_SIGNALS */ diff --git a/ACE/examples/APG/Signals/signals.mpc b/ACE/examples/APG/Signals/signals.mpc new file mode 100644 index 00000000000..51947c7a06b --- /dev/null +++ b/ACE/examples/APG/Signals/signals.mpc @@ -0,0 +1,37 @@ +// -*- MPC -*- +// $Id$ + +project(SigAction) : aceexe { + exename = SigAction + Source_Files { + SigAction.cpp + } +} + +project(SigGuard) : aceexe { + exename = SigGuard + Source_Files { + SigGuard.cpp + } +} + +project(SigHandler) : aceexe { + exename = SigHandler + Source_Files { + SigHandler.cpp + } +} + +project(SigHandlers) : aceexe { + exename = SigHandlers + Source_Files { + SigHandlers.cpp + } +} + +project(SigInfo) : aceexe { + exename = SigInfo + Source_Files { + SigInfo.cpp + } +} diff --git a/ACE/examples/APG/Sockets/.cvsignore b/ACE/examples/APG/Sockets/.cvsignore new file mode 100644 index 00000000000..0b2c9d92db4 --- /dev/null +++ b/ACE/examples/APG/Sockets/.cvsignore @@ -0,0 +1,8 @@ +Basic +Basic +Basic_Robust +Basic_Robust +Iovec +Iovec +Server +Server diff --git a/ACE/examples/APG/Sockets/Basic.cpp b/ACE/examples/APG/Sockets/Basic.cpp new file mode 100644 index 00000000000..6a20e435b3c --- /dev/null +++ b/ACE/examples/APG/Sockets/Basic.cpp @@ -0,0 +1,35 @@ +// $Id$ + +#include "ace/INET_Addr.h" +#include "ace/SOCK_Stream.h" +#include "ace/SOCK_Connector.h" +#include "ace/Log_Msg.h" + +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + // Listing 1 code/ch06 + ACE_INET_Addr srvr (50000, ACE_LOCALHOST); + // Listing 1 + + // Listing 2 code/ch06 + ACE_SOCK_Connector connector; + ACE_SOCK_Stream peer; + + if (-1 == connector.connect (peer, srvr)) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("connect")), 1); + // Listing 2 + + ssize_t bc; + char buf[64]; + + // Listing 3 code/ch06 + peer.send_n ("uptime\n", 7); + bc = peer.recv (buf, sizeof(buf)); + write (1, buf, bc); + peer.close (); + // Listing 3 + + return (0); +} diff --git a/ACE/examples/APG/Sockets/Basic_Robust.cpp b/ACE/examples/APG/Sockets/Basic_Robust.cpp new file mode 100644 index 00000000000..361519a4486 --- /dev/null +++ b/ACE/examples/APG/Sockets/Basic_Robust.cpp @@ -0,0 +1,137 @@ +// $Id$ + +#include "ace/OS_NS_errno.h" +#include "ace/INET_Addr.h" +#include "ace/SOCK_Stream.h" +#include "ace/SOCK_Connector.h" +#include "ace/Log_Msg.h" +#include "ace/Time_Value.h" + +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + /* + * Here we will use the default ctor and the set() + * method to configure it. After each set() we will + * display the address as a string and then connect + * to each respective server. We can reuse the addr + * instance once connection has been established. + * + // Listing 1 code/ch06 + ACE_INET_Addr addr; + ... + addr.set ("HAStatus", ACE_LOCALHOST); + ... + addr.set ("HALog", ACE_LOCALHOST); + // Listing 1 + * + */ + + ACE_INET_Addr addr; + ACE_TCHAR peerAddress[64]; + + // Listing 2 code/ch06 + addr.set (ACE_TEXT("HAStatus"), ACE_LOCALHOST); + if (addr.addr_to_string (peerAddress, + sizeof(peerAddress), 0) == 0) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Connecting to %s\n"), + peerAddress)); + } + // Listing 2 + + // Listing 3 code/ch06 + ACE_SOCK_Stream status; + ACE_OS::last_error(0); + ACE_SOCK_Connector statusConnector (status, addr); + if (ACE_OS::last_error()) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("status")), 100); + // Listing 3 + + addr.set (ACE_TEXT("HALog"), ACE_LOCALHOST); + if (addr.addr_to_string (peerAddress, + sizeof(peerAddress), 0) == 0) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Connecting to %s\n"), + peerAddress )); + } + + // Listing 4 code/ch06 + ACE_SOCK_Connector logConnector; + ACE_Time_Value timeout (10); + ACE_SOCK_Stream log; + if (logConnector.connect (log, addr, &timeout) == -1) + { + if (ACE_OS::last_error() == ETIME) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Timeout while ") + ACE_TEXT ("connecting to log server\n"))); + } + else + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("log"))); + } + return (101); + } + // Listing 4 + + /* + * We generally let the OS pick our local port number but + * if you want, you can choose that also: + // Listing 5 code/ch06 + ACE_SOCK_Connector logConnector; + ACE_INET_Addr local (4200, ACE_LOCALHOST); + if (logConnector.connect (log, addr, 0, local) == -1) + { + ... + // Listing 5 + } + */ + + char buf[64]; + + // Listing 6 code/ch06 + ACE_Time_Value sendTimeout (0, 5); + if (status.send_n ("uptime\n", 7, &sendTimeout) == -1) + { + if (ACE_OS::last_error() == ETIME) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Timeout while sending ") + ACE_TEXT ("query to status server\n"))); + } + // Listing 6 + else + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("send_n"))); + } + return (102); + } + + // Listing 7 code/ch06 + ssize_t bc ; + ACE_Time_Value recvTimeout (0, 1); + if ((bc = status.recv (buf, sizeof(buf), &recvTimeout)) == -1) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("recv"))); + return (103); + } + + log.send_n (buf, bc); + // Listing 7 + + status.close (); + log.close (); + + return (0); +} diff --git a/ACE/examples/APG/Sockets/Iovec.cpp b/ACE/examples/APG/Sockets/Iovec.cpp new file mode 100644 index 00000000000..fb27b6d562e --- /dev/null +++ b/ACE/examples/APG/Sockets/Iovec.cpp @@ -0,0 +1,84 @@ +// $Id$ + +#include "ace/INET_Addr.h" +#include "ace/SOCK_Stream.h" +#include "ace/SOCK_Connector.h" +#include "ace/Log_Msg.h" + +const char *UPTIME = "uptime"; +const char *HUMIDITY = "humidity"; +const char *TEMPERATURE = "temperature"; + +void addCommand (iovec [], const char *) +{} + +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_INET_Addr srvr (50000, ACE_LOCALHOST); + ACE_SOCK_Connector connector; + ACE_SOCK_Stream peer; + + ACE_ASSERT (connector.connect (peer, srvr) != -1); + + ssize_t bc; + + // Listing 1 code/ch06 + iovec send[4]; + send[0].iov_base = const_cast<char *> ("up"); + send[0].iov_len = 2; + send[1].iov_base = const_cast<char *> ("time"); + send[1].iov_len = 4; + send[2].iov_base = const_cast<char *> ("\n"); + send[2].iov_len = 1; + + peer.sendv (send, 3); + // Listing 1 + + // + // A more clever approach would use something like this: + // Where the addCommand() method allocates and populates + // the query array from a set of global commands. + // + // Listing 2 code/ch06 + iovec query[3]; + addCommand (query, UPTIME); + addCommand (query, HUMIDITY); + addCommand (query, TEMPERATURE); + peer.sendv (query, 3); + // Listing 2 + + // Listing 3 code/ch06 + iovec receive[2]; + receive[0].iov_base = new char [32]; + receive[0].iov_len = 32; + receive[1].iov_base = new char [64]; + receive[1].iov_len = 64; + + bc = peer.recvv (receive, 2); + // Listing 3 + + // Listing 4 code/ch06 + for (int i = 0; i < 2 && bc > 0; ++i) + { + size_t wc = receive[i].iov_len; + if (static_cast<size_t> (bc) < wc) + wc = static_cast<size_t> (bc); + write (1, receive[i].iov_base, wc); + bc -= receive[i].iov_len; + delete [] + (reinterpret_cast<char *> (receive[i].iov_base)); + } + // Listing 4 + + // Listing 5 code/ch06 + peer.send_n ("uptime\n", 7); + iovec response; + peer.recvv (&response); + write (1, response.iov_base, response.iov_len); + delete [] reinterpret_cast<char *> (response.iov_base); + // Listing 5 + + peer.close (); + + return (0); +} diff --git a/ACE/examples/APG/Sockets/Makefile.am b/ACE/examples/APG/Sockets/Makefile.am new file mode 100644 index 00000000000..3409703f567 --- /dev/null +++ b/ACE/examples/APG/Sockets/Makefile.am @@ -0,0 +1,72 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +ACE_BUILDDIR = $(top_builddir) +ACE_ROOT = $(top_srcdir) + +## Makefile.Sockets_Basic.am +noinst_PROGRAMS = Basic + +Basic_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +Basic_SOURCES = \ + Basic.cpp + +Basic_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Sockets_Basic_Robust.am +noinst_PROGRAMS += Basic_Robust + +Basic_Robust_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +Basic_Robust_SOURCES = \ + Basic_Robust.cpp + +Basic_Robust_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Sockets_Iovec.am +noinst_PROGRAMS += Iovec + +Iovec_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +Iovec_SOURCES = \ + Iovec.cpp + +Iovec_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Sockets_Server.am +noinst_PROGRAMS += Server + +Server_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +Server_SOURCES = \ + Server.cpp + +Server_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Clean up template repositories, etc. +clean-local: + -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.* + -rm -f gcctemp.c gcctemp so_locations *.ics + -rm -rf cxx_repository ptrepository ti_files + -rm -rf templateregistry ir.out + -rm -rf ptrepository SunWS_cache Templates.DB diff --git a/ACE/examples/APG/Sockets/Server.cpp b/ACE/examples/APG/Sockets/Server.cpp new file mode 100644 index 00000000000..2a9ca7f4f7b --- /dev/null +++ b/ACE/examples/APG/Sockets/Server.cpp @@ -0,0 +1,95 @@ +// $Id$ + +#include "ace/os_include/os_netdb.h" +#include "ace/OS_NS_errno.h" +#include "ace/INET_Addr.h" +#include "ace/SOCK_Stream.h" +#include "ace/SOCK_Acceptor.h" +#include "ace/Log_Msg.h" +#include "ace/Time_Value.h" + +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + // Listing 1 code/ch06 + ACE_INET_Addr port_to_listen ("HAStatus"); + ACE_SOCK_Acceptor acceptor; + + if (acceptor.open (port_to_listen, 1) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("acceptor.open")), + 100); + // Listing 1 + + /* + * The complete open signature: + * + // Listing 2 code/ch06 + int open (const ACE_Addr &local_sap, + int reuse_addr = 0, + int protocol_family = PF_INET, + int backlog = ACE_DEFAULT_BACKLOG, + int protocol = 0); + // Listing 2 + * + */ + + while (1) + { + ACE_SOCK_Stream peer; + ACE_INET_Addr peer_addr; + ACE_Time_Value timeout (10, 0); + + /* + * Basic acceptor usage + */ +#if 0 + // Listing 3 code/ch06 + if (acceptor.accept (peer) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("(%P|%t) Failed to accept ") + ACE_TEXT ("client connection\n")), + 100); + // Listing 3 +#endif /* 0 */ + + // Listing 4 code/ch06 + if (acceptor.accept (peer, &peer_addr, &timeout, 0) == -1) + { + if (ACE_OS::last_error() == EINTR) + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Interrupted while ") + ACE_TEXT ("waiting for connection\n"))); + else + if (ACE_OS::last_error() == ETIMEDOUT) + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Timeout while ") + ACE_TEXT ("waiting for connection\n"))); + } + // Listing 4 + // Listing 5 code/ch06 + else + { + ACE_TCHAR peer_name[MAXHOSTNAMELEN]; + peer_addr.addr_to_string (peer_name, MAXHOSTNAMELEN); + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Connection from %s\n"), + peer_name)); + // Listing 5 + // Listing 7 code/ch06 + char buffer[4096]; + ssize_t bytes_received; + + while ((bytes_received = + peer.recv (buffer, sizeof(buffer))) != -1) + { + peer.send_n (buffer, bytes_received); + } + + peer.close (); + // Listing 7 + } + } + + ACE_NOTREACHED (return 0); +} diff --git a/ACE/examples/APG/Sockets/sockets.mpc b/ACE/examples/APG/Sockets/sockets.mpc new file mode 100644 index 00000000000..86064233ac3 --- /dev/null +++ b/ACE/examples/APG/Sockets/sockets.mpc @@ -0,0 +1,30 @@ +// -*- MPC -*- +// $Id$ + +project(*Basic) : aceexe { + exename = Basic + Source_Files { + Basic.cpp + } +} + +project(*Basic Robust) : aceexe { + exename = Basic_Robust + Source_Files { + Basic_Robust.cpp + } +} + +project(*Iovec) : aceexe { + exename = Iovec + Source_Files { + Iovec.cpp + } +} + +project(*Server) : aceexe { + exename = Server + Source_Files { + Server.cpp + } +} diff --git a/ACE/examples/APG/Streams/.cvsignore b/ACE/examples/APG/Streams/.cvsignore new file mode 100644 index 00000000000..ff318c0de98 --- /dev/null +++ b/ACE/examples/APG/Streams/.cvsignore @@ -0,0 +1,2 @@ +Answerer +Answerer diff --git a/ACE/examples/APG/Streams/Answerer.cpp b/ACE/examples/APG/Streams/Answerer.cpp new file mode 100644 index 00000000000..507b6172108 --- /dev/null +++ b/ACE/examples/APG/Streams/Answerer.cpp @@ -0,0 +1,403 @@ +/** + * $Id$ + * + * Streams Listing 01 + * + * An answering machine based on a one-way ACE_Stream + */ + +#include "ace/OS_NS_string.h" +#include "ace/Stream.h" +#include "ace/Message_Block.h" +#include "ace/FILE_IO.h" + +#include "MessageInfo.h" +#include "Message.h" +#include "BasicTask.h" +#include "EndTask.h" +#include "Util.h" +#include "RecordingDevice.h" + +// Listing 21 code/ch18 +class AnswerIncomingCall : public BasicTask +{ +protected: + virtual int process (Message *message) + { + ACE_TRACE (ACE_TEXT ("AnswerIncomingCall::process()")); + + if (message->recorder ()->answer_call () < 0) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("AnswerIncomingCall")), + -1); + return 0; + } +}; +// Listing 21 + +// Listing 22 code/ch18 +class GetCallerId : public BasicTask +{ +protected: + virtual int process (Message *message) + { + ACE_TRACE (ACE_TEXT ("GetCallerId::process()")); + + CallerId *id; + id = message->recorder ()->retrieve_callerId (); + if (!id) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("GetCallerId")), + -1); + + message->caller_id (id); + return 0; + } +}; +// Listing 22 + +// Listing 23 code/ch18 +class PlayOutgoingMessage : public BasicTask +{ +protected: + virtual int process (Message *message) + { + ACE_TRACE (ACE_TEXT ("PlayOutgoingMessage::process()")); + + ACE_FILE_Addr outgoing_message = + this->get_outgoing_message (message); + + int pmrv = + message->recorder ()->play_message (outgoing_message); + if (pmrv < 0) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("PlayOutgoingMessage")), + -1); + return 0; + } + + ACE_FILE_Addr get_outgoing_message (Message *) + { + // Exclude 23 + return ACE_FILE_Addr (ACE_TEXT ("/tmp/outgoing_message")); + // Exclude 23 + } +}; +// Listing 23 + +// Listing 24 code/ch18 +class RecordIncomingMessage : public BasicTask +{ +protected: + virtual int process (Message *message) + { + ACE_TRACE (ACE_TEXT ("RecordIncomingMessage::process()")); + + ACE_FILE_Addr incoming_message = + this->get_incoming_message_queue (); + + MessageType *type = + message->recorder ()->record_message (incoming_message); + if (!type) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("RecordIncomingMessage")), + -1); + message->incoming_message (incoming_message, type); + return 0; + } + + ACE_FILE_Addr get_incoming_message_queue (void) + { + // Exclude 24 + return ACE_FILE_Addr (ACE_TEXT ("/tmp/incoming_message")); + // Exclude 24 + } +}; +// Listing 24 + +// Listing 25 code/ch18 +class ReleaseDevice : public BasicTask +{ +protected: + virtual int process (Message *message) + { + ACE_TRACE (ACE_TEXT ("ReleaseDevice::process()")); + message->recorder ()->release (); + return 0; + } +}; +// Listing 25 + +// Listing 26 code/ch18 +class EncodeMessage : public BasicTask +{ +protected: + virtual int process (Message *message) + { + ACE_TRACE (ACE_TEXT ("ReleaseDevice::process()")); + + ACE_FILE_Addr &incoming = message->addr (); + ACE_FILE_Addr addr = this->get_message_destination (message); + + if (message->is_text ()) + Util::convert_to_unicode (incoming, addr); + else if (message->is_audio ()) + Util::convert_to_mp3 (incoming, addr); + else if (message->is_video ()) + Util::convert_to_mpeg (incoming, addr); + + message->addr (addr); + return 0; + } + + ACE_FILE_Addr get_message_destination (Message *) + { + // Exclude 26 + return ACE_FILE_Addr (ACE_TEXT ("/tmp/encoded_message")); + // Exclude 26 + } +}; +// Listing 26 + +// Listing 27 code/ch18 +class SaveMetaData : public BasicTask +{ +protected: + virtual int process (Message *message) + { + ACE_TRACE (ACE_TEXT ("SaveMetaData::process()")); + + ACE_TString path (message->addr ().get_path_name ()); + path += ACE_TEXT (".xml"); + + ACE_FILE_Connector connector; + ACE_FILE_IO file; + ACE_FILE_Addr addr (path.c_str ()); + if (connector.connect (file, addr) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("create meta-data file")), + 0); + + file.truncate (0); + this->write (file, "<Message>\n"); + // ... + this->write (file, "</Message>\n"); + file.close (); + return 0; + } + +private: + int write (ACE_FILE_IO &file, const char *str) + { + return file.send (str, ACE_OS::strlen (str)); + } +}; +// Listing 27 + +// Listing 28 code/ch18 +class NotifySomeone : public BasicTask +{ +protected: + virtual int process (Message *message) + { + ACE_TRACE (ACE_TEXT ("NotifySomeone::process()")); + + // Format an email to tell someone about the + // newly received message. + // ... + + // Display message information in the logfile + ACE_DEBUG ((LM_INFO, + ACE_TEXT ("New message from %s ") + ACE_TEXT ("received and stored at %s\n"), + message->caller_id ()->string (), + message->addr ().get_path_name ())); + return 0; + } +}; +// Listing 28 + +// Listing 10 code/ch18 +class RecordingStream : public ACE_Stream<ACE_MT_SYNCH> +{ +public: + typedef ACE_Stream<ACE_MT_SYNCH> inherited; + typedef ACE_Module<ACE_MT_SYNCH> Module; + + RecordingStream () : inherited() + { } +// Listing 10 + + // Listing 1000 code/ch18 + virtual int open (void *arg, + Module *head = 0, Module *tail = 0) + { + if (tail == 0) + ACE_NEW_RETURN (tail, + Module (ACE_TEXT ("End Module"), new EndTask ()), + -1); + this->inherited::open (arg, head, tail); + // Listing 1000 + + // Listing 1001 code/ch18 + Module *answerIncomingCallModule; + ACE_NEW_RETURN (answerIncomingCallModule, + Module (ACE_TEXT ("Answer Incoming Call"), + new AnswerIncomingCall ()), + -1); + + // Listing 11 code/ch18 + Module *getCallerIdModule; + ACE_NEW_RETURN (getCallerIdModule, + Module (ACE_TEXT ("Get Caller ID"), new GetCallerId ()), + -1); + // Listing 11 + + Module *playOGMModule; + ACE_NEW_RETURN (playOGMModule, + Module (ACE_TEXT ("Play Outgoing Message"), + new PlayOutgoingMessage ()), + -1); + + Module *recordModule; + ACE_NEW_RETURN (recordModule, + Module (ACE_TEXT ("Record Incoming Message"), + new RecordIncomingMessage ()), + -1); + + Module *releaseModule; + ACE_NEW_RETURN (releaseModule, + Module (ACE_TEXT ("Release Device"), + new ReleaseDevice ()), + -1); + + Module *conversionModule; + ACE_NEW_RETURN (conversionModule, + Module (ACE_TEXT ("Encode Message"), + new EncodeMessage ()), + -1); + + Module *saveMetaDataModule; + ACE_NEW_RETURN (saveMetaDataModule, + Module (ACE_TEXT ("Save Meta-Data"), + new SaveMetaData ()), + -1); + + Module *notificationModule; + ACE_NEW_RETURN (notificationModule, + Module (ACE_TEXT ("Notify Someone"), + new NotifySomeone ()), + -1); + // Listing 1001 + + // Listing 12 code/ch18 + if (this->push (notificationModule) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("Failed to push %p\n"), + ACE_TEXT ("notificationModule")), + -1); + if (this->push (saveMetaDataModule) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("Failed to push %p\n"), + ACE_TEXT ("saveMetaDataModule")), + -1); + if (this->push (conversionModule) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("Failed to push %p\n"), + ACE_TEXT ("conversionModule")), + -1); + if (this->push (releaseModule) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("Failed to push %p\n"), + ACE_TEXT ("releaseModule")), + -1); + if (this->push (recordModule) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("Failed to push %p\n"), + ACE_TEXT ("recordModule")), + -1); + if (this->push (playOGMModule) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("Failed to push %p\n"), + ACE_TEXT ("playOGMModule")), + -1); + if (this->push (getCallerIdModule) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("Failed to push %p\n"), + ACE_TEXT ("getCallerIdModule")), + -1); + if (this->push (answerIncomingCallModule) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("Failed to push %p\n") + ACE_TEXT ("answerIncomingCallModule")), + -1); + // Listing 12 + + return 0; + } + + // Listing 13 code/ch18 + int record (RecordingDevice *recorder) + { + ACE_Message_Block * mb; + ACE_NEW_RETURN (mb, ACE_Message_Block (sizeof(Message)), -1); + + Message *message = (Message *)mb->wr_ptr (); + mb->wr_ptr (sizeof(Message)); + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("RecordingStream::record() - ") + ACE_TEXT ("message->recorder(recorder)\n"))); + message->recorder (recorder); + + int rval = this->put (mb); + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("RecordingStream::record() - ") + ACE_TEXT ("this->put() returns %d\n"), + rval)); + return rval; + } + // Listing 13 +}; + + +// Listing 1 code/ch18 +int ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + RecordingDevice *recorder = + RecordingDeviceFactory::instantiate (argc, argv); + // Listing 1 + + // Listing 2 code/ch18 + RecordingStream *recording_stream; + ACE_NEW_RETURN (recording_stream, RecordingStream, -1); + + if (recording_stream->open (0) < 0) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("RecordingStream->open()")), + 0); + // Listing 2 + + // Listing 3 code/ch18 + for (;;) + { + ACE_DEBUG ((LM_INFO, + ACE_TEXT ("Waiting for incoming message\n"))); + RecordingDevice *activeRecorder = + recorder->wait_for_activity (); + + ACE_DEBUG ((LM_INFO, + ACE_TEXT ("Initiating recording process\n"))); + + recording_stream->record (activeRecorder); + } + // Listing 3 + + return 0; +} diff --git a/ACE/examples/APG/Streams/BasicTask.h b/ACE/examples/APG/Streams/BasicTask.h new file mode 100644 index 00000000000..edebc397998 --- /dev/null +++ b/ACE/examples/APG/Streams/BasicTask.h @@ -0,0 +1,143 @@ +/* -*- C++ -*- */ +// $Id$ + +#ifndef BASIC_TASK_H +#define BASIC_TASK_H + +#include "ace/Task_T.h" +#include "ace/ace_wchar.h" + +// Listing 100 code/ch18 +class BasicTask : public ACE_Task<ACE_MT_SYNCH> +{ +public: + typedef ACE_Task<ACE_MT_SYNCH> inherited; + + BasicTask () : inherited() + { } + + virtual int open (void * = 0) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("BasicTask::open() starting ") + ACE_TEXT ("%d threads\n"), + this->desired_threads ())); + + return this->activate (THR_NEW_LWP | THR_JOINABLE, + this->desired_threads ()); + } + // Listing 100 + + // Listing 101 code/ch18 + int put (ACE_Message_Block *message, + ACE_Time_Value *timeout) + { + return this->putq (message, timeout); + } + // Listing 101 + + // Listing 1020 code/ch18 + virtual int svc (void) + { + for (ACE_Message_Block *message = 0; ; ) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("BasicTask::svc() - ") + ACE_TEXT ("waiting for work\n" ))); + + if (this->getq (message) == -1) + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), + ACE_TEXT ("getq")), + -1); + // Listing 1020 + + // Listing 1021 code/ch18 + if (message->msg_type () == ACE_Message_Block::MB_HANGUP) + { + if (this->putq (message) == -1) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("Task::svc() putq"))); + message->release (); + } + break; + } + // Listing 1021 + + // Listing 1022 code/ch18 + Message *recordedMessage = + (Message *)message->rd_ptr (); + + if (this->process (recordedMessage) == -1) + { + message->release (); + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("process")), + -1); + } + // Listing 1022 + + // Listing 1023 code/ch18 + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("BasicTask::svc() - ") + ACE_TEXT ("Continue to next stage\n" ))); + if (this->next_step (message) < 0) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("put_next failed"))); + message->release (); + break; + } + // Listing 1023 + } + + return 0; + } + + // Listing 103 code/ch18 + virtual int close (u_long flags) + { + int rval = 0; + + if (flags == 1) + { + ACE_Message_Block *hangup = new ACE_Message_Block (); + hangup->msg_type (ACE_Message_Block::MB_HANGUP); + if (this->putq (hangup) == -1) + { + hangup->release (); + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("Task::close() putq")), + -1); + } + + rval = this->wait (); + } + + return rval; + } + // Listing 103 + + // Listing 105 code/ch18 +protected: + virtual int next_step (ACE_Message_Block *message_block) + { + return this->put_next (message_block); + } + // Listing 105 + + // Listing 104 code/ch18 + virtual int process (Message *message) = 0; + + virtual int desired_threads (void) + { + return 1; + } +}; +// Listing 104 + +#endif /* BASIC_TASK_H */ diff --git a/ACE/examples/APG/Streams/Command.h b/ACE/examples/APG/Streams/Command.h new file mode 100644 index 00000000000..eae0f5ecb5f --- /dev/null +++ b/ACE/examples/APG/Streams/Command.h @@ -0,0 +1,40 @@ +/* -*- C++ -*- */ +// $Id$ + +#ifndef COMMAND_H +#define COMMAND_H + +#include "ace/SString.h" +#include "ace/Message_Block.h" + +// Listing 01 code/ch18 +class Command : public ACE_Data_Block +{ +public: + // Result Values + enum { + RESULT_PASS = 1, + RESULT_SUCCESS = 0, + RESULT_FAILURE = -1 + }; + + // Commands + enum { + CMD_UNKNOWN = -1, + CMD_ANSWER_CALL = 10, + CMD_RETRIEVE_CALLER_ID, + CMD_PLAY_MESSAGE, + CMD_RECORD_MESSAGE + } commands; + + int flags_; + int command_; + + void *extra_data_; + + int numeric_result_; + ACE_TString result_; +}; +// Listing 01 + +#endif /* COMMAND_H */ diff --git a/ACE/examples/APG/Streams/CommandModule.cpp b/ACE/examples/APG/Streams/CommandModule.cpp new file mode 100644 index 00000000000..9ee5a92918a --- /dev/null +++ b/ACE/examples/APG/Streams/CommandModule.cpp @@ -0,0 +1,20 @@ +// $Id$ + +#include "CommandModule.h" + +// Listing 01 code/ch18 +CommandModule::CommandModule (const ACE_TCHAR *module_name, + CommandTask *writer, + CommandTask *reader, + ACE_SOCK_Stream *peer) + : inherited(module_name, writer, reader, peer) +{ } +// Listing 01 + +// Listing 02 code/ch18 +ACE_SOCK_Stream &CommandModule::peer (void) +{ + ACE_SOCK_Stream *peer = (ACE_SOCK_Stream *)this->arg (); + return *peer; +} +// Listing 02 diff --git a/ACE/examples/APG/Streams/CommandModule.h b/ACE/examples/APG/Streams/CommandModule.h new file mode 100644 index 00000000000..7fe65b81f78 --- /dev/null +++ b/ACE/examples/APG/Streams/CommandModule.h @@ -0,0 +1,27 @@ +/* -*- C++ -*- */ +// $Id$ + +#ifndef COMMAND_MODULE_H +#define COMMAND_MODULE_H + +#include "ace/Module.h" +#include "ace/SOCK_Stream.h" +#include "CommandTask.h" + +// Listing 01 code/ch18 +class CommandModule : public ACE_Module<ACE_MT_SYNCH> +{ +public: + typedef ACE_Module<ACE_MT_SYNCH> inherited; + typedef ACE_Task<ACE_MT_SYNCH> Task; + + CommandModule (const ACE_TCHAR *module_name, + CommandTask *writer, + CommandTask *reader, + ACE_SOCK_Stream *peer); + + ACE_SOCK_Stream &peer (void); +}; +// Listing 01 + +#endif /* COMMAND_MODULE_H */ diff --git a/ACE/examples/APG/Streams/CommandStream.cpp b/ACE/examples/APG/Streams/CommandStream.cpp new file mode 100644 index 00000000000..def3f123d77 --- /dev/null +++ b/ACE/examples/APG/Streams/CommandStream.cpp @@ -0,0 +1,97 @@ +// $Id$ + +#include "ace/Log_Msg.h" +#include "ace/OS_Memory.h" +#include "CommandStream.h" +#include "Command.h" +#include "CommandModule.h" +#include "CommandTasks.h" + +// Gotcha: superclass' open() won't open head/tail modules +// Gotcha!! Must open the stream before pushing modules! + +// Listing 01 code/ch18 +int CommandStream::open (void *arg, + ACE_Module<ACE_MT_SYNCH> *head, + ACE_Module<ACE_MT_SYNCH> *tail) +{ + ACE_TRACE (ACE_TEXT ("CommandStream::open(peer)")); + + if (this->inherited::open (arg, head, tail) == -1) + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), + ACE_TEXT ("Failed to open superclass")), + -1); + // Listing 01 + + // Listing 02 code/ch18 + CommandModule *answerCallModule; + ACE_NEW_RETURN (answerCallModule, + AnswerCallModule (this->peer_), + -1); + + CommandModule *retrieveCallerIdModule; + ACE_NEW_RETURN (retrieveCallerIdModule, + RetrieveCallerIdModule (this->peer_), + -1); + + CommandModule *playMessageModule; + ACE_NEW_RETURN (playMessageModule, + PlayMessageModule (this->peer_), + -1); + + CommandModule *recordMessageModule; + ACE_NEW_RETURN (recordMessageModule, + RecordMessageModule (this->peer_), + -1); + // Listing 02 + + // Listing 03 code/ch18 + if (this->push (answerCallModule) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("Failed to push %p\n"), + answerCallModule->name()), + -1); + + if (this->push (retrieveCallerIdModule) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("Failed to push %p\n"), + retrieveCallerIdModule->name()), + -1); + + if (this->push (playMessageModule) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("Failed to push %p\n"), + playMessageModule->name()), + -1); + + if (this->push (recordMessageModule) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("Failed to push %p\n"), + recordMessageModule->name()), + -1); + // Listing 03 + return 0; +} + +// Listing 04 code/ch18 +Command *CommandStream::execute (Command *command) +{ + ACE_Message_Block *mb; + ACE_NEW_RETURN (mb, ACE_Message_Block (command), 0); + if (this->put (mb) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("Fail on put command %d: %p\n"), + command->command_, + ACE_TEXT ("")), + 0); + + this->get (mb); + command = (Command *)mb->data_block (); + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("Command (%d) returns (%d)\n"), + command->command_, + command->numeric_result_)); + + return command; +} +// Listing 04 diff --git a/ACE/examples/APG/Streams/CommandStream.h b/ACE/examples/APG/Streams/CommandStream.h new file mode 100644 index 00000000000..97e9e673f7c --- /dev/null +++ b/ACE/examples/APG/Streams/CommandStream.h @@ -0,0 +1,44 @@ +/* -*- C++ -*- */ +// $Id$ + +#ifndef COMMAND_STREAM_H +#define COMMAND_STREAM_H + +#include "ace/Module.h" +#include "ace/Stream.h" +#include "ace/SOCK_Stream.h" +#include "ace/Synch_Traits.h" + +#include "Command.h" + +// A CommandStream is a bidirectional ACE_Stream implementing a chain +// of commands. A message will move down the stream until a +// CommandModule is capable of processing it. After processing, it +// will move on down the stream to the end. Data received from the +// tail will likewise move up the stream until the downstream's +// partner module is encoutered. The retrieved data will be processed +// and continue on up the stream. + +// Listing 01 code/ch18 +class CommandStream : public ACE_Stream<ACE_MT_SYNCH> +{ +public: + typedef ACE_Stream<ACE_MT_SYNCH> inherited; + + CommandStream (ACE_SOCK_Stream *peer) + : inherited (), peer_(peer) { } + + virtual int open (void *arg, + ACE_Module<ACE_MT_SYNCH> *head = 0, + ACE_Module<ACE_MT_SYNCH> *tail = 0); + + Command *execute (Command *command); + +private: + CommandStream () { } + + ACE_SOCK_Stream *peer_; +}; +// Listing 01 + +#endif /* COMMAND_STREAM_H */ diff --git a/ACE/examples/APG/Streams/CommandTask.cpp b/ACE/examples/APG/Streams/CommandTask.cpp new file mode 100644 index 00000000000..7ad63166ffd --- /dev/null +++ b/ACE/examples/APG/Streams/CommandTask.cpp @@ -0,0 +1,153 @@ +// $Id$ + +#include "CommandTask.h" + +// Listing 01 code/ch18 +CommandTask::CommandTask (int command) + : inherited (), command_(command) +{ } +// Listing 01 + +// Listing 02 code/ch18 +int CommandTask::open (void *) +{ + return this->activate (); +} +// Listing 02 + +// Listing 03 code/ch18 +int CommandTask::put (ACE_Message_Block *message, + ACE_Time_Value *timeout) +{ + return this->putq (message, timeout); +} +// Listing 03 + +// Listing 04 code/ch18 +int CommandTask::process (Command *) +{ + ACE_TRACE (ACE_TEXT ("CommandTask::process()")); + return Command::RESULT_FAILURE; +} +// Listing 04 + +// Listing 05 code/ch18 +int CommandTask::close (u_long flags) +{ + int rval = 0; + if (flags == 1) + { + ACE_Message_Block *hangup = new ACE_Message_Block; + hangup->msg_type (ACE_Message_Block::MB_HANGUP); + if (this->putq (hangup->duplicate ()) == -1) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("Task::close() putq")), + -1); + } + + hangup->release (); + rval = this->wait (); + } + + return rval; +} +// Listing 05 + +// Listing 06 code/ch18 +// Listing 061 code/ch18 +int CommandTask::svc (void) +{ + ACE_Message_Block *message; + + for (;;) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("CommandTask::svc() - ") + ACE_TEXT ("%s waiting for work\n"), + this->module ()->name ())); + + if (this->getq (message) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("getq")), + -1); + + if (message->msg_type () == ACE_Message_Block::MB_HANGUP) + { + if (this->putq (message->duplicate ()) == -1) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("Task::svc() putq")), + -1); + } + + message->release (); + break; + } + // Listing 061 + + // Listing 062 code/ch18 + Command *command = (Command *)message->data_block (); + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("CommandTask::svc() - ") + ACE_TEXT ("%s got work request %d\n"), + this->module ()->name (), + command->command_)); + + if (command->command_ != this->command_) + { + this->put_next (message->duplicate ()); + } + // Listing 062 + // Listing 063 code/ch18 + else + { + int result = this->process (command); + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("CommandTask::svc() - ") + ACE_TEXT ("%s work request %d result is %d\n"), + this->module ()->name (), + command->command_, + result)); + + if (result == Command::RESULT_FAILURE) + { + command->numeric_result_ = -1; + } + // Listing 063 + // Listing 064 code/ch18 + else if (result == Command::RESULT_PASS) + { + this->put_next (message->duplicate ()); + } + // Listing 064 + // Listing 065 code/ch18 + else // result == Command::RESULT_SUCCESS + { + if (this->is_writer ()) + { + this->sibling ()->putq + (message->duplicate ()); + } + // Listing 065 + // Listing 066 code/ch18 + else // this->is_reader () + { + this->put_next (message->duplicate ()); + } + // Listing 066 + } // result == ... + } // command->command_ ? = this->command_ + + // Listing 067 code/ch18 + message->release (); + } // for (;;) + + return 0; +} +// Listing 067 +// Listing 06 diff --git a/ACE/examples/APG/Streams/CommandTask.h b/ACE/examples/APG/Streams/CommandTask.h new file mode 100644 index 00000000000..ae78017b0f9 --- /dev/null +++ b/ACE/examples/APG/Streams/CommandTask.h @@ -0,0 +1,39 @@ +/* -*- C++ -*- */ +// $Id$ + +#ifndef COMMAND_TASK_H +#define COMMAND_TASK_H + +#include "ace/Task.h" +#include "ace/Module.h" + +#include "Command.h" + +// Listing 01 code/ch18 +class CommandTask : public ACE_Task<ACE_MT_SYNCH> +{ +public: + typedef ACE_Task<ACE_MT_SYNCH> inherited; + + virtual ~CommandTask () { } + + virtual int open (void * = 0 ); + + int put (ACE_Message_Block *message, + ACE_Time_Value *timeout); + + virtual int svc (void); + + virtual int close (u_long flags); + +protected: + CommandTask (int command); + + virtual int process (Command *message); + + int command_; +}; +// Listing 01 + + +#endif /* COMMAND_TASK_H */ diff --git a/ACE/examples/APG/Streams/CommandTasks.cpp b/ACE/examples/APG/Streams/CommandTasks.cpp new file mode 100644 index 00000000000..78a5e2de451 --- /dev/null +++ b/ACE/examples/APG/Streams/CommandTasks.cpp @@ -0,0 +1,221 @@ +// $Id$ + +#include "ace/FILE_Addr.h" +#include "ace/FILE_Connector.h" +#include "ace/FILE_IO.h" + +#include "Command.h" +#include "CommandTasks.h" +#include "RecordingDevice_Text.h" + +// Listing 011 code/ch18 +AnswerCallModule::AnswerCallModule (ACE_SOCK_Stream *peer) + : CommandModule (ACE_TEXT ("AnswerCall Module"), + new AnswerCallDownstreamTask (), + new AnswerCallUpstreamTask (), + peer) +{ } +// Listing 011 +// Listing 012 code/ch18 +AnswerCallDownstreamTask::AnswerCallDownstreamTask (void) + : CommandTask(Command::CMD_ANSWER_CALL) +{ } +// Listing 012 +// Listing 013 code/ch18 +int AnswerCallDownstreamTask::process (Command *command) +{ + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Answer Call (downstream)\n"))); + + TextListenerAcceptor *acceptor = + (TextListenerAcceptor *)command->extra_data_; + + CommandModule *module = + (CommandModule*)this->module (); + + command->numeric_result_ = + acceptor->accept (module->peer ()); + + acceptor->release (); + return Command::RESULT_SUCCESS; +} +// Listing 013 +// Listing 014 code/ch18 +AnswerCallUpstreamTask::AnswerCallUpstreamTask (void) + : CommandTask(Command::CMD_ANSWER_CALL) +{ } +// Listing 014 +// Listing 015 code/ch18 +int AnswerCallUpstreamTask::process (Command *) +{ + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Answer Call (upstream)\n"))); + + return Command::RESULT_SUCCESS; +} +// Listing 015 + +// Listing 021 code/ch18 +RetrieveCallerIdModule::RetrieveCallerIdModule + (ACE_SOCK_Stream *peer) + : CommandModule (ACE_TEXT ("RetrieveCallerId Module"), + new RetrieveCallerIdDownstreamTask (), + new RetrieveCallerIdUpstreamTask (), + peer) +{ } +// Listing 021 +// Listing 022 code/ch18 +RetrieveCallerIdDownstreamTask::RetrieveCallerIdDownstreamTask + (void) + : CommandTask(Command::CMD_RETRIEVE_CALLER_ID) +{ } + +int RetrieveCallerIdDownstreamTask::process (Command *) +{ + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("Retrieving Caller ID data\n"))); + + return Command::RESULT_SUCCESS; +} +// Listing 022 +// Listing 023 code/ch18 +RetrieveCallerIdUpstreamTask::RetrieveCallerIdUpstreamTask + (void) + : CommandTask(Command::CMD_RETRIEVE_CALLER_ID) +{ } + +int RetrieveCallerIdUpstreamTask::process (Command *command) +{ + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("Returning Caller ID data\n"))); + + ACE_INET_Addr remote_addr; + + CommandModule *module = + (CommandModule*)this->module (); + + module->peer ().get_remote_addr (remote_addr); + ACE_TCHAR remote_addr_str[256]; + remote_addr.addr_to_string (remote_addr_str, 256); + command->result_ = ACE_TString (remote_addr_str); + + return Command::RESULT_SUCCESS; +} +// Listing 023 + +PlayMessageModule::PlayMessageModule (ACE_SOCK_Stream *peer) + : CommandModule (ACE_TEXT ("PlayMessage Module"), + new PlayMessageDownstreamTask (), + new PlayMessageUpstreamTask (), + peer) +{ } + +PlayMessageDownstreamTask::PlayMessageDownstreamTask (void) + : CommandTask(Command::CMD_PLAY_MESSAGE) +{ } +// Listing 032 code/ch18 +int PlayMessageDownstreamTask::process (Command *command) +{ + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("Play Outgoing Message\n"))); + + ACE_FILE_Connector connector; + ACE_FILE_IO file; + + ACE_FILE_Addr *addr = + (ACE_FILE_Addr *)command->extra_data_; + + if (connector.connect (file, *addr) == -1) + { + command->numeric_result_ = -1; + } + else + { + command->numeric_result_ = 0; + + CommandModule *module = + (CommandModule*)this->module (); + + char rwbuf[512]; + ssize_t rwbytes; + while ((rwbytes = file.recv (rwbuf, 512)) > 0) + { + module->peer ().send_n (rwbuf, rwbytes); + } + } + + return Command::RESULT_SUCCESS; +} +// Listing 032 +PlayMessageUpstreamTask::PlayMessageUpstreamTask (void) + : CommandTask(Command::CMD_PLAY_MESSAGE) +{ } + +int PlayMessageUpstreamTask::process (Command *command) +{ + ACE_FILE_Addr * addr = + (ACE_FILE_Addr *)command->extra_data_; + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("Outgoing message (%s) sent\n"), + addr->get_path_name ())); + + return Command::RESULT_SUCCESS; +} + +RecordMessageModule::RecordMessageModule (ACE_SOCK_Stream *peer) + : CommandModule (ACE_TEXT ("RecordMessage Module"), + new RecordMessageDownstreamTask (), + new RecordMessageUpstreamTask (), + peer) +{ } + +RecordMessageDownstreamTask::RecordMessageDownstreamTask (void) + : CommandTask(Command::CMD_RECORD_MESSAGE) +{ } + +int RecordMessageDownstreamTask::process (Command *) +{ + return Command::RESULT_SUCCESS; +} + +RecordMessageUpstreamTask::RecordMessageUpstreamTask (void) + : CommandTask(Command::CMD_RECORD_MESSAGE) +{ } +// Listing 033 code/ch18 +int RecordMessageUpstreamTask::process (Command *command) +{ + // Collect whatever the peer sends and write into the + // specified file. + ACE_FILE_Connector connector; + ACE_FILE_IO file; + + ACE_FILE_Addr *addr = + (ACE_FILE_Addr *)command->extra_data_; + + if (connector.connect (file, *addr) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("create file")), + Command::RESULT_FAILURE); + file.truncate (0); + + CommandModule *module = + (CommandModule*)this->module (); + + ssize_t total_bytes = 0; + char rwbuf[512]; + ssize_t rwbytes; + while ((rwbytes = module->peer ().recv (rwbuf, 512)) > 0) + { + total_bytes += file.send_n (rwbuf, rwbytes); + } + + file.close (); + + ACE_DEBUG ((LM_INFO, + ACE_TEXT ("RecordMessageUpstreamTask ") + ACE_TEXT ("- recorded %d byte message\n"), + total_bytes)); + + return Command::RESULT_SUCCESS; +} +// Listing 033 diff --git a/ACE/examples/APG/Streams/CommandTasks.h b/ACE/examples/APG/Streams/CommandTasks.h new file mode 100644 index 00000000000..0d55d4da07b --- /dev/null +++ b/ACE/examples/APG/Streams/CommandTasks.h @@ -0,0 +1,108 @@ +/* -*- C++ -*- */ +// $Id$ + +#ifndef COMMAND_TASKS_H +#define COMMAND_TASKS_H + +#include "ace/SOCK_Stream.h" + +#include "Command.h" +#include "CommandTask.h" +#include "CommandModule.h" + +// CommandModule and CommandTask objects that implement the command +// stream functions. + +// Listing 011 code/ch18 +class AnswerCallModule : public CommandModule +{ +public: + AnswerCallModule (ACE_SOCK_Stream * peer); +}; +// Listing 011 +// Listing 012 code/ch18 +class AnswerCallDownstreamTask : public CommandTask +{ +public: + AnswerCallDownstreamTask (); +protected: + virtual int process (Command *command); +}; +// Listing 012 +// Listing 013 code/ch18 +class AnswerCallUpstreamTask : public CommandTask +{ +public: + AnswerCallUpstreamTask (); +protected: + virtual int process (Command *command); +}; +// Listing 013 + +// Listing 02 code/ch18 +class RetrieveCallerIdModule : public CommandModule +{ +public: + RetrieveCallerIdModule (ACE_SOCK_Stream *peer); +}; +class RetrieveCallerIdDownstreamTask : public CommandTask +{ +public: + RetrieveCallerIdDownstreamTask (); +protected: + virtual int process (Command *command); +}; +class RetrieveCallerIdUpstreamTask : public CommandTask +{ +public: + RetrieveCallerIdUpstreamTask (); +protected: + virtual int process (Command *command); +}; +// Listing 02 + +// Listing 03 code/ch18 +class PlayMessageModule : public CommandModule +{ +public: + PlayMessageModule (ACE_SOCK_Stream *peer); +}; +class PlayMessageDownstreamTask : public CommandTask +{ +public: + PlayMessageDownstreamTask (); +protected: + virtual int process (Command *command); +}; +class PlayMessageUpstreamTask : public CommandTask +{ +public: + PlayMessageUpstreamTask (); +protected: + virtual int process (Command *command); +}; +// Listing 03 + +// Listing 04 code/ch18 +class RecordMessageModule : public CommandModule +{ +public: + RecordMessageModule (ACE_SOCK_Stream *peer); +}; +class RecordMessageDownstreamTask : public CommandTask +{ +public: + RecordMessageDownstreamTask (); +protected: + virtual int process (Command *command); +}; +class RecordMessageUpstreamTask : public CommandTask +{ +public: + RecordMessageUpstreamTask (); +protected: + virtual int process (Command *command); +}; +// Listing 04 + +#endif /* COMMAND_TASKS_H */ diff --git a/ACE/examples/APG/Streams/EndTask.h b/ACE/examples/APG/Streams/EndTask.h new file mode 100644 index 00000000000..a42eca655d9 --- /dev/null +++ b/ACE/examples/APG/Streams/EndTask.h @@ -0,0 +1,27 @@ +/* -*- C++ -*- */ +// $Id$ + +#ifndef END_TASK_H +#define END_TASK_H + +// Listing 1 code/ch18 +class EndTask : public BasicTask { +protected: + virtual int process (Message *) + { + ACE_TRACE (ACE_TEXT ("EndTask::process()")); + return 0; + } + + virtual int next_step (ACE_Message_Block *mb) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("EndTask::next_step() - ") + ACE_TEXT ("end of the line.\n"))); + mb->release (); + return 0; + } +}; +// Listing 1 + +#endif /* END_TASK_H */ diff --git a/ACE/examples/APG/Streams/Makefile.am b/ACE/examples/APG/Streams/Makefile.am new file mode 100644 index 00000000000..e23f2f22143 --- /dev/null +++ b/ACE/examples/APG/Streams/Makefile.am @@ -0,0 +1,52 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +ACE_BUILDDIR = $(top_builddir) +ACE_ROOT = $(top_srcdir) + + +## Makefile.Answerer.am + +if BUILD_THREADS +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS = Answerer + +Answerer_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +Answerer_SOURCES = \ + Answerer.cpp \ + CommandModule.cpp \ + CommandStream.cpp \ + CommandTask.cpp \ + CommandTasks.cpp \ + RecordingDeviceFactory.cpp \ + RecordingDevice_Text.cpp \ + CommandModule.h \ + CommandStream.h \ + CommandTask.h \ + CommandTasks.h \ + RecordingDeviceFactory.h \ + RecordingDevice_Text.h + +Answerer_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO +endif BUILD_THREADS + +## Clean up template repositories, etc. +clean-local: + -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.* + -rm -f gcctemp.c gcctemp so_locations *.ics + -rm -rf cxx_repository ptrepository ti_files + -rm -rf templateregistry ir.out + -rm -rf ptrepository SunWS_cache Templates.DB diff --git a/ACE/examples/APG/Streams/Message.h b/ACE/examples/APG/Streams/Message.h new file mode 100644 index 00000000000..29ddd30d5a1 --- /dev/null +++ b/ACE/examples/APG/Streams/Message.h @@ -0,0 +1,92 @@ +/* -*- C++ -*- */ +// $Id$ + +#ifndef MESSAGE_H +#define MESSAGE_H + +class RecordingDevice; + +class Message +{ +public: + Message () : device_(0), type_(0), id_(0) + { } + + ~Message () + { } + + RecordingDevice *recorder (void) + { + return this->device_; + } + + void recorder (RecordingDevice *device) + { + this->device_ = device; + } + + void type (MessageType *type) + { + this->type_ = type; + } + + MessageType *type (void) + { + return this->type_; + } + + void caller_id (CallerId *id) + { + this->id_ = id; + } + + CallerId *caller_id (void) + { + return this->id_; + } + + void addr (ACE_FILE_Addr &addr) + { + this->addr_ = addr; + } + + void incoming_message (ACE_FILE_Addr &addr, MessageType *type) + { + this->addr_ = addr; + this->type_ = type; + } + + ACE_FILE_Addr &addr (void) + { + return this->addr_; + } + + int is_text (void) + { + return this->type_->is_text (); + } + + int is_audio (void) + { + return this->type_->is_audio (); + } + + int is_video (void) + { + return this->type_->is_video (); + } + +private: + RecordingDevice *device_; + MessageType *type_; + CallerId *id_; + ACE_FILE_Addr addr_; +}; + +class AudioMessage : public Message +{ }; + +class VideoMessage : public Message +{ }; + +#endif /* MESSAGE_H */ diff --git a/ACE/examples/APG/Streams/MessageInfo.h b/ACE/examples/APG/Streams/MessageInfo.h new file mode 100644 index 00000000000..0f0f1bc60dc --- /dev/null +++ b/ACE/examples/APG/Streams/MessageInfo.h @@ -0,0 +1,100 @@ +/* -*- C++ -*- */ +// $Id$ + +#ifndef MESSAGE_INFO_H +#define MESSAGE_INFO_H + +#include "ace/FILE_Addr.h" +#include "ace/SString.h" + +/* Opaque class that represents a caller's ID */ +class CallerId +{ +public: + CallerId () : id_ (ACE_TEXT ("UNKNOWN")) + { } + + CallerId (ACE_TString id) : id_(id) + { } + + const ACE_TCHAR * string(void) + { + return this->id_.c_str (); + } + +private: + ACE_TString id_; +}; + +class MessageType +{ +public: + enum { + // Known video codecs + FIRST_VIDEO_CODEC = 1, + + DIVX, + // ... + LAST_VIDEO_CODEC, + + // Known audio codecs + FIRST_AUDIO_CODEC, + + MP3, + RAWPCM, + // ... + LAST_AUDIO_CODEC, + + // Known text codecs + FIRST_TEXT_CODEC, + + RAWTEXT, + XML, + + // ... + LAST_TEXT_CODEC, + + LAST_CODEC + }; + + MessageType (int codec, ACE_FILE_Addr addr) + : codec_(codec), addr_(addr) + { } + + int get_codec (void) + { + return this->codec_; + } + + ACE_FILE_Addr &get_addr (void) + { + return this->addr_; + } + + int is_video (void) + { + return + this->get_codec () > FIRST_VIDEO_CODEC && + this->get_codec () < LAST_VIDEO_CODEC; + } + + int is_audio (void) + { + return + this->get_codec () > FIRST_AUDIO_CODEC && + this->get_codec () < LAST_AUDIO_CODEC ; + } + + int is_text (void) + { + return + this->get_codec () > FIRST_TEXT_CODEC && + this->get_codec () < LAST_TEXT_CODEC ; + } + +private: + int codec_; + ACE_FILE_Addr addr_; +}; + +# endif /* MESSAGE_INFO_H */ diff --git a/ACE/examples/APG/Streams/RecordingDevice.h b/ACE/examples/APG/Streams/RecordingDevice.h new file mode 100644 index 00000000000..cee3d7154de --- /dev/null +++ b/ACE/examples/APG/Streams/RecordingDevice.h @@ -0,0 +1,119 @@ +/* -*- C++ -*- */ +// $Id$ + +#ifndef RECORDING_DEVICE_H +#define RECORDING_DEVICE_H + +#include "ace/FILE_Addr.h" +#include "ace/Event_Handler.h" +#include "ace/Log_Msg.h" +#include "ace/Reactor.h" +#include "ace/Semaphore.h" + +class CallerId; +class MessageType; + +class RecordingDevice +{ +public: + RecordingDevice () + { + // Initialize the semaphore so that we don't block on the + // first call to wait_for_activity(). + } + + virtual ~RecordingDevice () + { + } + + virtual const ACE_TCHAR *get_name (void) const + { + return ACE_TEXT ("UNKNOWN"); + } + + virtual int init (int, ACE_TCHAR *[]) + { + return 0; + } + + // Answer the incoming call + virtual int answer_call (void) = 0; + + // Fetch some form of caller identification at the hardware level. + virtual CallerId *retrieve_callerId (void) = 0; + + // Fetch the message at the location specified by 'addr' and play + // it for the caller. + virtual int play_message (ACE_FILE_Addr &addr) = 0; + + // Record data from our physical device into the file at the + // specified address. Return the number of bytes recorded. + virtual MessageType *record_message (ACE_FILE_Addr &addr) = 0; + + // Release the RecordingDevice to accept another incoming call + virtual void release (void) + { + this->release_semaphore (); + } + + // Get the handler of the device so that wait_for_activity() can + // wait for data to arrive. + virtual ACE_Event_Handler *get_handler (void) const + { + return 0; + } + + virtual RecordingDevice *wait_for_activity (void) + { + // Block on a semaphore until it says we're ready to do + // work. + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("Waiting for semaphore\n"))); + this->acquire_semaphore (); + + // Use the reactor to wait for activity on our handle + ACE_Reactor reactor; + + ACE_Event_Handler *handler = this->get_handler (); + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("Handler is %@\n"), + (void *)handler)); + + reactor.register_handler (this->get_handler (), + ACE_Event_Handler::READ_MASK); + + reactor.handle_events (); + // Error-check this... + + // Leave the semaphore locked so that we'll block until + // recording_complete() is invoked. + + return this; + } + +protected: + void acquire_semaphore (void) + { + this->semaphore_.acquire (); + } + + void release_semaphore (void) + { + // Reset the semaphore so that wait_for_activity() will + // unblock. + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("Releasing semaphore\n"))); + this->semaphore_.release (); + } + +private: + ACE_Semaphore semaphore_; +}; + +#include "RecordingDevice_Text.h" +#include "RecordingDevice_USRVM.h" +#include "RecordingDevice_QC.h" + +#include "RecordingDeviceFactory.h" + +#endif /* RECORDING_DEVICE_H */ diff --git a/ACE/examples/APG/Streams/RecordingDeviceFactory.cpp b/ACE/examples/APG/Streams/RecordingDeviceFactory.cpp new file mode 100644 index 00000000000..f5585e1ec0a --- /dev/null +++ b/ACE/examples/APG/Streams/RecordingDeviceFactory.cpp @@ -0,0 +1,25 @@ +// $Id$ + +#include "RecordingDevice.h" +#include "RecordingDeviceFactory.h" +#include "RecordingDevice_Text.h" + +RecordingDevice *RecordingDeviceFactory::instantiate (int argc, + ACE_TCHAR *argv[]) +{ + RecordingDevice * device = 0; + + // Determine the implementation based on the values of argv + // Exclude 2 + device = new TextListenerAcceptor (); + // Exclude 2 + + // Initialize the device with the remaining parameters. + if (device->init (argc, argv) < 0) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("RecordingDeviceFactory::instantiate() - ") + ACE_TEXT ("%s->init(argc, argv)"), + device->get_name()), + 0); + return device; +} diff --git a/ACE/examples/APG/Streams/RecordingDeviceFactory.h b/ACE/examples/APG/Streams/RecordingDeviceFactory.h new file mode 100644 index 00000000000..13485b20947 --- /dev/null +++ b/ACE/examples/APG/Streams/RecordingDeviceFactory.h @@ -0,0 +1,22 @@ +/* -*- C++ -*- */ +// $Id$ + +#ifndef RECORDING_DEVICE_FACTORY_H +#define RECORDING_DEVICE_FACTORY_H + +class RecordingDevice; + +/* + * A factory class that creates an appropriate RecordingDevice + * derivative based on command-line parameters. + */ +class RecordingDeviceFactory +{ +public: + + // Instantiate the appropriate RecordingDevice implementation + static RecordingDevice *instantiate (int argc, ACE_TCHAR *argv[]); +}; + +#endif /* RECORDING_DEVICE_FACTORY_H */ + diff --git a/ACE/examples/APG/Streams/RecordingDevice_QC.h b/ACE/examples/APG/Streams/RecordingDevice_QC.h new file mode 100644 index 00000000000..356d70afc5c --- /dev/null +++ b/ACE/examples/APG/Streams/RecordingDevice_QC.h @@ -0,0 +1,5 @@ +// $Id$ + +class QuickCam : public RecordingDevice + { + }; diff --git a/ACE/examples/APG/Streams/RecordingDevice_Text.cpp b/ACE/examples/APG/Streams/RecordingDevice_Text.cpp new file mode 100644 index 00000000000..01720bb2470 --- /dev/null +++ b/ACE/examples/APG/Streams/RecordingDevice_Text.cpp @@ -0,0 +1,197 @@ +/* + * $Id$ + * + * A RecordingDevice that listens to a socket and collects text. + */ + +#include "MessageInfo.h" +#include "RecordingDevice.h" +#include "RecordingDevice_Text.h" +#include "Util.h" + +TextListenerAcceptor::TextListenerAcceptor (void) + : ACE_Event_Handler(), RecordingDevice() +{ } + +// ACE_Event_Handler interface + +int TextListenerAcceptor::open (ACE_INET_Addr &addr) +{ + if (this->acceptor_.open (addr, 1) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("acceptor open")), + -1); + return 0; +} + +ACE_HANDLE TextListenerAcceptor::get_handle (void) const +{ + return this->acceptor_.get_handle (); +} + +int TextListenerAcceptor::handle_input (ACE_HANDLE) +{ + ACE_DEBUG ((LM_INFO, + ACE_TEXT ("TextListenerAcceptor - connection request\n" ))); + return 0; +} + +int TextListenerAcceptor::accept (ACE_SOCK_Stream &peer) +{ + return this->acceptor_.accept (peer); +} + +// RecordingDevice interface + +// Open a listening socket on the port specified by argv. +int TextListenerAcceptor::init (int argc, ACE_TCHAR *argv[]) +{ + ACE_UNUSED_ARG(argc); + + ACE_INET_Addr addr (argv[1]); + + if (this->open (addr) < 0) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("TextListener - open")), + -1); + return 0; +} + +ACE_Event_Handler *TextListenerAcceptor::get_handler (void) const +{ + return (ACE_Event_Handler *)this; +} + +RecordingDevice *TextListenerAcceptor::wait_for_activity (void) +{ + this->RecordingDevice::wait_for_activity (); + return new TextListener (this); +} + +int TextListenerAcceptor::answer_call (void) +{ + return -1; +} + +CallerId *TextListenerAcceptor::retrieve_callerId (void) +{ + return 0; +} + +int TextListenerAcceptor::play_message (ACE_FILE_Addr &addr) +{ + ACE_UNUSED_ARG(addr); + return 0; +} + +MessageType *TextListenerAcceptor::record_message (ACE_FILE_Addr &addr) +{ + ACE_UNUSED_ARG(addr); + return 0; +} + + +// Listing 01 code/ch18 +TextListener::TextListener (TextListenerAcceptor *acceptor) + : acceptor_(acceptor) +{ + ACE_TRACE ("TextListener ctor"); + + ACE_NEW (this->command_stream_, CommandStream (&(this->peer_))); + this->command_stream_->open (0); +} +// Listing 01 + +const ACE_TCHAR *TextListener::get_name (void) const +{ + return ACE_TEXT ("TextListener"); +} + +// Listing 02 code/ch18 +int TextListener::answer_call (void) +{ + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("TextListener::answer_call()\n"))); + + Command *c = new Command (); + c->command_ = Command::CMD_ANSWER_CALL; + c->extra_data_ = this->acceptor_; + + c = this->command_stream_->execute (c); + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("TextListener::answer_call() ") + ACE_TEXT ("result is %d\n"), + c->numeric_result_)); + + return c->numeric_result_; +} +// Listing 02 + +// Listing 03 code/ch18 +CallerId *TextListener::retrieve_callerId (void) +{ + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("TextListener::retrieve_callerId()\n"))); + + Command *c = new Command (); + c->command_ = Command::CMD_RETRIEVE_CALLER_ID; + + c = this->command_stream_->execute (c); + + CallerId *caller_id = new CallerId (c->result_); + return caller_id; +} +// Listing 03 + +// Listing 04 code/ch18 +int TextListener::play_message (ACE_FILE_Addr &addr) +{ + MessageType *type = Util::identify_message (addr); + if (type->is_text ()) + { + Command *c = new Command (); + c->command_ = Command::CMD_PLAY_MESSAGE; + c->extra_data_ = &addr; + c = this->command_stream_->execute (c); + return c->numeric_result_; + } + + ACE_FILE_Addr temp (ACE_TEXT ("/tmp/outgoing_message.text")); + ACE_FILE_IO *file; + if (type->is_audio ()) + file = Util::audio_to_text (addr, temp); + else if (type->is_video ()) + file = Util::video_to_text (addr, temp); + else + ACE_ERROR_RETURN + ((LM_ERROR, ACE_TEXT ("Invalid message type %d\n"), + type->get_codec ()), -1); + int rval = this->play_message (temp); + file->remove (); + return rval; +} +// Listing 04 + +// Listing 05 code/ch18 +MessageType *TextListener::record_message (ACE_FILE_Addr &addr) +{ + Command *c = new Command (); + c->command_ = Command::CMD_RECORD_MESSAGE; + c->extra_data_ = &addr; + c = this->command_stream_->execute (c); + if (c->numeric_result_ == -1) + return 0; + + return new MessageType (MessageType::RAWTEXT, addr); +} +// Listing 05 + +// Listing 06 code/ch18 +void TextListener::release (void) +{ + delete this; +} +// Listing 06 diff --git a/ACE/examples/APG/Streams/RecordingDevice_Text.h b/ACE/examples/APG/Streams/RecordingDevice_Text.h new file mode 100644 index 00000000000..a49f400d922 --- /dev/null +++ b/ACE/examples/APG/Streams/RecordingDevice_Text.h @@ -0,0 +1,84 @@ +/* -*- C++ -*- */ +/* + * $Id$ + * + * A RecordingDevice that listens to a socket and collects text. + */ + +#ifndef RECORDING_DEVICE_TEXT_H +#define RECORDING_DEVICE_TEXT_H + +#include "ace/FILE_IO.h" +#include "ace/FILE_Connector.h" +#include "ace/SOCK_Stream.h" +#include "ace/SOCK_Acceptor.h" + +#include "CommandStream.h" +#include "MessageInfo.h" +#include "RecordingDevice.h" + +class TextListenerAcceptor : + public ACE_Event_Handler, + public RecordingDevice +{ +public: + TextListenerAcceptor (); + + // ACE_Event_Handler interface + + int open (ACE_INET_Addr &addr); + + ACE_HANDLE get_handle (void) const; + + int handle_input (ACE_HANDLE); + + int accept (ACE_SOCK_Stream &peer); + + // RecordingDevice interface + + // Open a listening socket on the port specified by argv. + int init (int argc, ACE_TCHAR *argv[]); + + ACE_Event_Handler *get_handler (void) const; + + virtual RecordingDevice *wait_for_activity (void); + + virtual int answer_call (void); + + virtual CallerId *retrieve_callerId (void); + + virtual int play_message (ACE_FILE_Addr &addr); + + virtual MessageType *record_message (ACE_FILE_Addr &addr); + +private: + ACE_SOCK_Acceptor acceptor_; +}; + +// Listing 01 code/ch18 +class TextListener : public RecordingDevice +{ +public: + TextListener (TextListenerAcceptor *acceptor); + + virtual const ACE_TCHAR *get_name (void) const; + + int answer_call (void); + + CallerId *retrieve_callerId (void); + + int play_message (ACE_FILE_Addr &addr); + + MessageType *record_message (ACE_FILE_Addr &addr); + + virtual void release (void); + // Listing 01 + // Listing 02 code/ch18 +private: + CommandStream *command_stream_; + TextListenerAcceptor *acceptor_; + ACE_SOCK_Stream peer_; +}; +// Listing 02 + +#endif /* RECORDING_DEVICE_TEXT_H */ diff --git a/ACE/examples/APG/Streams/RecordingDevice_USRVM.h b/ACE/examples/APG/Streams/RecordingDevice_USRVM.h new file mode 100644 index 00000000000..7519f7c1c84 --- /dev/null +++ b/ACE/examples/APG/Streams/RecordingDevice_USRVM.h @@ -0,0 +1,5 @@ +// $Id$ + +class USRoboticsVoiceModem : public RecordingDevice + { + }; diff --git a/ACE/examples/APG/Streams/Util.h b/ACE/examples/APG/Streams/Util.h new file mode 100644 index 00000000000..d47a699aee7 --- /dev/null +++ b/ACE/examples/APG/Streams/Util.h @@ -0,0 +1,92 @@ +/* -*- C++ -*- */ +// $Id$ + +#ifndef UTIL_H +#define UTIL_H + +#include "ace/FILE_Addr.h" +#include "ace/FILE_Connector.h" +#include "ace/FILE_IO.h" + +class Util +{ +public: + static MessageType *identify_message (ACE_FILE_Addr &src) + { + // Determine the contents of the specified file + return new MessageType (MessageType::RAWTEXT, src); + } + + static ACE_FILE_IO *audio_to_text (ACE_FILE_Addr &, ACE_FILE_Addr &dest) + { + ACE_FILE_Connector connector; + ACE_FILE_IO *file = 0; + if (connector.connect (*file, dest) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("create file")), + 0); + + // Convert audio data to printable text + + return file; + } + + static ACE_FILE_IO *video_to_text (ACE_FILE_Addr &, ACE_FILE_Addr &dest) + { + ACE_FILE_Connector connector; + ACE_FILE_IO *file = 0; + if (connector.connect (*file, dest) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("create file")), + 0); + + // Extract audio data from video file and convert to printable text + return file; + } + + static int convert_to_unicode (ACE_FILE_Addr &src, ACE_FILE_Addr &dest) + { + ACE_FILE_Connector connector; + ACE_FILE_IO input; + if (connector.connect (input, src) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("read file")), + 0); + ACE_FILE_IO output; + if (connector.connect (output, dest) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("create file")), + 0); + + char rwbuf[512]; + ssize_t rwbytes; + while ((rwbytes = input.recv (rwbuf, 512)) > 0) + { + output.send_n (rwbuf, rwbytes); + } + + input.close (); + output.close (); + + // Convert arbirary text to unicode + return 0; + } + + static int convert_to_mp3 (ACE_FILE_Addr &, ACE_FILE_Addr &) + { + // Convert arbitrary audio data to some standard mp3 format + return 0; + } + + static int convert_to_mpeg (ACE_FILE_Addr &, ACE_FILE_Addr &) + { + // Convert arbitrary vidio data to some standard mpeg format + return 0; + } +}; + +#endif /* UTIL_H */ diff --git a/ACE/examples/APG/Streams/streams.mpc b/ACE/examples/APG/Streams/streams.mpc new file mode 100644 index 00000000000..df74b446031 --- /dev/null +++ b/ACE/examples/APG/Streams/streams.mpc @@ -0,0 +1,17 @@ +// -*- MPC -*- +// $Id$ + +project(Answerer) : aceexe { + avoids += ace_for_tao + exename = Answerer + requires += threads + Source_Files { + Answerer.cpp + CommandModule.cpp + CommandStream.cpp + CommandTask.cpp + CommandTasks.cpp + RecordingDeviceFactory.cpp + RecordingDevice_Text.cpp + } +} diff --git a/ACE/examples/APG/Svc_Config/.cvsignore b/ACE/examples/APG/Svc_Config/.cvsignore new file mode 100644 index 00000000000..c508d301216 --- /dev/null +++ b/ACE/examples/APG/Svc_Config/.cvsignore @@ -0,0 +1,4 @@ +HA_Configurable_Server_Dynamic +HA_Configurable_Server_Dynamic +HA_Configurable_Server_Static +HA_Configurable_Server_Static diff --git a/ACE/examples/APG/Svc_Config/HASTATUS_export.h b/ACE/examples/APG/Svc_Config/HASTATUS_export.h new file mode 100644 index 00000000000..9115c514089 --- /dev/null +++ b/ACE/examples/APG/Svc_Config/HASTATUS_export.h @@ -0,0 +1,53 @@ +// -*- C++ -*- +// $Id$ +// Definition for Win32 Export directives. +// This file is generated automatically by generate_export_file.pl HASTATUS +// ------------------------------ +#ifndef HASTATUS_EXPORT_H +#define HASTATUS_EXPORT_H + +#include "ace/config-all.h" + +#if defined (ACE_AS_STATIC_LIBS) && !defined (HASTATUS_HAS_DLL) +# define HASTATUS_HAS_DLL 0 +#endif /* ACE_AS_STATIC_LIBS && ! HASTATUS_HAS_DLL */ + +#if !defined (HASTATUS_HAS_DLL) +# define HASTATUS_HAS_DLL 1 +#endif /* ! HASTATUS_HAS_DLL */ + +#if defined (HASTATUS_HAS_DLL) && (HASTATUS_HAS_DLL == 1) +# if defined (HASTATUS_BUILD_DLL) +# define HASTATUS_Export ACE_Proper_Export_Flag +# define HASTATUS_SINGLETON_DECLARATION(T) ACE_EXPORT_SINGLETON_DECLARATION (T) +# define HASTATUS_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) ACE_EXPORT_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) +# else /* HASTATUS_BUILD_DLL */ +# define HASTATUS_Export ACE_Proper_Import_Flag +# define HASTATUS_SINGLETON_DECLARATION(T) ACE_IMPORT_SINGLETON_DECLARATION (T) +# define HASTATUS_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) ACE_IMPORT_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) +# endif /* HASTATUS_BUILD_DLL */ +#else /* HASTATUS_HAS_DLL == 1 */ +# define HASTATUS_Export +# define HASTATUS_SINGLETON_DECLARATION(T) +# define HASTATUS_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) +#endif /* HASTATUS_HAS_DLL == 1 */ + +// Set HASTATUS_NTRACE = 0 to turn on library specific tracing even if +// tracing is turned off for ACE. +#if !defined (HASTATUS_NTRACE) +# if (ACE_NTRACE == 1) +# define HASTATUS_NTRACE 1 +# else /* (ACE_NTRACE == 1) */ +# define HASTATUS_NTRACE 0 +# endif /* (ACE_NTRACE == 1) */ +#endif /* !HASTATUS_NTRACE */ + +#if (HASTATUS_NTRACE == 1) +# define HASTATUS_TRACE(X) +#else /* (HASTATUS_NTRACE == 1) */ +# define HASTATUS_TRACE(X) ACE_TRACE _IMPL(X) +#endif /* (HASTATUS_NTRACE == 1) */ + +#endif /* HASTATUS_EXPORT_H */ + +// End of auto generated file. diff --git a/ACE/examples/APG/Svc_Config/HA_Configurable_Server_Dynamic.cpp b/ACE/examples/APG/Svc_Config/HA_Configurable_Server_Dynamic.cpp new file mode 100644 index 00000000000..1126a0393d1 --- /dev/null +++ b/ACE/examples/APG/Svc_Config/HA_Configurable_Server_Dynamic.cpp @@ -0,0 +1,17 @@ +// $Id$ + +// Listing 1 code/ch19 +#include "ace/OS_main.h" +#include "ace/Service_Config.h" +#include "ace/Reactor.h" + +int ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + ACE_Service_Config::open (argc, argv); + + // We use this version of the event loop so that reconfigurations + // are triggered properly. + ACE_Reactor::instance ()->run_reactor_event_loop (ACE_Reactor::check_reconfiguration); + return 0; +} +// Listing 1 diff --git a/ACE/examples/APG/Svc_Config/HA_Configurable_Server_Static.cpp b/ACE/examples/APG/Svc_Config/HA_Configurable_Server_Static.cpp new file mode 100644 index 00000000000..8ac10b08ee1 --- /dev/null +++ b/ACE/examples/APG/Svc_Config/HA_Configurable_Server_Static.cpp @@ -0,0 +1,18 @@ +// $Id$ + +// Listing 1 code/ch19 +#include "ace/OS_main.h" +#include "ace/Service_Config.h" +#include "ace/Reactor.h" + +int ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + ACE_STATIC_SVC_REGISTER (HA_Status_Descriptor); + ACE_Service_Config::open (argc, + argv, + ACE_DEFAULT_LOGGER_KEY, + 0); + ACE_Reactor::instance ()->run_reactor_event_loop (); + return 0; +} +// Listing 1 diff --git a/ACE/examples/APG/Svc_Config/HA_Status_Dynamic.cpp b/ACE/examples/APG/Svc_Config/HA_Status_Dynamic.cpp new file mode 100644 index 00000000000..39f871a8bb3 --- /dev/null +++ b/ACE/examples/APG/Svc_Config/HA_Status_Dynamic.cpp @@ -0,0 +1,113 @@ +/** + * $Id$ + * + * Home Automation Status server. Sample code from The ACE Programmer's Guide, + * Copyright 2003 Addison-Wesley. All Rights Reserved. + */ + +#include "ace/OS_NS_stdio.h" +#include "ace/OS_NS_string.h" +#include "ace/Configuration.h" +#include "ace/Configuration_Import_Export.h" +#include "ace/Get_Opt.h" +#include "HA_Status_Dynamic.h" + +// Listing 1 code/ch19 +int +HA_Status::init (int argc, ACE_TCHAR *argv[]) +{ + static const ACE_TCHAR options[] = ACE_TEXT (":f:"); + ACE_Get_Opt cmd_opts (argc, argv, options, 0); + if (cmd_opts.long_option + (ACE_TEXT ("config"), 'f', ACE_Get_Opt::ARG_REQUIRED) == -1) + return -1; + int option; + ACE_TCHAR config_file[MAXPATHLEN]; + ACE_OS::strcpy (config_file, ACE_TEXT ("HAStatus.conf")); + while ((option = cmd_opts ()) != EOF) + switch (option) + { + case 'f': + ACE_OS::strncpy (config_file, + cmd_opts.opt_arg (), + MAXPATHLEN); + break; + case ':': + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("-%c requires an argument\n"), + cmd_opts.opt_opt ()), + -1); + default: + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("Parse error.\n")), + -1); + } + + ACE_Configuration_Heap config; + config.open (); + ACE_Registry_ImpExp config_importer (config); + if (config_importer.import_config (config_file) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + config_file), + -1); + + ACE_Configuration_Section_Key status_section; + if (config.open_section (config.root_section (), + ACE_TEXT ("HAStatus"), + 0, + status_section) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("Can't open HAStatus section")), + -1); + + u_int status_port; + if (config.get_integer_value (status_section, + ACE_TEXT ("ListenPort"), + status_port) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("HAStatus ListenPort ") + ACE_TEXT ("does not exist\n")), + -1); + this->listen_addr_.set (static_cast<u_short> (status_port)); + + if (this->acceptor_.open (this->listen_addr_) != 0) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("HAStatus %p\n"), + ACE_TEXT ("accept")), + -1); + + return 0; +} +// Listing 1 + +// Listing 2 code/ch19 +int +HA_Status::fini (void) +{ + this->acceptor_.close (); + return 0; +} +// Listing 2 + +// Listing 3 code/ch19 +int +HA_Status::info (ACE_TCHAR **str, size_t len) const + { + ACE_TCHAR buf[BUFSIZ]; + ACE_OS::sprintf (buf, + ACE_TEXT ("HAStatus listening on port %hu\n"), + this->listen_addr_.get_port_number ()); + if (*str == 0) + *str = ACE::strnew (buf); + else + ACE_OS::strncpy (*str, buf, len); + return static_cast<int> (ACE_OS::strlen (*str)); + } +// Listing 3 + +// Listing 4 code/ch19 +ACE_FACTORY_DEFINE (HASTATUS, HA_Status) +// Listing 4 + diff --git a/ACE/examples/APG/Svc_Config/HA_Status_Dynamic.h b/ACE/examples/APG/Svc_Config/HA_Status_Dynamic.h new file mode 100644 index 00000000000..c11f9a56d35 --- /dev/null +++ b/ACE/examples/APG/Svc_Config/HA_Status_Dynamic.h @@ -0,0 +1,43 @@ +/** + * $Id$ + * + * Home Automation Status server. Sample code from The ACE Programmer's Guide, + * copyright 2003 Addison-Wesley. All Rights Reserved. + */ + +#ifndef __HASTATUS_H_ +#define __HASTATUS_H_ + +// Listing 1 code/ch19 +#include "ace/OS.h" +#include "ace/Acceptor.h" +#include "ace/INET_Addr.h" +#include "ace/SOCK_Stream.h" +#include "ace/SOCK_Acceptor.h" +#include "ace/Service_Object.h" +#include "ace/Svc_Handler.h" + +#include "HASTATUS_export.h" + +class ClientHandler : + public ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH> +{ + // ... Same as previous examples. +}; + +class HASTATUS_Export HA_Status : public ACE_Service_Object +{ + public: + virtual int init (int argc, ACE_TCHAR *argv[]); + + virtual int fini (void); + + virtual int info (ACE_TCHAR **str, size_t len) const; + + private: + ACE_Acceptor<ClientHandler, ACE_SOCK_ACCEPTOR> acceptor_; + ACE_INET_Addr listen_addr_; +}; +// Listing 1 + +#endif /* __HASTATUS_H_ */ diff --git a/ACE/examples/APG/Svc_Config/HA_Status_Static.cpp b/ACE/examples/APG/Svc_Config/HA_Status_Static.cpp new file mode 100644 index 00000000000..ef09bcaa5cd --- /dev/null +++ b/ACE/examples/APG/Svc_Config/HA_Status_Static.cpp @@ -0,0 +1,121 @@ +/** + * $Id$ + * + * Home Automation Status server. Sample code from The ACE Programmer's Guide, + * Copyright 2003 Addison-Wesley. All Rights Reserved. + */ + +#include "ace/OS_NS_stdio.h" +#include "ace/OS_NS_string.h" +#include "ace/Configuration.h" +#include "ace/Configuration_Import_Export.h" +#include "ace/Get_Opt.h" +#include "HA_Status_Static.h" + +// Listing 1 code/ch19 +int +HA_Status::init (int argc, ACE_TCHAR *argv[]) +{ + static const ACE_TCHAR options[] = ACE_TEXT (":f:"); + ACE_Get_Opt cmd_opts (argc, argv, options, 0); + if (cmd_opts.long_option + (ACE_TEXT ("config"), 'f', ACE_Get_Opt::ARG_REQUIRED) == -1) + return -1; + int option; + ACE_TCHAR config_file[MAXPATHLEN]; + ACE_OS::strcpy (config_file, ACE_TEXT ("HAStatus.conf")); + while ((option = cmd_opts ()) != EOF) + switch (option) + { + case 'f': + ACE_OS::strncpy (config_file, + cmd_opts.opt_arg (), + MAXPATHLEN); + break; + case ':': + ACE_ERROR_RETURN + ((LM_ERROR, ACE_TEXT ("-%c requires an argument\n"), + cmd_opts.opt_opt ()), + -1); + default: + ACE_ERROR_RETURN + ((LM_ERROR, ACE_TEXT ("Parse error.\n")), -1); + } + + ACE_Configuration_Heap config; + config.open (); + ACE_Registry_ImpExp config_importer (config); + if (config_importer.import_config (config_file) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + config_file), + -1); + + ACE_Configuration_Section_Key status_section; + if (config.open_section (config.root_section (), + ACE_TEXT ("HAStatus"), + 0, + status_section) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("Can't open HAStatus section")), + -1); + + u_int status_port; + if (config.get_integer_value (status_section, + ACE_TEXT ("ListenPort"), + status_port) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("HAStatus ListenPort does ") + ACE_TEXT ("not exist\n")), + -1); + this->listen_addr_.set (static_cast<u_short> (status_port)); + + if (this->acceptor_.open (this->listen_addr_) != 0) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("HAStatus %p\n"), + ACE_TEXT ("accept")), + -1); + + return 0; +} +// Listing 1 + +// Listing 2 code/ch19 +int +HA_Status::fini (void) +{ + this->acceptor_.close (); + return 0; +} +// Listing 2 + +// Listing 3 code/ch19 +int +HA_Status::info (ACE_TCHAR **str, size_t len) const + { + ACE_TCHAR buf[BUFSIZ]; + ACE_OS::sprintf (buf, ACE_TEXT ("HAStatus listening on port %hu\n"), + this->listen_addr_.get_port_number ()); + if (*str == 0) + *str = ACE::strnew (buf); + else + ACE_OS::strncpy (*str, buf, len); + return static_cast<int> (ACE_OS::strlen (*str)); + } +// Listing 3 + +// Listing 4 code/ch19 +ACE_FACTORY_DEFINE (ACE_Local_Service, HA_Status) + +ACE_STATIC_SVC_DEFINE (HA_Status_Descriptor, + ACE_TEXT ("HA_Status_Static_Service"), + ACE_SVC_OBJ_T, + &ACE_SVC_NAME (HA_Status), + ACE_Service_Type::DELETE_THIS | + ACE_Service_Type::DELETE_OBJ, + 0) // Service not initially active + +ACE_STATIC_SVC_REQUIRE (HA_Status_Descriptor) +// Listing 4 + diff --git a/ACE/examples/APG/Svc_Config/HA_Status_Static.h b/ACE/examples/APG/Svc_Config/HA_Status_Static.h new file mode 100644 index 00000000000..d4926ff0460 --- /dev/null +++ b/ACE/examples/APG/Svc_Config/HA_Status_Static.h @@ -0,0 +1,40 @@ +/** + * $Id$ + * + * Home Automation Status server. Sample code from The ACE Programmer's Guide, + * copyright 2003 Addison-Wesley. All Rights Reserved. + */ + +#ifndef __HASTATUS_H_ +#define __HASTATUS_H_ + +// Listing 1 code/ch19 +#include "ace/OS.h" +#include "ace/Acceptor.h" +#include "ace/INET_Addr.h" +#include "ace/SOCK_Stream.h" +#include "ace/SOCK_Acceptor.h" +#include "ace/Service_Object.h" +#include "ace/Svc_Handler.h" +#include "ace/Service_Config.h" + +class ClientHandler : + public ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH> +{ + // ... Same as previous examples. +}; + +class HA_Status : public ACE_Service_Object +{ + public: + virtual int init (int argc, ACE_TCHAR *argv[]); + virtual int fini (void); + virtual int info (ACE_TCHAR **str, size_t len) const; + + private: + ACE_Acceptor<ClientHandler, ACE_SOCK_ACCEPTOR> acceptor_; + ACE_INET_Addr listen_addr_; +}; +// Listing 1 + +#endif /* __HASTATUS_H_ */ diff --git a/ACE/examples/APG/Svc_Config/Makefile.am b/ACE/examples/APG/Svc_Config/Makefile.am new file mode 100644 index 00000000000..9fa3e2f18b6 --- /dev/null +++ b/ACE/examples/APG/Svc_Config/Makefile.am @@ -0,0 +1,80 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +ACE_BUILDDIR = $(top_builddir) +ACE_ROOT = $(top_srcdir) + +noinst_PROGRAMS = + +## Makefile.HA_Configurable_Server_Dynamic.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS += HA_Configurable_Server_Dynamic + +HA_Configurable_Server_Dynamic_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +HA_Configurable_Server_Dynamic_SOURCES = \ + HA_Configurable_Server_Dynamic.cpp \ + HASTATUS_export.h \ + HA_Status_Dynamic.h \ + HA_Status_Static.h + +HA_Configurable_Server_Dynamic_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Makefile.HA_Configurable_Server_Static.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS += HA_Configurable_Server_Static + +HA_Configurable_Server_Static_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +HA_Configurable_Server_Static_SOURCES = \ + HA_Configurable_Server_Static.cpp \ + HA_Status_Static.cpp \ + HA_Status_Static.h + +HA_Configurable_Server_Static_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Makefile.Svc_Config_HA_Status.am + +if !BUILD_ACE_FOR_TAO + +noinst_LTLIBRARIES = libHA_Status.la + +libHA_Status_la_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) \ + -DHASTATUS_BUILD_DLL + +libHA_Status_la_SOURCES = \ + HA_Status_Dynamic.cpp + +noinst_HEADERS = \ + HA_Status_Dynamic.h + +endif !BUILD_ACE_FOR_TAO + +## Clean up template repositories, etc. +clean-local: + -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.* + -rm -f gcctemp.c gcctemp so_locations *.ics + -rm -rf cxx_repository ptrepository ti_files + -rm -rf templateregistry ir.out + -rm -rf ptrepository SunWS_cache Templates.DB diff --git a/ACE/examples/APG/Svc_Config/status.ini b/ACE/examples/APG/Svc_Config/status.ini new file mode 100644 index 00000000000..8a36fb124fa --- /dev/null +++ b/ACE/examples/APG/Svc_Config/status.ini @@ -0,0 +1,2 @@ +[HAStatus] +"ListenPort"=dword:000001ec diff --git a/ACE/examples/APG/Svc_Config/svc.conf.dynamic b/ACE/examples/APG/Svc_Config/svc.conf.dynamic new file mode 100644 index 00000000000..e8ffb12c8ad --- /dev/null +++ b/ACE/examples/APG/Svc_Config/svc.conf.dynamic @@ -0,0 +1,2 @@ +dynamic HA_Status_Dynamic_Service Service_Object * +HA_Status:_make_HA_Status() "-f status.ini" diff --git a/ACE/examples/APG/Svc_Config/svc.conf.static b/ACE/examples/APG/Svc_Config/svc.conf.static new file mode 100644 index 00000000000..0103380c776 --- /dev/null +++ b/ACE/examples/APG/Svc_Config/svc.conf.static @@ -0,0 +1 @@ +static HA_Status_Static_Service "-f status.ini" diff --git a/ACE/examples/APG/Svc_Config/svc_config.mpc b/ACE/examples/APG/Svc_Config/svc_config.mpc new file mode 100644 index 00000000000..ddc33b97c53 --- /dev/null +++ b/ACE/examples/APG/Svc_Config/svc_config.mpc @@ -0,0 +1,28 @@ +// -*- MPC -*- +// $Id$ + +project(*HA Status) : acelib { + avoids += ace_for_tao + sharedname = HA_Status + dynamicflags = HASTATUS_BUILD_DLL + Source_Files { + HA_Status_Dynamic.cpp + } +} + +project(HA Configurable Server Dynamic) : aceexe { + avoids += ace_for_tao + exename = HA_Configurable_Server_Dynamic + Source_Files { + HA_Configurable_Server_Dynamic.cpp + } +} + +project(HA Configurable Server Static) : aceexe { + avoids += ace_for_tao + exename = HA_Configurable_Server_Static + Source_Files { + HA_Configurable_Server_Static.cpp + HA_Status_Static.cpp + } +} diff --git a/ACE/examples/APG/ThreadManagement/.cvsignore b/ACE/examples/APG/ThreadManagement/.cvsignore new file mode 100644 index 00000000000..535a0039a50 --- /dev/null +++ b/ACE/examples/APG/ThreadManagement/.cvsignore @@ -0,0 +1,18 @@ +Async_Cancel +Async_Cancel +Coop_Cancel +Coop_Cancel +ExitHandler +ExitHandler +Pool +Pool +Priorities +Priorities +Signals +Signals +Signals2 +Signals2 +Start_Hook +Start_Hook +State +State diff --git a/ACE/examples/APG/ThreadManagement/Async_Cancel.cpp b/ACE/examples/APG/ThreadManagement/Async_Cancel.cpp new file mode 100644 index 00000000000..5d5d5fcf0e8 --- /dev/null +++ b/ACE/examples/APG/ThreadManagement/Async_Cancel.cpp @@ -0,0 +1,63 @@ +// $Id$ + +#include "ace/OS_NS_unistd.h" +#include "ace/Task.h" +#include "ace/Log_Msg.h" + +#if defined (ACE_HAS_PTHREADS) +// Only works on Pthreads... + +// Listing 1 code/ch13 +class CanceledTask : public ACE_Task<ACE_MT_SYNCH> +{ +public: + virtual int svc (void) + { + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) Starting thread\n"))); + + if (this->set_cancel_mode () < 0) + return -1; + + while (1) + { + // Put this thread in a compute loop.. no + // cancellation points are available. + } + } + + int set_cancel_mode (void) + { + cancel_state new_state; + + // Set the cancel state to asynchronous and enabled. + new_state.cancelstate = PTHREAD_CANCEL_ENABLE; + new_state.canceltype = PTHREAD_CANCEL_ASYNCHRONOUS; + if (ACE_Thread::setcancelstate (new_state, 0) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("cancelstate")), -1); + return 0; + } +}; +// Listing 1 +// Listing 2 code/ch13 +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + CanceledTask task; + task.activate (); + ACE_OS::sleep (1); + ACE_Thread_Manager::instance ()->cancel_task (&task, 1); + task.wait (); + + return 0; +} +// Listing 2 + +#else /* ACE_HAS_PTHREADS */ +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + puts ("This example works on Pthreads platforms.\n"); + return 0; +} +#endif /* ACE_HAS_PTHREADS */ + diff --git a/ACE/examples/APG/ThreadManagement/Coop_Cancel.cpp b/ACE/examples/APG/ThreadManagement/Coop_Cancel.cpp new file mode 100644 index 00000000000..4a7714cf14b --- /dev/null +++ b/ACE/examples/APG/ThreadManagement/Coop_Cancel.cpp @@ -0,0 +1,68 @@ +// $Id$ + +#include "ace/config-lite.h" +#if defined (ACE_HAS_THREADS) + +#include "ace/OS_NS_time.h" +#include "ace/OS_NS_unistd.h" +#include "ace/Task.h" +#include "ace/Log_Msg.h" + +// Listing 1 code/ch13 +class CanceledTask : public ACE_Task<ACE_MT_SYNCH> +{ +public: + + virtual int svc (void) + { + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) starting up \n"))); + + // Cache our ACE_Thread_Manager pointer. + ACE_Thread_Manager *mgr = this->thr_mgr (); + while (1) + { + if (mgr->testcancel (mgr->thr_self ())) + return 0; + + ACE_Message_Block *mb = 0; + ACE_Time_Value tv (0, 1000); + tv += ACE_OS::time (0); + int result = this->getq (mb, &tv); + if (result == -1 && errno == EWOULDBLOCK) + continue; + else + { + // Do real work. + } + } + + ACE_NOTREACHED (return 0); + } +}; +// Listing 1 + +// Listing 2 code/ch13 +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + CanceledTask task; + task.activate (); + + ACE_OS::sleep (1); + + ACE_Thread_Manager::instance ()->cancel_task (&task); + task.wait (); + return 0; +} +// Listing 2 + +#else +#include "ace/OS_main.h" +#include "ace/OS_NS_stdio.h" + +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_OS::puts (ACE_TEXT ("This example requires threads.")); + return 0; +} + +#endif /* ACE_HAS_THREADS */ diff --git a/ACE/examples/APG/ThreadManagement/ExitHandler.cpp b/ACE/examples/APG/ThreadManagement/ExitHandler.cpp new file mode 100644 index 00000000000..85238eac052 --- /dev/null +++ b/ACE/examples/APG/ThreadManagement/ExitHandler.cpp @@ -0,0 +1,71 @@ +// $Id$ + +// Listing 1 code/ch13 +#include "ace/Task.h" +#include "ace/Log_Msg.h" + +class ExitHandler : public ACE_At_Thread_Exit +{ +public: + virtual void apply (void) + { + ACE_DEBUG ((LM_INFO, ACE_TEXT ("(%t) is exiting \n"))); + + // Shut down all devices. + } +}; +// Listing 1 +// Listing 2 code/ch13 +class HA_CommandHandler : public ACE_Task_Base +{ +public: + HA_CommandHandler(ExitHandler& eh) : eh_(eh) + { } + + virtual int svc (void) + { + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) starting up \n"))); + + this->thr_mgr ()->at_exit (eh_); + + // Do something. + + // Forcefully exit. + ACE_Thread::exit (); + + // NOT REACHED + return 0; + } + +private: + ExitHandler& eh_; +}; +// Listing 2 +// Listing 3 code/ch13 +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ExitHandler eh; + + HA_CommandHandler handler (eh); + handler.activate (); + + ACE_Thread_Manager::instance ()->wait (); + return 0; +} +// Listing 3 +#if 0 +// Listing 4 code/ch13 +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ExitHandler eh; + ACE_Thread_Manager tm; + + HA_CommandHandler handler (eh); + handler.thr_mgr (&tm); + handler.activate (); + + tm.wait(); + return 0; +} +// Listing 4 +#endif diff --git a/ACE/examples/APG/ThreadManagement/Makefile.am b/ACE/examples/APG/ThreadManagement/Makefile.am new file mode 100644 index 00000000000..0ed91996db2 --- /dev/null +++ b/ACE/examples/APG/ThreadManagement/Makefile.am @@ -0,0 +1,146 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +ACE_BUILDDIR = $(top_builddir) +ACE_ROOT = $(top_srcdir) + +## Makefile.Async_Cancel.am +noinst_PROGRAMS = Async_Cancel + +Async_Cancel_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +Async_Cancel_SOURCES = \ + Async_Cancel.cpp \ + SecurityContext.h + +Async_Cancel_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Coop_Cancel.am +noinst_PROGRAMS += Coop_Cancel + +Coop_Cancel_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +Coop_Cancel_SOURCES = \ + Coop_Cancel.cpp \ + SecurityContext.h + +Coop_Cancel_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.ExitHandler.am +noinst_PROGRAMS += ExitHandler + +ExitHandler_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +ExitHandler_SOURCES = \ + ExitHandler.cpp \ + SecurityContext.h + +ExitHandler_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Pool.am +noinst_PROGRAMS += Pool + +Pool_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +Pool_SOURCES = \ + Pool.cpp \ + SecurityContext.h + +Pool_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Priorities.am +noinst_PROGRAMS += Priorities + +Priorities_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +Priorities_SOURCES = \ + Priorities.cpp \ + SecurityContext.h + +Priorities_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Signals.am +noinst_PROGRAMS += Signals + +Signals_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +Signals_SOURCES = \ + Signals.cpp \ + SecurityContext.h + +Signals_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Signals2.am +noinst_PROGRAMS += Signals2 + +Signals2_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +Signals2_SOURCES = \ + Signals2.cpp \ + SecurityContext.h + +Signals2_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Start_Hook.am +noinst_PROGRAMS += Start_Hook + +Start_Hook_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +Start_Hook_SOURCES = \ + Start_Hook.cpp \ + SecurityContext.h + +Start_Hook_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.State.am +noinst_PROGRAMS += State + +State_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +State_SOURCES = \ + State.cpp \ + SecurityContext.h + +State_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Clean up template repositories, etc. +clean-local: + -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.* + -rm -f gcctemp.c gcctemp so_locations *.ics + -rm -rf cxx_repository ptrepository ti_files + -rm -rf templateregistry ir.out + -rm -rf ptrepository SunWS_cache Templates.DB diff --git a/ACE/examples/APG/ThreadManagement/Pool.cpp b/ACE/examples/APG/ThreadManagement/Pool.cpp new file mode 100644 index 00000000000..30ae56801a5 --- /dev/null +++ b/ACE/examples/APG/ThreadManagement/Pool.cpp @@ -0,0 +1,46 @@ +// $Id$ + +#include "ace/config-lite.h" +#if defined (ACE_HAS_THREADS) + +#include "ace/Task.h" +#include "ace/Log_Msg.h" + +// Listing 1 code/ch13 +class HA_CommandHandler : public ACE_Task<ACE_MT_SYNCH> +{ +public: + virtual int svc (void) + { + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) starting up \n"))); + ACE_Message_Block *mb; + if (this->getq (mb) == -1) + return -1; + // ... do something with the message. + return 0; + } +}; +// Listing 1 +// Listing 2 code/ch13 +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + HA_CommandHandler handler; + + // Create 4 threads. + handler.activate (THR_NEW_LWP | THR_JOINABLE, 4); + handler.wait (); + return 0; +} +// Listing 2 + +#else +#include "ace/OS_main.h" +#include "ace/OS_NS_stdio.h" + +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_OS::puts (ACE_TEXT ("This example requires threads.")); + return 0; +} + +#endif /* ACE_HAS_THREADS */ diff --git a/ACE/examples/APG/ThreadManagement/Priorities.cpp b/ACE/examples/APG/ThreadManagement/Priorities.cpp new file mode 100644 index 00000000000..3a80a613714 --- /dev/null +++ b/ACE/examples/APG/ThreadManagement/Priorities.cpp @@ -0,0 +1,104 @@ +// $Id$ + +#include "ace/config-lite.h" + +#if defined (ACE_HAS_THREADS) + +#include "ace/Task.h" +#include "ace/Log_Msg.h" +#include "ace/OS_NS_unistd.h" + +// Listing 2 code/ch13 +class HA_CommandHandler : public ACE_Task<ACE_MT_SYNCH> +{ +public: + HA_CommandHandler (const char *name) : name_ (name) + { } + + virtual int svc (void) + { + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) starting up %C\n"), + name_)); + + ACE_OS::sleep (2); + ACE_Message_Block *mb = 0; + while (this->getq (mb) != -1) + { + if (mb->msg_type () == ACE_Message_Block::MB_BREAK) + { + mb->release (); + break; + } + process_message (mb); + mb->release (); + } + return 0; + } + + void process_message (ACE_Message_Block *) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%t) Processing message %C\n"), + name_)); + // Simulate compute bound task. + for (int i = 0; i < 100; i++) + ; + } + +private: + const char *name_; +}; +// Listing 2 + +#if !defined (ACE_THR_PRI_OTHER_MAX) +// This should be fixed in ACE... There's no _MAX, _MIN values for +// thread priorities. +#if defined (ACE_WIN32) +# define ACE_THR_PRI_OTHER_MAX ((ACE_THR_PRI_OTHER_DEF) + 1) +#elif defined (VXWORKS) +# define ACE_THR_PRI_OTHER_MAX 0 +#endif +#endif + +// Listing 1 code/ch13 +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + HA_CommandHandler hp_handler ("HighPriority"); + hp_handler.activate (THR_NEW_LWP | THR_JOINABLE, + 1, 1, ACE_THR_PRI_OTHER_MAX); + + HA_CommandHandler lp_handler ("LowPriority"); + lp_handler.activate (THR_NEW_LWP | THR_JOINABLE, + 1, 1, ACE_THR_PRI_OTHER_DEF); + + ACE_Message_Block mb; + for (int i = 0; i < 100; i++) + { + ACE_Message_Block *mb_hp, *mb_lp; + mb_hp = mb.clone (); + mb_lp = mb.clone (); + hp_handler.putq (mb_hp); + lp_handler.putq (mb_lp); + } + + ACE_Message_Block stop (0, ACE_Message_Block::MB_BREAK); + hp_handler.putq (stop.clone ()); + lp_handler.putq (stop.clone ()); + hp_handler.wait (); + lp_handler.wait (); + + return 0; +} +// Listing 1 + +#else +#include "ace/OS_main.h" +#include "ace/OS_NS_stdio.h" + +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_OS::puts (ACE_TEXT ("This example requires threads.")); + return 0; +} + +#endif /* ACE_HAS_THREADS */ diff --git a/ACE/examples/APG/ThreadManagement/SecurityContext.h b/ACE/examples/APG/ThreadManagement/SecurityContext.h new file mode 100644 index 00000000000..73adbd1a435 --- /dev/null +++ b/ACE/examples/APG/ThreadManagement/SecurityContext.h @@ -0,0 +1,16 @@ +/** + * $Id$ + * + * Sample code from The ACE Programmer's Guide, + * copyright 2003 Addison-Wesley. All Rights Reserved. + */ + +#ifndef __SECURITYCONTEXT_H_ +#define __SECURITYCONTEXT_H_ + +struct SecurityContext + { + const char * user; + }; + +#endif /* __SECURITYCONTEXT_H_ */ diff --git a/ACE/examples/APG/ThreadManagement/Signals.cpp b/ACE/examples/APG/ThreadManagement/Signals.cpp new file mode 100644 index 00000000000..85547ed3249 --- /dev/null +++ b/ACE/examples/APG/ThreadManagement/Signals.cpp @@ -0,0 +1,93 @@ +// $Id$ + +#include "ace/config-lite.h" +#if defined (ACE_HAS_THREADS) + +#include "ace/OS_NS_time.h" +#include "ace/OS_NS_unistd.h" +#include "ace/Task.h" +#include "ace/Log_Msg.h" +#include "ace/Signal.h" +#include "ace/Sig_Handler.h" + +// Listing 1 code/ch13 +class SignalableTask : public ACE_Task<ACE_MT_SYNCH> +{ +public: + virtual int handle_signal (int signum, + siginfo_t * = 0, + ucontext_t * = 0) + { + if (signum == SIGUSR1) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%t) received a %S signal\n"), + signum)); + handle_alert (); + } + return 0; + } + + virtual int svc (void) + { + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) Starting thread\n"))); + + while (1) + { + ACE_Message_Block* mb = 0; + ACE_Time_Value tv (0, 1000); + tv += ACE_OS::time (0); + int result = this->getq (mb, &tv); + if (result == -1 && errno == EWOULDBLOCK) + continue; + else + process_message (mb); + } + + ACE_NOTREACHED (return 0); + } + + void handle_alert (); + void process_message (ACE_Message_Block *mb); +}; +// Listing 1 + +void +SignalableTask::process_message (ACE_Message_Block *) +{ +} + +void +SignalableTask::handle_alert () +{ +} + +// Listing 2 code/ch13 +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + SignalableTask handler; + handler.activate (THR_NEW_LWP | THR_JOINABLE , 5); + + ACE_Sig_Handler sh; + sh.register_handler (SIGUSR1, &handler); + + ACE_OS::sleep (1); + + ACE_Thread_Manager::instance () -> + kill_grp (handler.grp_id (), SIGUSR1); + handler.wait (); + return 0; +} +// Listing 2 + +#else +#include "ace/OS_main.h" +#include "ace/OS_NS_stdio.h" + +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_OS::puts (ACE_TEXT ("This example requires threads.")); + return 0; +} + +#endif /* ACE_HAS_THREADS */ diff --git a/ACE/examples/APG/ThreadManagement/Signals2.cpp b/ACE/examples/APG/ThreadManagement/Signals2.cpp new file mode 100644 index 00000000000..0df855c45bb --- /dev/null +++ b/ACE/examples/APG/ThreadManagement/Signals2.cpp @@ -0,0 +1,97 @@ +// $Id$ + +#include "ace/config-lite.h" +#if defined (ACE_HAS_THREADS) + +#include "ace/OS_NS_time.h" +#include "ace/OS_NS_unistd.h" +#include "ace/Task.h" +#include "ace/Log_Msg.h" +#include "ace/Signal.h" +#include "ace/Sig_Handler.h" + +class SignalableTask : public ACE_Task<ACE_MT_SYNCH> +{ +public: + virtual int handle_signal (int signum, + siginfo_t * = 0, + ucontext_t * = 0) + { + if (signum == SIGUSR1) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%t) received a %S signal\n"), + signum)); + handle_alert(); + } + + return 0; + } + + virtual int svc (void) + { + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) Starting thread\n"))); + + while (1) + { + ACE_Message_Block* mb = 0; + ACE_Time_Value tv (0, 1000); + tv += ACE_OS::time (0); + + int result = this->getq(mb, &tv); + + if (result == -1 && errno == EWOULDBLOCK) + continue; + else + process_message (mb); + } + + ACE_NOTREACHED (return 0); + } + + void handle_alert (); + void process_message (ACE_Message_Block *mb); +}; + +void +SignalableTask::process_message (ACE_Message_Block *) +{ + return; +} + +void +SignalableTask::handle_alert (void) +{ + return; +} + +// Listing 1 code/ch13 +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) Main thread \n"))); + SignalableTask handler; + handler.activate (THR_NEW_LWP | THR_JOINABLE, 5); + + ACE_Sig_Handler sh; + sh.register_handler (SIGUSR1, &handler); + + ACE_OS::sleep (1); // Allow threads to start + + for (int i = 0; i < 5; i++) + ACE_OS::kill (ACE_OS::getpid (), SIGUSR1); + handler.wait (); + return 0; +} +// Listing 1 + +#else +#include "ace/OS_main.h" +#include "ace/OS_NS_stdio.h" + +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_OS::puts (ACE_TEXT ("This example requires threads.")); + return 0; +} + +#endif /* ACE_HAS_THREADS */ diff --git a/ACE/examples/APG/ThreadManagement/Start_Hook.cpp b/ACE/examples/APG/ThreadManagement/Start_Hook.cpp new file mode 100644 index 00000000000..1c4ad0794b7 --- /dev/null +++ b/ACE/examples/APG/ThreadManagement/Start_Hook.cpp @@ -0,0 +1,60 @@ +// $Id$ + +#include "ace/Thread_Hook.h" +#include "ace/Task.h" +#include "ace/Log_Msg.h" + +#include "SecurityContext.h" + +// Listing 1 code/ch13 +class HA_ThreadHook : public ACE_Thread_Hook +{ +public: + virtual ACE_THR_FUNC_RETURN start (ACE_THR_FUNC func, void* arg) + { + ACE_DEBUG ((LM_DEBUG, ACE_TEXT("(%t) New Thread Spawned\n"))); + + // Create the context on the thread's own stack. + ACE_TSS<SecurityContext> secCtx; + // Special initialization. + add_sec_context_thr (secCtx); + + return (*func) (arg); + } + + void add_sec_context_thr (ACE_TSS<SecurityContext> &secCtx); +}; +// Listing 1 + +void +HA_ThreadHook::add_sec_context_thr(ACE_TSS<SecurityContext> &secCtx) +{ + secCtx->user = 0; +} + + +class HA_CommandHandler : public ACE_Task_Base +{ +public: + virtual int svc (void) + { + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) starting up \n"))); + + // Do something. + + return 0; + } +}; +// Listing 2 code/ch13 +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + HA_ThreadHook hook; + ACE_Thread_Hook::thread_hook (&hook); + + HA_CommandHandler handler; + handler.activate (); + handler.wait(); + return 0; +} +// Listing 2 + diff --git a/ACE/examples/APG/ThreadManagement/State.cpp b/ACE/examples/APG/ThreadManagement/State.cpp new file mode 100644 index 00000000000..d95433440c7 --- /dev/null +++ b/ACE/examples/APG/ThreadManagement/State.cpp @@ -0,0 +1,39 @@ +// $Id$ + +#include "ace/Task.h" + +class HA_CommandHandler : public ACE_Task_Base +{ +public: + virtual int svc (void) + { + ACE_DEBUG + ((LM_DEBUG, ACE_TEXT ("(%t) Handler Thread running\n"))); + return 0; + } +}; + + +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) Main Thread running\n"))); +// Listing 1 code/ch13 + HA_CommandHandler handler; + int result = handler.activate (THR_NEW_LWP | + THR_JOINABLE | + THR_SUSPENDED); + ACE_ASSERT (result == 0); + + ACE_UNUSED_ARG (result); + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%t) The current thread count is %d\n"), + handler.thr_count ())); + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%t) The group identifier is %d\n"), + handler.grp_id ())); + handler.resume (); + handler.wait (); +// Listing 1 + return 0; +} diff --git a/ACE/examples/APG/ThreadManagement/threadmgmt.mpc b/ACE/examples/APG/ThreadManagement/threadmgmt.mpc new file mode 100644 index 00000000000..bb765150abb --- /dev/null +++ b/ACE/examples/APG/ThreadManagement/threadmgmt.mpc @@ -0,0 +1,65 @@ +// -*- MPC -*- +// $Id$ + +project(Async Cancel) : aceexe { + exename = Async_Cancel + Source_Files { + Async_Cancel.cpp + } +} + +project(Coop Cancel) : aceexe { + exename = Coop_Cancel + Source_Files { + Coop_Cancel.cpp + } +} + +project(ExitHandler) : aceexe { + exename = ExitHandler + Source_Files { + ExitHandler.cpp + } +} + +project(Pool) : aceexe { + exename = Pool + Source_Files { + Pool.cpp + } +} + +project(Priorities) : aceexe { + exename = Priorities + Source_Files { + Priorities.cpp + } +} + +project(Signals) : aceexe { + exename = Signals + Source_Files { + Signals.cpp + } +} + +project(Signals2) : aceexe { + exename = Signals2 + Source_Files { + Signals2.cpp + } +} + +project(Start Hook) : aceexe { + exename = Start_Hook + Source_Files { + Start_Hook.cpp + } +} + +project(State) : aceexe { + exename = State + Source_Files { + State.cpp + } +} diff --git a/ACE/examples/APG/ThreadPools/.cvsignore b/ACE/examples/APG/ThreadPools/.cvsignore new file mode 100644 index 00000000000..7052a85815f --- /dev/null +++ b/ACE/examples/APG/ThreadPools/.cvsignore @@ -0,0 +1,10 @@ +Futures +Futures +LF_ThreadPool +LF_ThreadPool +TP_Reactor +TP_Reactor +Task_ThreadPool +Task_ThreadPool +ThreadPool +ThreadPool diff --git a/ACE/examples/APG/ThreadPools/Futures.cpp b/ACE/examples/APG/ThreadPools/Futures.cpp new file mode 100644 index 00000000000..361a8bb43a2 --- /dev/null +++ b/ACE/examples/APG/ThreadPools/Futures.cpp @@ -0,0 +1,321 @@ +// $Id$ + +#include "ace/config-lite.h" +#if defined (ACE_HAS_THREADS) + +#include "ace/OS_NS_string.h" +#include "ace/OS_NS_time.h" +#include "ace/Task.h" +#include "ace/Unbounded_Queue.h" +#include "ace/Synch.h" +#include "ace/SString.h" +#include "ace/Method_Request.h" +#include "ace/Future.h" +#include "ace/Activation_Queue.h" + +#define OUTSTANDING_REQUESTS 20 + +// Listing 2 code/ch16 +class CompletionCallBack: public ACE_Future_Observer<ACE_CString*> +{ +public: + virtual void update (const ACE_Future<ACE_CString*> & future) + { + ACE_CString *result = 0; + + // Block for the result. + future.get (result); + ACE_DEBUG ((LM_INFO, ACE_TEXT("%C\n"), result->c_str ())); + delete result; + } +}; +// Listing 2 +// Listing 1 code/ch16 +class LongWork : public ACE_Method_Request +{ +public: + virtual int call (void) + { + ACE_TRACE (ACE_TEXT ("LongWork::call")); + ACE_DEBUG + ((LM_INFO, ACE_TEXT ("(%t) Attempting long work task\n"))); + ACE_OS::sleep (1); + + char buf[1024]; + ACE_OS::strcpy (buf, "Completed assigned task\n"); + ACE_CString *msg; + ACE_NEW_RETURN + (msg, ACE_CString (buf, ACE_OS::strlen (buf) + 1), -1); + result_.set (msg); + return 0; + } + + ACE_Future<ACE_CString*> &future (void) + { + ACE_TRACE (ACE_TEXT ("LongWork::future")); + return result_; + } + + void attach (CompletionCallBack *cb) + { + result_.attach (cb); + } + +private: + ACE_Future<ACE_CString*> result_; +}; +// Listing 1 + +class Exit : public ACE_Method_Request +{ +public: + virtual int call (void) + { + ACE_TRACE (ACE_TEXT ("Exit::call")); + return -1; + } +}; + +class Worker; + +class IManager +{ +public: + virtual ~IManager (void) { } + + virtual int return_to_work (Worker *worker) = 0; +}; + +// Listing 3 code/ch16 +class Worker: public ACE_Task<ACE_MT_SYNCH> +{ +public: + Worker (IManager *manager) + : manager_(manager), queue_ (msg_queue ()) + { } + + int perform (ACE_Method_Request *req) + { + ACE_TRACE (ACE_TEXT ("Worker::perform")); + return this->queue_.enqueue (req); + } + + virtual int svc (void) + { + thread_id_ = ACE_Thread::self (); + while (1) + { + ACE_Method_Request *request = this->queue_.dequeue(); + if (request == 0) + return -1; + + // Invoke the request + int result = request->call (); + if (result == -1) + break; + + // Return to work. + this->manager_->return_to_work (this); + } + + return 0; + } + + ACE_thread_t thread_id (void); + +private: + IManager *manager_; + ACE_thread_t thread_id_; + ACE_Activation_Queue queue_; +}; +// Listing 3 + +ACE_thread_t Worker::thread_id (void) +{ + return thread_id_; +} + +// Listing 4 code/ch16 +class Manager : public ACE_Task_Base, private IManager +{ +public: + enum {POOL_SIZE = 5, MAX_TIMEOUT = 5}; + + Manager () + : shutdown_(0), workers_lock_(), workers_cond_(workers_lock_) + { + ACE_TRACE (ACE_TEXT ("Manager::TP")); + } + + int perform (ACE_Method_Request *req) + { + ACE_TRACE (ACE_TEXT ("Manager::perform")); + return this->queue_.enqueue (req); + } + + int svc (void) + { + ACE_TRACE (ACE_TEXT ("Manager::svc")); + + ACE_DEBUG ((LM_INFO, ACE_TEXT ("(%t) Manager started\n"))); + + // Create pool when you get in the first time. + create_worker_pool (); + + while (!done ()) + { + ACE_Time_Value tv ((long)MAX_TIMEOUT); + tv += ACE_OS::time (0); + + // Get the next message + ACE_Method_Request *request = this->queue_.dequeue (&tv); + if (request == 0) + { + shut_down (); + break; + } + + // Choose a worker. + Worker *worker = choose_worker (); + + // Ask the worker to do the job. + worker->perform (request); + } + + return 0; + } + + int shut_down (void); + + virtual int return_to_work (Worker *worker) + { + ACE_GUARD_RETURN + (ACE_Thread_Mutex, worker_mon, this->workers_lock_, -1); + ACE_DEBUG + ((LM_DEBUG, ACE_TEXT ("(%t) Worker returning to work.\n"))); + this->workers_.enqueue_tail (worker); + this->workers_cond_.signal (); + + return 0; + } + +private: + Worker *choose_worker (void) + { + ACE_GUARD_RETURN + (ACE_Thread_Mutex, worker_mon, this->workers_lock_, 0) + + while (this->workers_.is_empty ()) + workers_cond_.wait (); + + Worker *worker = 0; + this->workers_.dequeue_head (worker); + return worker; + } + + int create_worker_pool (void) + { + ACE_GUARD_RETURN + (ACE_Thread_Mutex, worker_mon, this->workers_lock_, -1); + for (int i = 0; i < POOL_SIZE; i++) + { + Worker *worker; + ACE_NEW_RETURN (worker, Worker (this), -1); + this->workers_.enqueue_tail (worker); + worker->activate (); + } + + return 0; + } + + int done (void) + { + return (shutdown_ == 1); + } + + ACE_thread_t thread_id (Worker *worker) + { + return worker->thread_id (); + } + +private: + int shutdown_; + ACE_Thread_Mutex workers_lock_; + ACE_Condition<ACE_Thread_Mutex> workers_cond_; + ACE_Unbounded_Queue<Worker* > workers_; + ACE_Activation_Queue queue_; +}; +// Listing 4 + +int +Manager::shut_down (void) +{ + ACE_TRACE (ACE_TEXT ("Manager::shut_down")); + ACE_Unbounded_Queue<Worker* >::ITERATOR iter = this->workers_.begin (); + Worker **worker_ptr = 0; + do + { + iter.next (worker_ptr); + Worker *worker = (*worker_ptr); + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) Attempting shutdown of %d\n"), + thread_id (worker))); + + Exit *req; + ACE_NEW_RETURN (req, Exit(), -1); + + // Send the hangup message + worker->perform (req); + + // Wait for the exit. + worker->wait (); + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%t) Worker %d shut down.\n"), + thread_id (worker))); + + delete req; + delete worker; + + } + while (iter.advance ()); + + shutdown_ = 1; + + return 0; +} + +// Listing 5 code/ch16 +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + Manager tp; + tp.activate (); + + ACE_Time_Value tv; + tv.msec (100); + + // Wait for a few seconds every time you send a message. + CompletionCallBack cb; + LongWork workArray[OUTSTANDING_REQUESTS]; + for (int i = 0; i < OUTSTANDING_REQUESTS; i++) + { + workArray[i].attach (&cb); + ACE_OS::sleep (tv); + tp.perform (&workArray[i]); + } + + ACE_Thread_Manager::instance ()->wait (); + return 0; +} +// Listing 5 + +#else +#include "ace/OS_main.h" +#include "ace/OS_NS_stdio.h" + +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_OS::puts (ACE_TEXT ("This example requires threads.")); + return 0; +} + +#endif /* ACE_HAS_THREADS */ diff --git a/ACE/examples/APG/ThreadPools/LF_ThreadPool.cpp b/ACE/examples/APG/ThreadPools/LF_ThreadPool.cpp new file mode 100644 index 00000000000..820e74c36e8 --- /dev/null +++ b/ACE/examples/APG/ThreadPools/LF_ThreadPool.cpp @@ -0,0 +1,252 @@ +// $Id$ + +#include "ace/config-lite.h" +#if defined (ACE_HAS_THREADS) + +#include "ace/OS_NS_string.h" +#include "ace/OS_NS_sys_time.h" +#include "ace/Task.h" +#include "ace/Containers.h" +#include "ace/Synch.h" + +// Listing 4 code/ch16 +class Follower +{ +public: + Follower (ACE_Thread_Mutex &leader_lock) + : cond_(leader_lock) + { + owner_ = ACE_Thread::self (); + } + + int wait (void) + { + return this->cond_.wait (); + } + + int signal (void) + { + return this->cond_.signal (); + } + + ACE_thread_t owner (void) + { + return this->owner_; + } + +private: + ACE_Condition<ACE_Thread_Mutex> cond_; + ACE_thread_t owner_; +}; +// Listing 4 +// Listing 1 code/ch16 +class LF_ThreadPool : public ACE_Task<ACE_MT_SYNCH> +{ +public: + LF_ThreadPool () : shutdown_(0), current_leader_(0) + { + ACE_TRACE (ACE_TEXT ("LF_ThreadPool::TP")); + } + + virtual int svc (void); + + void shut_down (void) + { + shutdown_ = 1; + } + +private: + int become_leader (void); + + Follower *make_follower (void); + + int elect_new_leader (void); + + int leader_active (void) + { + ACE_TRACE (ACE_TEXT ("LF_ThreadPool::leader_active")); + return this->current_leader_ != 0; + } + + void leader_active (ACE_thread_t leader) + { + ACE_TRACE (ACE_TEXT ("LF_ThreadPool::leader_active")); + this->current_leader_ = leader; + } + + void process_message (ACE_Message_Block *mb); + + int done (void) + { + return (shutdown_ == 1); + } + +private: + int shutdown_; + ACE_thread_t current_leader_; + ACE_Thread_Mutex leader_lock_; + ACE_Unbounded_Queue<Follower*> followers_; + ACE_Thread_Mutex followers_lock_; + static long LONG_TIME; +}; +// Listing 1 +// Listing 2 code/ch16 +int +LF_ThreadPool::svc (void) +{ + ACE_TRACE (ACE_TEXT ("LF_ThreadPool::svc")); + while (!done ()) + { + become_leader (); // Block until this thread is the leader. + + ACE_Message_Block *mb = 0; + ACE_Time_Value tv (LONG_TIME); + tv += ACE_OS::gettimeofday (); + + // Get a message, elect new leader, then process message. + if (this->getq (mb, &tv) < 0) + { + if (elect_new_leader () == 0) + break; + continue; + } + + elect_new_leader (); + process_message (mb); + } + + return 0; +} +// Listing 2 +// Listing 3 code/ch16 +int +LF_ThreadPool::become_leader (void) +{ + ACE_TRACE (ACE_TEXT ("LF_ThreadPool::become_leader")); + + ACE_GUARD_RETURN + (ACE_Thread_Mutex, leader_mon, this->leader_lock_, -1); + if (leader_active ()) + { + Follower *fw = make_follower (); + { + // Wait until told to do so. + while (leader_active ()) + fw->wait (); + } + + delete fw; + } + + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) Becoming the leader\n"))); + + // Mark yourself as the active leader. + leader_active (ACE_Thread::self ()); + return 0; +} + +Follower* +LF_ThreadPool::make_follower (void) +{ + ACE_TRACE (ACE_TEXT ("LF_ThreadPool::make_follower")); + + ACE_GUARD_RETURN + (ACE_Thread_Mutex, follower_mon, this->followers_lock_, 0); + Follower *fw; + ACE_NEW_RETURN (fw, Follower (this->leader_lock_), 0); + this->followers_.enqueue_tail (fw); + return fw; +} +// Listing 3 +// Listing 5 code/ch16 +int +LF_ThreadPool::elect_new_leader (void) +{ + ACE_TRACE (ACE_TEXT ("LF_ThreadPool::elect_new_leader")); + + ACE_GUARD_RETURN + (ACE_Thread_Mutex, leader_mon, this->leader_lock_, -1); + leader_active (0); + + // Wake up a follower + if (!followers_.is_empty ()) + { + ACE_GUARD_RETURN (ACE_Thread_Mutex, + follower_mon, + this->followers_lock_, + -1); + // Get the old follower. + Follower *fw; + if (this->followers_.dequeue_head (fw) != 0) + return -1; + ACE_DEBUG ((LM_ERROR, + ACE_TEXT ("(%t) Resigning and Electing %d\n"), + fw->owner ())); + return (fw->signal () == 0) ? 0 : -1; + } + else + { + ACE_DEBUG + ((LM_ERROR, ACE_TEXT ("(%t) Oops no followers left\n"))); + return -1; + } +} +// Listing 5 + +void +LF_ThreadPool::process_message (ACE_Message_Block *mb) +{ + ACE_TRACE (ACE_TEXT ("LF_ThreadPool::process_message")); + int msgId; + ACE_OS::memcpy (&msgId, mb->rd_ptr (), sizeof(int)); + mb->release (); + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%t) Started processing message:%d\n"), + msgId)); + ACE_OS::sleep (1); + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%t) Finished processing message:%d\n"), + msgId)); +} + +long LF_ThreadPool::LONG_TIME = 5L; + +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + LF_ThreadPool tp; + tp.activate (THR_NEW_LWP| THR_JOINABLE, 5); + + // Wait for a few seconds... + ACE_OS::sleep (2); + ACE_Time_Value tv (1L); + + ACE_Message_Block *mb; + for (int i = 0; i < 30; i++) + { + ACE_NEW_RETURN (mb, ACE_Message_Block (sizeof(int)), -1); + ACE_OS::memcpy (mb->wr_ptr (), &i, sizeof(int)); + ACE_OS::sleep (tv); + + // Add a new work item. + tp.putq (mb); + } + + ACE_Thread_Manager::instance ()->wait (); + + ACE_OS::sleep (10); + + return 0; +} + +#else +#include "ace/OS_main.h" +#include "ace/OS_NS_stdio.h" + +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_OS::puts (ACE_TEXT ("This example requires threads.")); + return 0; +} + +#endif /* ACE_HAS_THREADS */ diff --git a/ACE/examples/APG/ThreadPools/Makefile.am b/ACE/examples/APG/ThreadPools/Makefile.am new file mode 100644 index 00000000000..f1167e857c5 --- /dev/null +++ b/ACE/examples/APG/ThreadPools/Makefile.am @@ -0,0 +1,96 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +ACE_BUILDDIR = $(top_builddir) +ACE_ROOT = $(top_srcdir) + +noinst_PROGRAMS = + +## Makefile.Futures.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS += Futures + +Futures_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +Futures_SOURCES = \ + Futures.cpp \ + Request_Handler.h + +Futures_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Makefile.LF_ThreadPool.am +noinst_PROGRAMS += LF_ThreadPool + +LF_ThreadPool_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +LF_ThreadPool_SOURCES = \ + LF_ThreadPool.cpp \ + Request_Handler.h + +LF_ThreadPool_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.TP_Reactor.am +noinst_PROGRAMS += TP_Reactor + +TP_Reactor_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +TP_Reactor_SOURCES = \ + TP_Reactor.cpp \ + Request_Handler.h + +TP_Reactor_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Task_ThreadPool.am +noinst_PROGRAMS += Task_ThreadPool + +Task_ThreadPool_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +Task_ThreadPool_SOURCES = \ + Task_ThreadPool.cpp \ + Request_Handler.h + +Task_ThreadPool_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.ThreadPool.am +noinst_PROGRAMS += ThreadPool + +ThreadPool_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +ThreadPool_SOURCES = \ + ThreadPool.cpp \ + Request_Handler.h + +ThreadPool_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Clean up template repositories, etc. +clean-local: + -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.* + -rm -f gcctemp.c gcctemp so_locations *.ics + -rm -rf cxx_repository ptrepository ti_files + -rm -rf templateregistry ir.out + -rm -rf ptrepository SunWS_cache Templates.DB diff --git a/ACE/examples/APG/ThreadPools/Request_Handler.h b/ACE/examples/APG/ThreadPools/Request_Handler.h new file mode 100644 index 00000000000..9965fb7a30e --- /dev/null +++ b/ACE/examples/APG/ThreadPools/Request_Handler.h @@ -0,0 +1,34 @@ +/** + * $Id$ + * + * Sample code from The ACE Programmer's Guide, + * copyright 2003 Addison-Wesley. All Rights Reserved. + */ + +#ifndef __REQUEST_HANDLER_H_ +#define __REQUEST_HANDLER_H_ + +#include "ace/Svc_Handler.h" +#include "ace/SOCK_Stream.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL +class ACE_Thread_Manager; +ACE_END_VERSIONED_NAMESPACE_DECL + +class Request_Handler : public ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_MT_SYNCH> + { + // = TITLE + // This class is the Svc_Handler used by <Acceptor>. + public: + Request_Handler (ACE_Thread_Manager *tm = 0); + // The default constructor makes sure the right reactor is used. + + protected: + virtual int handle_input (ACE_HANDLE fd = ACE_INVALID_HANDLE); + virtual int handle_close (ACE_HANDLE fd, ACE_Reactor_Mask = 0); + + private: + size_t nr_msgs_rcvd_; + }; + +#endif /* __REQUEST_HANDLER_H_ */ diff --git a/ACE/examples/APG/ThreadPools/TP_Reactor.cpp b/ACE/examples/APG/ThreadPools/TP_Reactor.cpp new file mode 100644 index 00000000000..9c82907a8e6 --- /dev/null +++ b/ACE/examples/APG/ThreadPools/TP_Reactor.cpp @@ -0,0 +1,269 @@ +// == == == == == == == == == == == == == == == == == == == == == == == +// $Id$ +// Stolen from $ACE_ROOT/tests/Thread_Pool_Reactor_Test.cpp +// Thread_Pool_Reactor_Test.cpp, v 1.29 2001/03/20 01:07:21 irfan Exp +// = AUTHOR +// Irfan Pyarali <irfan@cs.wustl.edu> and +// Nanbor Wang <nanbor@cs.wustl.edu> +// == == == == == == == == == == == == == == == == == == == == == == == + +#include "ace/config-lite.h" +#if defined (ACE_HAS_THREADS) + +#include "ace/OS_NS_string.h" +#include "ace/OS_NS_unistd.h" +#include "ace/SOCK_Connector.h" +#include "ace/SOCK_Acceptor.h" +#include "ace/Acceptor.h" +#include "ace/Thread_Manager.h" +#include "ace/TP_Reactor.h" + +#include "Request_Handler.h" + +// Accepting end point. This is actually "localhost:10010", but some +// platform couldn't resolve the name so we use the IP address +// directly here. +static const ACE_TCHAR *rendezvous = ACE_TEXT ("127.0.0.1:10010"); + +// Total number of server threads. +static size_t svr_thrno = 5; + +// Total number of client threads. +static size_t cli_runs = 2; + +// Total connection attemps of a client thread. +static size_t cli_conn_no = 2; + +// Total requests a client thread sends. +static size_t cli_req_no = 5; + +// Delay before a thread sending the next request (in msec.) +static int req_delay = 50; + + +typedef ACE_Strategy_Acceptor <Request_Handler, ACE_SOCK_ACCEPTOR> ACCEPTOR; + + +Request_Handler::Request_Handler (ACE_Thread_Manager *thr_mgr) + : ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_MT_SYNCH> (thr_mgr), + nr_msgs_rcvd_(0) +{ + this->reactor (ACE_Reactor::instance ()); +} + +int +Request_Handler::handle_input (ACE_HANDLE fd) +{ + ACE_TCHAR buffer[BUFSIZ]; + ACE_TCHAR len = 0; + ssize_t result = this->peer ().recv (&len, sizeof (ACE_TCHAR)); + + if (result > 0 + && this->peer ().recv_n (buffer, len * sizeof (ACE_TCHAR)) + == static_cast<ssize_t> (len * sizeof (ACE_TCHAR))) + { + ++this->nr_msgs_rcvd_; + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%t) svr input; fd: 0x%x; input: %s\n"), + fd, + buffer)); + if (ACE_OS::strcmp (buffer, ACE_TEXT ("shutdown")) == 0) + ACE_Reactor::instance()->end_reactor_event_loop (); + return 0; + } + else + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%t) Request_Handler: 0x%x peer closed (0x%x)\n"), + this, fd)); + return -1; +} + +int +Request_Handler::handle_close (ACE_HANDLE fd, ACE_Reactor_Mask) +{ + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%t) svr close; fd: 0x%x, rcvd %d msgs\n"), + fd, + this->nr_msgs_rcvd_)); + + if (this->nr_msgs_rcvd_ != cli_req_no) + ACE_ERROR((LM_ERROR, + ACE_TEXT ("(%t) Handler 0x%x: Expected %d messages; got %d\n"), + this, + cli_req_no, + this->nr_msgs_rcvd_)); + + this->destroy (); + return 0; +} + +// Listing 2 code/ch16 +static int +reactor_event_hook (ACE_Reactor *) +{ + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%t) handling events ....\n"))); + + return 0; +} + +class ServerTP : public ACE_Task_Base +{ +public: + virtual int svc (void) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%t) Running the event loop\n"))); + + int result = + ACE_Reactor::instance ()->run_reactor_event_loop + (&reactor_event_hook); + + if (result == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("(%t) %p\n"), + ACE_TEXT ("Error handling events")), + 0); + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%t) Done handling events.\n"))); + + return 0; + } +}; +// Listing 2 + +class Client: public ACE_Task_Base + { + public: + Client() + :addr_(rendezvous) + {} + + virtual int svc() + { + ACE_OS::sleep (3); + const ACE_TCHAR *msg = + ACE_TEXT ("Message from Connection worker"); + + ACE_TCHAR buf [BUFSIZ]; + buf[0] = ACE_OS::strlen (msg) + 1; + ACE_OS::strcpy (&buf[1], msg); + + for (size_t i = 0; i < cli_runs; i++) + send_work_to_server(buf); + + shut_down(); + + return 0; + } + + private: + void send_work_to_server(ACE_TCHAR* arg) + { + ACE_SOCK_Stream stream; + ACE_SOCK_Connector connect; + ACE_Time_Value delay (0, req_delay); + size_t len = * reinterpret_cast<ACE_TCHAR *> (arg); + + for (size_t i = 0 ; i < cli_conn_no; i++) + { + if (connect.connect (stream, addr_) < 0) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("(%t) %p\n"), + ACE_TEXT ("connect"))); + continue; + } + + for (size_t j = 0; j < cli_req_no; j++) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("Sending work to server on handle 0x%x, req %d\n"), + stream.get_handle (), + j+1)); + if (stream.send_n (arg, + (len + 1) * sizeof (ACE_TCHAR)) == -1) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("(%t) %p\n"), + ACE_TEXT ("send_n"))); + continue; + } + ACE_OS::sleep (delay); + } + + stream.close (); + } + + } + + void shut_down() + { + ACE_SOCK_Stream stream; + ACE_SOCK_Connector connect; + + if (connect.connect (stream, addr_) == -1) + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("(%t) %p Error while connecting\n"), + ACE_TEXT ("connect"))); + + const ACE_TCHAR *sbuf = ACE_TEXT ("\011shutdown"); + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("shutdown stream handle = %x\n"), + stream.get_handle ())); + + if (stream.send_n (sbuf, (ACE_OS::strlen (sbuf) + 1) * sizeof (ACE_TCHAR)) == -1) + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("(%t) %p\n"), + ACE_TEXT ("send_n"))); + + stream.close (); + } + private: + ACE_INET_Addr addr_; + }; +// Listing 1 code/ch16 +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_TP_Reactor sr; + ACE_Reactor new_reactor (&sr); + ACE_Reactor::instance (&new_reactor); + + ACCEPTOR acceptor; + ACE_INET_Addr accept_addr (rendezvous); + + if (acceptor.open (accept_addr) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("open")), + 1); + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%t) Spawning %d server threads...\n"), + svr_thrno)); + + ServerTP serverTP; + serverTP.activate (THR_NEW_LWP | THR_JOINABLE, svr_thrno); + + Client client; + client.activate (); + + ACE_Thread_Manager::instance ()->wait (); + + return 0; +} +// Listing 1 +#else +#include "ace/OS_main.h" +#include "ace/OS_NS_stdio.h" + +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_OS::puts (ACE_TEXT ("This example requires threads.")); + return 0; +} + +#endif /* ACE_HAS_THREADS */ diff --git a/ACE/examples/APG/ThreadPools/Task_ThreadPool.cpp b/ACE/examples/APG/ThreadPools/Task_ThreadPool.cpp new file mode 100644 index 00000000000..53ebe76b0bc --- /dev/null +++ b/ACE/examples/APG/ThreadPools/Task_ThreadPool.cpp @@ -0,0 +1,149 @@ +// $Id$ + +#include "ace/config-lite.h" +#if defined (ACE_HAS_THREADS) + +#include "ace/OS_NS_string.h" +#include "ace/OS_NS_time.h" +#include "ace/Task.h" +#include "ace/Synch.h" +#include "ace/SString.h" + +// Listing 2 code/ch16 +class Workers : public ACE_Task<ACE_MT_SYNCH> +{ +public: + Workers () + { } + + virtual int svc (void) + { + while (1) + { + ACE_Message_Block *mb = 0; + if (this->getq (mb) == -1) + { + ACE_DEBUG ((LM_INFO, + ACE_TEXT ("(%t) Shutting down\n"))); + break; + } + + // Process the message. + process_message (mb); + } + + return 0; + } + // Listing 2 + +private: + void process_message (ACE_Message_Block *mb) + { + ACE_TRACE (ACE_TEXT ("Workers::process_message")); + int msgId; + ACE_OS::memcpy (&msgId, mb->rd_ptr (), sizeof(int)); + mb->release (); + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%t) Started processing message %d\n"), + msgId)); + ACE_OS::sleep (3); + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%t) Finished processing message %d\n"), + msgId)); + } +}; + +// Listing 1 code/ch16 +class Manager : public ACE_Task<ACE_MT_SYNCH> +{ +public: + enum {POOL_SIZE = 5, MAX_TIMEOUT = 5}; + + Manager () : shutdown_(0) + { + ACE_TRACE (ACE_TEXT ("Manager::Manager")); + } + + int svc (void) + { + ACE_TRACE (ACE_TEXT ("Manager::svc")); + + ACE_DEBUG ((LM_INFO, ACE_TEXT ("(%t) Manager started\n"))); + + // Create pool. + Workers pool; + pool.activate (THR_NEW_LWP | THR_JOINABLE, POOL_SIZE); + + while (!done ()) + { + ACE_Message_Block *mb = 0; + ACE_Time_Value tv ((long)MAX_TIMEOUT); + tv += ACE_OS::time (0); + + // Get a message request. + if (this->getq (mb, &tv) < 0) + { + pool.msg_queue ()->deactivate (); + pool.wait (); + break; + } + + // Ask the worker pool to do the job. + pool.putq (mb); + } + + return 0; + } + +private: + int done (void); + + int shutdown_; +}; +// Listing 1 + +int Manager::done (void) +{ + return (shutdown_ == 1); +} + + +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + Manager tp; + tp.activate (); + + // Wait for a moment every time you send a message. + ACE_Time_Value tv; + tv.msec (100); + + ACE_Message_Block *mb; + for (int i = 0; i < 30; i++) + { + ACE_NEW_RETURN + (mb, ACE_Message_Block(sizeof(int)), -1); + + ACE_OS::memcpy (mb->wr_ptr (), &i, sizeof(int)); + + ACE_OS::sleep (tv); + + // Add a new work item. + tp.putq (mb); + } + + ACE_Thread_Manager::instance ()->wait (); + return 0; +} + +#else +#include "ace/OS_main.h" +#include "ace/OS_NS_stdio.h" + +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_OS::puts (ACE_TEXT ("This example requires threads.")); + return 0; +} + +#endif /* ACE_HAS_THREADS */ diff --git a/ACE/examples/APG/ThreadPools/ThreadPool.cpp b/ACE/examples/APG/ThreadPools/ThreadPool.cpp new file mode 100644 index 00000000000..684762efcbf --- /dev/null +++ b/ACE/examples/APG/ThreadPools/ThreadPool.cpp @@ -0,0 +1,271 @@ +// $Id$ + +#include "ace/config-lite.h" +#if defined (ACE_HAS_THREADS) + +#include "ace/OS_NS_string.h" +#include "ace/OS_NS_time.h" +#include "ace/Task.h" +#include "ace/Containers.h" +#include "ace/Synch.h" +#include "ace/SString.h" +#include "ace/Method_Request.h" +#include "ace/Future.h" +#include "ace/Activation_Queue.h" + +class Worker; + +class IManager +{ +public: + virtual ~IManager (void) { } + + virtual int return_to_work (Worker *worker) = 0; +}; + +// Listing 2 code/ch16 +class Worker : public ACE_Task<ACE_MT_SYNCH> +{ +public: + Worker (IManager *manager) : manager_(manager) { } + + virtual int svc (void) + { + thread_id_ = ACE_Thread::self (); + while (1) + { + ACE_Message_Block *mb = 0; + if (this->getq (mb) == -1) + ACE_ERROR_BREAK + ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("getq"))); + if (mb->msg_type () == ACE_Message_Block::MB_HANGUP) + { + ACE_DEBUG ((LM_INFO, + ACE_TEXT ("(%t) Shutting down\n"))); + mb->release (); + break; + } + // Process the message. + process_message (mb); + // Return to work. + this->manager_->return_to_work (this); + } + + return 0; + } + // Listing 2 + + ACE_thread_t thread_id (void) + { + return thread_id_; + } + +private: + void process_message (ACE_Message_Block *mb) + { + ACE_TRACE (ACE_TEXT ("Worker::process_message")); + int msgId; + ACE_OS::memcpy (&msgId, mb->rd_ptr (), sizeof(int)); + mb->release (); + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%t) Started processing message %d\n"), + msgId)); + ACE_OS::sleep (3); + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%t) Finished processing message %d\n"), + msgId)); + } + + IManager *manager_; + ACE_thread_t thread_id_; +}; + +// Listing 1 code/ch16 +class Manager: public ACE_Task<ACE_MT_SYNCH>, private IManager +{ +public: + enum {POOL_SIZE = 5, MAX_TIMEOUT = 5}; + + Manager () + : shutdown_(0), workers_lock_(), workers_cond_(workers_lock_) + { + ACE_TRACE (ACE_TEXT ("Manager::Manager")); + } + + int svc (void) + { + ACE_TRACE (ACE_TEXT ("Manager::svc")); + + ACE_DEBUG ((LM_INFO, ACE_TEXT ("(%t) Manager started\n"))); + + // Create pool. + create_worker_pool (); + + while (!done ()) + { + ACE_Message_Block *mb = 0; + ACE_Time_Value tv ((long)MAX_TIMEOUT); + tv += ACE_OS::time (0); + + // Get a message request. + if (this->getq (mb, &tv) < 0) + { + shut_down (); + break; + } + + // Choose a worker. + Worker *worker = 0; + { + ACE_GUARD_RETURN (ACE_Thread_Mutex, + worker_mon, this->workers_lock_, -1); + + while (this->workers_.is_empty ()) + workers_cond_.wait (); + + this->workers_.dequeue_head (worker); + } + + // Ask the worker to do the job. + worker->putq (mb); + } + + return 0; + } + + int shut_down (void); + + ACE_thread_t thread_id (Worker *worker); + + virtual int return_to_work (Worker *worker) + { + ACE_GUARD_RETURN (ACE_Thread_Mutex, + worker_mon, this->workers_lock_, -1); + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%t) Worker %d returning to work.\n"), + worker->thr_mgr ()->thr_self ())); + this->workers_.enqueue_tail (worker); + this->workers_cond_.signal (); + + return 0; + } + +private: + int create_worker_pool (void) + { + ACE_GUARD_RETURN (ACE_Thread_Mutex, + worker_mon, + this->workers_lock_, + -1); + for (int i = 0; i < POOL_SIZE; i++) + { + Worker *worker; + ACE_NEW_RETURN (worker, Worker (this), -1); + this->workers_.enqueue_tail (worker); + worker->activate (); + } + + return 0; + } + + int done (void); + +private: + int shutdown_; + ACE_Thread_Mutex workers_lock_; + ACE_Condition<ACE_Thread_Mutex> workers_cond_; + ACE_Unbounded_Queue<Worker* > workers_; +}; +// Listing 1 + +int Manager::done (void) +{ + return (shutdown_ == 1); +} + +int +Manager::shut_down (void) +{ + ACE_TRACE (ACE_TEXT ("Manager::shut_down")); + ACE_Unbounded_Queue<Worker* >::ITERATOR iter = + this->workers_.begin (); + Worker **worker_ptr = 0; + do + { + iter.next (worker_ptr); + Worker *worker = (*worker_ptr); + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%t) Attempting shutdown of %d\n"), + thread_id (worker))); + + // Send the hangup message. + ACE_Message_Block *mb; + ACE_NEW_RETURN + (mb, + ACE_Message_Block(0, + ACE_Message_Block::MB_HANGUP), + -1); + worker->putq (mb); + + // Wait for the exit. + worker->wait (); + + ACE_ASSERT (worker->msg_queue ()->is_empty ()); + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%t) Worker %d shut down.\n)"), + thread_id (worker))); + delete worker; + } + while (iter.advance ()); + + shutdown_ = 1; + + return 0; +} + +ACE_thread_t +Manager::thread_id (Worker *worker) +{ + return worker->thread_id (); +} + + +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + Manager tp; + tp.activate (); + + // Wait for a moment every time you send a message. + ACE_Time_Value tv; + tv.msec (100); + + ACE_Message_Block *mb; + for (int i = 0; i < 30; i++) + { + ACE_NEW_RETURN + (mb, ACE_Message_Block(sizeof(int)), -1); + + ACE_OS::memcpy (mb->wr_ptr (), &i, sizeof(int)); + + ACE_OS::sleep (tv); + + // Add a new work item. + tp.putq (mb); + } + + ACE_Thread_Manager::instance ()->wait (); + return 0; +} + +#else +#include "ace/OS_main.h" +#include "ace/OS_NS_stdio.h" + +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_OS::puts (ACE_TEXT ("This example requires threads.")); + return 0; +} + +#endif /* ACE_HAS_THREADS */ diff --git a/ACE/examples/APG/ThreadPools/threadpools.mpc b/ACE/examples/APG/ThreadPools/threadpools.mpc new file mode 100644 index 00000000000..1bb9a860920 --- /dev/null +++ b/ACE/examples/APG/ThreadPools/threadpools.mpc @@ -0,0 +1,38 @@ +// -*- MPC -*- +// $Id$ + +project(Futures) : aceexe { + avoids += ace_for_tao + exename = Futures + Source_Files { + Futures.cpp + } +} + +project(LF ThreadPool) : aceexe { + exename = LF_ThreadPool + Source_Files { + LF_ThreadPool.cpp + } +} + +project(Task ThreadPool) : aceexe { + exename = Task_ThreadPool + Source_Files { + Task_ThreadPool.cpp + } +} + +project(ThreadPool) : aceexe { + exename = ThreadPool + Source_Files { + ThreadPool.cpp + } +} + +project(TP Reactor) : aceexe { + exename = TP_Reactor + Source_Files { + TP_Reactor.cpp + } +} diff --git a/ACE/examples/APG/ThreadSafety/.cvsignore b/ACE/examples/APG/ThreadSafety/.cvsignore new file mode 100644 index 00000000000..7fe1b99d03f --- /dev/null +++ b/ACE/examples/APG/ThreadSafety/.cvsignore @@ -0,0 +1,16 @@ +Atomic_Op +Atomic_Op +Barrier +Barrier +Mutex +Mutex +RW_Lock +RW_Lock +Semaphore +Semaphore +TSS +TSS +Tokens +Tokens +Tokens_Deadlock +Tokens_Deadlock diff --git a/ACE/examples/APG/ThreadSafety/Atomic_Op.cpp b/ACE/examples/APG/ThreadSafety/Atomic_Op.cpp new file mode 100644 index 00000000000..d315d433a66 --- /dev/null +++ b/ACE/examples/APG/ThreadSafety/Atomic_Op.cpp @@ -0,0 +1,127 @@ +// $Id$ + +#include "ace/Synch.h" +#include "ace/Task.h" +#include "ace/Log_Msg.h" +#include "ace/Atomic_Op.h" + +#if defined(RUNNING_ON_UNSAFE_MULTIPROCESSOR) +// Listing 1 code/ch14 +typedef ACE_Atomic_Op<ACE_Thread_Mutex, unsigned int> SafeUInt; +// Listing 1 +// Listing 2 code/ch14 +typedef ACE_Atomic_Op<ACE_Thread_Mutex, int> SafeInt; +// Listing 2 +#else +typedef ACE_Atomic_Op<ACE_Null_Mutex, unsigned int> SafeUInt; +typedef ACE_Atomic_Op<ACE_Null_Mutex, int> SafeInt; +#endif /* RUNNING_ON_UNSAFE_MULTIPROCESSOR) */ + +static const unsigned int Q_SIZE = 2; +static const int MAX_PROD = 10; + +// Listing 3 code/ch14 +class Producer : public ACE_Task_Base +{ +public: + Producer (int *buf, SafeUInt &in, SafeUInt &out) + : buf_(buf), in_(in), out_(out) + { } + + int svc (void) + { + SafeInt itemNo = 0; + while (1) + { + // Busy wait. + do + { } + while (in_.value () - out_.value () == Q_SIZE); + + itemNo++; + buf_[in_.value () % Q_SIZE] = itemNo.value (); + in_++; + + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Produced %d \n"), + itemNo.value ())); + + if (check_termination (itemNo.value ())) + break; + } + + return 0; + } + + int check_termination (int item) + { + return (item == MAX_PROD); + } + +private: + int * buf_; + SafeUInt& in_; + SafeUInt& out_; +}; + +class Consumer : public ACE_Task_Base +{ +public: + Consumer (int *buf, SafeUInt &in, SafeUInt& out) + : buf_(buf), in_(in), out_(out) + { } + + int svc (void) + { + while (1) + { + int item; + + // Busy wait. + do + { } + while (in_.value () - out_.value () == 0); + + item = buf_[out_.value () % Q_SIZE]; + out_++; + + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Consumed %d\n"), + item)); + + if (check_termination (item)) + break; + } + + return 0; + } + + int check_termination (int item) + { + return (item == MAX_PROD); + } + +private: + int * buf_; + SafeUInt& in_; + SafeUInt& out_; +}; +// Listing 3 + +// Listing 4 code/ch14 +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + int shared_buf[Q_SIZE]; + SafeUInt in = 0; + SafeUInt out = 0; + + Producer producer (shared_buf, in, out); + Consumer consumer (shared_buf, in, out); + + producer.activate(); + consumer.activate(); + producer.wait(); + consumer.wait(); + + return 0; +} +// Listing 4 + diff --git a/ACE/examples/APG/ThreadSafety/Barrier.cpp b/ACE/examples/APG/ThreadSafety/Barrier.cpp new file mode 100644 index 00000000000..b07a08f0cee --- /dev/null +++ b/ACE/examples/APG/ThreadSafety/Barrier.cpp @@ -0,0 +1,91 @@ +// $Id$ + +#include "ace/config-lite.h" +#if defined (ACE_HAS_THREADS) + +#include "ace/OS_NS_stdlib.h" +#include "ace/OS_NS_time.h" +#include "ace/Task.h" +#include "ace/Synch.h" + +// Listing 2 code/ch14 +class HA_CommandHandler : public ACE_Task<ACE_MT_SYNCH> +{ +public: + enum { N_THREADS = 5 }; + + HA_CommandHandler (ACE_Barrier& startup_barrier, + ACE_Barrier &shutdown_barrier) + : startup_barrier_(startup_barrier), + shutdown_barrier_(shutdown_barrier) + { } + + void initialize_handler (void); + int handle_command_requests (void); + + int svc (void) + { + initialize_handler (); + startup_barrier_.wait (); + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t: %D) Started\n"))); + + while (handle_command_requests () > 0) + ; + + shutdown_barrier_.wait (); + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t: %D) Ended\n"))); + + return 0; + } + +private: + ACE_Barrier& startup_barrier_; + ACE_Barrier& shutdown_barrier_; +}; +// Listing 2 + +void +HA_CommandHandler::initialize_handler (void) +{ + ACE_Time_Value tv (0, ACE_OS::rand () * 100); + timespec_t t = (timespec_t)tv; + ACE_OS::nanosleep (&t); +} + +int +HA_CommandHandler::handle_command_requests (void) +{ + ACE_Time_Value tv (0, ACE_OS::rand () * 100); + timespec_t t = (timespec_t)tv; + + // Simulate work. + ACE_OS::nanosleep (&t); + + return -1; +} + +// Listing 1 code/ch14 +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_Barrier startup_barrier (HA_CommandHandler::N_THREADS); + ACE_Barrier shutdown_barrier (HA_CommandHandler::N_THREADS); + + HA_CommandHandler handler (startup_barrier, shutdown_barrier); + handler.activate (THR_NEW_LWP | THR_JOINABLE, + HA_CommandHandler::N_THREADS); + handler.wait (); + return 0; +} +// Listing 1 + +#else +#include "ace/OS_main.h" +#include "ace/OS_NS_stdio.h" + +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_OS::puts (ACE_TEXT ("This example requires threads.")); + return 0; +} + +#endif /* ACE_HAS_THREADS */ diff --git a/ACE/examples/APG/ThreadSafety/ClientContext.h b/ACE/examples/APG/ThreadSafety/ClientContext.h new file mode 100644 index 00000000000..bcd58fc4599 --- /dev/null +++ b/ACE/examples/APG/ThreadSafety/ClientContext.h @@ -0,0 +1,30 @@ +/** + * $Id$ + * + * Sample code from The ACE Programmer's Guide, + * copyright 2003 Addison-Wesley. All Rights Reserved. + */ + +#ifndef __CLIENTCONTEXT_H_ +#define __CLIENTCONTEXT_H_ + +#include "ace/Hash_Map_Manager.h" +#include "ace/Synch.h" + +typedef ACE_Hash_Map_Manager<const char *, void *, ACE_Null_Mutex> +Map; + +// Listing 1 code/ch14 +// Client-specific context information. +class ClientContext +{ +public: + void *get_attribute (const char *name); + void set_attribute (const char *name, void *value); + +private: + Map attributeMap_; +}; +// Listing 1 + +#endif /* __CLIENTCONTEXT_H_ */ diff --git a/ACE/examples/APG/ThreadSafety/Makefile.am b/ACE/examples/APG/ThreadSafety/Makefile.am new file mode 100644 index 00000000000..e7c52980171 --- /dev/null +++ b/ACE/examples/APG/ThreadSafety/Makefile.am @@ -0,0 +1,141 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +ACE_BUILDDIR = $(top_builddir) +ACE_ROOT = $(top_srcdir) + + +## Makefile.Atomic_Op.am +noinst_PROGRAMS = Atomic_Op + +Atomic_Op_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +Atomic_Op_SOURCES = \ + Atomic_Op.cpp \ + ClientContext.h + +Atomic_Op_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Barrier.am +noinst_PROGRAMS += Barrier + +Barrier_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +Barrier_SOURCES = \ + Barrier.cpp \ + ClientContext.h + +Barrier_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Mutex.am +noinst_PROGRAMS += Mutex + +Mutex_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +Mutex_SOURCES = \ + Mutex.cpp \ + ClientContext.h + +Mutex_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.RW_Lock.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS += RW_Lock + +RW_Lock_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +RW_Lock_SOURCES = \ + RW_Lock.cpp \ + ClientContext.h + +RW_Lock_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Makefile.Semaphore.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS += Semaphore + +Semaphore_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +Semaphore_SOURCES = \ + Semaphore.cpp \ + ClientContext.h + +Semaphore_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Makefile.TSS.am +noinst_PROGRAMS += TSS + +TSS_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +TSS_SOURCES = \ + TSS.cpp \ + ClientContext.h + +TSS_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Tokens.am +noinst_PROGRAMS += Tokens + +Tokens_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +Tokens_SOURCES = \ + Tokens.cpp \ + ClientContext.h + +Tokens_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Tokens_Deadlock.am +noinst_PROGRAMS += Tokens_Deadlock + +Tokens_Deadlock_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +Tokens_Deadlock_SOURCES = \ + Tokens_Deadlock.cpp \ + ClientContext.h + +Tokens_Deadlock_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Clean up template repositories, etc. +clean-local: + -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.* + -rm -f gcctemp.c gcctemp so_locations *.ics + -rm -rf cxx_repository ptrepository ti_files + -rm -rf templateregistry ir.out + -rm -rf ptrepository SunWS_cache Templates.DB diff --git a/ACE/examples/APG/ThreadSafety/Mutex.cpp b/ACE/examples/APG/ThreadSafety/Mutex.cpp new file mode 100644 index 00000000000..aa21665222c --- /dev/null +++ b/ACE/examples/APG/ThreadSafety/Mutex.cpp @@ -0,0 +1,73 @@ +// $Id$ + +#include "ace/config-lite.h" +#if defined (ACE_HAS_THREADS) + +#include "ace/Synch.h" + +class LogMessage +{ +public: + enum { CRITICAL, NORMAL}; + + virtual ~LogMessage () + { + } + + virtual int priority (void) + { + return NORMAL; + } +}; + +class CriticalLogMessage : public LogMessage +{ + virtual int priority (void) + { + return LogMessage::CRITICAL; + } +}; + +// Listing 1 code/ch14 +typedef ACE_Thread_Mutex MUTEX; +class Logger +{ +public: + void log (LogMessage *msg) + { + ACE_GUARD (MUTEX, mon, mutex_); + if (msg->priority () == LogMessage::CRITICAL) + logCritical (msg); + } + + void logCritical (LogMessage *) + { + // Acquires the same mutex as log()! + ACE_GUARD(MUTEX, mon, mutex_); + } + +private: + MUTEX mutex_; +}; + +static Logger logger; + +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + CriticalLogMessage cm; + logger.log(&cm); // Will cause deadlock. + return 0; +} +// Listing 1 + +#else +#include "ace/OS_main.h" +#include "ace/OS_NS_stdio.h" + +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_OS::puts (ACE_TEXT ("This example requires threads.")); + return 0; +} + +#endif /* ACE_HAS_THREADS */ diff --git a/ACE/examples/APG/ThreadSafety/RW_Lock.cpp b/ACE/examples/APG/ThreadSafety/RW_Lock.cpp new file mode 100644 index 00000000000..83f1287bbdb --- /dev/null +++ b/ACE/examples/APG/ThreadSafety/RW_Lock.cpp @@ -0,0 +1,139 @@ +// $Id$ + +#include "ace/config-lite.h" +#if defined (ACE_HAS_THREADS) + +#include "ace/Synch.h" +#include "ace/Containers.h" +#include "ace/Task.h" + +class Device +{ +public: + Device (int id) : id_(id) + { } + + int id_; +}; + +typedef ACE_DLList<Device> DeviceList; +typedef ACE_DLList_Iterator<Device> DeviceListIterator; + +// Listing 1 code/ch14 +class HA_DiscoveryAgent +{ +public: + void add_device (Device *device) + { + ACE_WRITE_GUARD (ACE_RW_Thread_Mutex, mon, rwmutex_); + list_add_item_i (device); + } + + void remove_device (Device *device) + { + ACE_READ_GUARD (ACE_RW_Thread_Mutex, mon, rwmutex_); + list_remove_item_i(device); + } + + int contains_device (Device *device) + { + ACE_READ_GUARD_RETURN + (ACE_RW_Thread_Mutex, mon, rwmutex_, -1); + return list_contains_item_i (device); + } + +private: + void list_add_item_i (Device * device); + int list_contains_item_i (Device * device); + void list_remove_item_i (Device* device); + +private: + DeviceList deviceList_; + ACE_RW_Thread_Mutex rwmutex_; +}; +// Listing 1 + +void +HA_DiscoveryAgent::list_add_item_i (Device *device) +{ + deviceList_.insert_tail (device); +} + +int +HA_DiscoveryAgent::list_contains_item_i (Device *device) +{ + DeviceListIterator iter (deviceList_); + while (!iter.done ()) + { + if (iter.next () == device) + return 1; + iter++; + } + + return 0; +} + +void +HA_DiscoveryAgent::list_remove_item_i (Device *device) +{ + DeviceListIterator iter (deviceList_); + while (!iter.done ()) + { + if (iter.next () == device) + { + iter.remove (); + break; + } + iter++; + } +} + +static Device *devices[100]; + +class Runner : public ACE_Task_Base +{ +public: + Runner(HA_DiscoveryAgent &agent) : agent_(agent) + { } + + virtual int svc (void) + { + ACE_ASSERT(agent_.contains_device(devices[9]) == 1); + agent_.remove_device (devices[9]); + ACE_ASSERT(agent_.contains_device(devices[9]) == 0); + return 0; + } + +private: + HA_DiscoveryAgent &agent_; +}; + +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + HA_DiscoveryAgent agent; + + for (int i = 0; i < 100; i++) + { + devices[i] = new Device (i); + agent.add_device (devices[i]); + } + + Runner runner (agent); + runner.activate (); + + runner.wait (); + + return 0; +} + +#else +#include "ace/OS_main.h" +#include "ace/OS_NS_stdio.h" + +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_OS::puts (ACE_TEXT ("This example requires threads.")); + return 0; +} + +#endif /* ACE_HAS_THREADS */ diff --git a/ACE/examples/APG/ThreadSafety/Semaphore.cpp b/ACE/examples/APG/ThreadSafety/Semaphore.cpp new file mode 100644 index 00000000000..47a85d86874 --- /dev/null +++ b/ACE/examples/APG/ThreadSafety/Semaphore.cpp @@ -0,0 +1,147 @@ +// $Id$ + +#include "ace/config-lite.h" +#if defined (ACE_HAS_THREADS) + +#include "ace/OS_NS_string.h" +#include "ace/Task.h" +#include "ace/Synch.h" + +// Listing 2 code/ch14 +class Consumer : public ACE_Task<ACE_MT_SYNCH> +{ +public: + enum { N_THREADS = 5 }; + + Consumer (ACE_Semaphore& psema, ACE_Semaphore& csema) + : psema_(psema), csema_(csema), exit_condition_(0) + { } + + int svc (void) + { + while (!is_closed ()) + consume_item (); + return 0; + } + + void consume_item () + { + csema_.acquire (); + if (!is_closed ()) + { + ACE_Message_Block *mb; + this->getq (mb); + if (mb->msg_type () == ACE_Message_Block::MB_HANGUP) + { + shutdown (); + mb->release (); + return; + } + else + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%t) Consumed %d\n"), + *((int*)mb->rd_ptr ()))); + mb->release(); + } + psema_.release (); + } + } + + void shutdown (void) + { + exit_condition_ = 1; + this->msg_queue ()->deactivate (); + csema_.release (N_THREADS); + } + + int is_closed (void) + { + return exit_condition_; + } + +private: + ACE_Semaphore& psema_; + ACE_Semaphore& csema_; + int exit_condition_; +}; +// Listing 2 +// Listing 1 code/ch14 +class Producer : public ACE_Task_Base +{ +public: + enum { MAX_PROD = 128 }; + + Producer (ACE_Semaphore& psema, ACE_Semaphore& csema, + Consumer &consumer) + : psema_(psema), csema_(csema), consumer_(consumer) + { } + + int svc (void) + { + for (int i = 0; i <= MAX_PROD; i++) + produce_item (i); + hang_up (); + return 0; + } + + void produce_item (int item) + { + psema_.acquire (); + ACE_Message_Block *mb + = new ACE_Message_Block (sizeof (int), + ACE_Message_Block::MB_DATA); + ACE_OS::memcpy (mb->wr_ptr (), &item, sizeof item); + mb->wr_ptr (sizeof (int)); + this->consumer_.putq (mb); + + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) Produced %d\n"), item)); + csema_.release(); + } + + void hang_up () + { + psema_.acquire (); + ACE_Message_Block *mb = + new ACE_Message_Block (0, ACE_Message_Block::MB_HANGUP); + this->consumer_.putq (mb); + csema_.release (); + } + +private: + ACE_Semaphore& psema_; + ACE_Semaphore& csema_; + Consumer& consumer_; +}; +// Listing 1 +// Listing 3 code/ch14 +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_Semaphore psem (5); + ACE_Semaphore csem (0); + + Consumer consumer (psem, csem); + Producer producer (psem, csem, consumer); + + producer.activate (); + consumer.activate (THR_NEW_LWP | THR_JOINABLE, + Consumer::N_THREADS); + + producer.wait (); + consumer.wait (); + + return 0; +} +// Listing 3 + +#else +#include "ace/OS_main.h" +#include "ace/OS_NS_stdio.h" + +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_OS::puts (ACE_TEXT ("This example requires threads.")); + return 0; +} + +#endif /* ACE_HAS_THREADS */ diff --git a/ACE/examples/APG/ThreadSafety/TSS.cpp b/ACE/examples/APG/ThreadSafety/TSS.cpp new file mode 100644 index 00000000000..8cc875cb3ee --- /dev/null +++ b/ACE/examples/APG/ThreadSafety/TSS.cpp @@ -0,0 +1,75 @@ +// $Id$ + +#include "ace/config-lite.h" +#if defined (ACE_HAS_THREADS) + +#include "ace/Synch.h" +#include "ace/Task.h" +#include "ClientContext.h" + + +void* +ClientContext::get_attribute (const char *name) +{ + void * value = 0; + attributeMap_.find (name, value); + return value; +} + +void +ClientContext::set_attribute (const char *name, void *value) +{ + attributeMap_.bind (name, value); +} + +// Listing 2 code/ch14 +class HA_CommandHandler : public ACE_Task<ACE_MT_SYNCH> +{ +public: + virtual int svc (void) + { + ACE_thread_t tid = this->thr_mgr ()->thr_self (); + // Set our identifier in TSS. + this->tss_ctx_->set_attribute ("thread_id", &tid); + + while (handle_requests () > 0) + ; + + return 0; + } + + int handle_requests (void) + { + ACE_thread_t *tid = + (ACE_thread_t*)this->tss_ctx_->get_attribute ("thread_id"); + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) TSS TID: %d \n"), + *tid)); + + // do work. + return -1; + } + +private: + ACE_TSS<ClientContext> tss_ctx_; +}; +// Listing 2 + +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + HA_CommandHandler handler; + handler.activate (THR_NEW_LWP | THR_JOINABLE, 5); + handler.wait (); + return 0; +} + +#else +#include "ace/OS_main.h" +#include "ace/OS_NS_stdio.h" + +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_OS::puts (ACE_TEXT ("This example requires threads.")); + return 0; +} + +#endif /* ACE_HAS_THREADS */ diff --git a/ACE/examples/APG/ThreadSafety/Tokens.cpp b/ACE/examples/APG/ThreadSafety/Tokens.cpp new file mode 100644 index 00000000000..13adff1febb --- /dev/null +++ b/ACE/examples/APG/ThreadSafety/Tokens.cpp @@ -0,0 +1,102 @@ +// $Id$ + +#include "ace/Local_Tokens.h" +#include "ace/Token_Manager.h" +#include "ace/Task.h" +#include "ace/OS_NS_time.h" + +#if defined (ACE_HAS_TOKENS_LIBRARY) + +class Device; + +// Listing 1 code/ch14 +class HA_Device_Repository +{ +public: + + enum { N_DEVICES = 100 }; + + HA_Device_Repository () + { + for (int i = 0; i < N_DEVICES; i++) + tokens_[i] = new ACE_Local_Mutex (0, 0, 1); + } + + ~HA_Device_Repository () + { + for (int i = 0; i < N_DEVICES; i++) + delete tokens_[i]; + } + + int update_device (int device_id, char *commands) + { + this->tokens_[device_id]->acquire (); + + Device *curr_device = this->devices_[device_id]; + internal_do (curr_device); + + this->tokens_[device_id]->release (); + + return 0; + } + + void internal_do (Device *device); + +private: + Device *devices_[N_DEVICES]; + ACE_Local_Mutex *tokens_[N_DEVICES]; + unsigned int seed_; +}; +// Listing 1 + +void +HA_Device_Repository::internal_do (Device *device) +{ + ACE_UNUSED_ARG (device); // Real code would use this. + ACE_Time_Value tv (0, ACE_OS::rand_r (this->seed_) % 10000); + timespec_t t = (timespec_t)tv; + ACE_OS::nanosleep (&t); +} + +// Listing 2 code/ch14 +class HA_CommandHandler : public ACE_Task_Base +{ +public: + enum { N_THREADS = 5 }; + + HA_CommandHandler (HA_Device_Repository &rep) : rep_(rep) + { } + + int svc (void) + { + for (int i = 0; i < HA_Device_Repository::N_DEVICES; i++) + rep_.update_device (i, ""); + return 0; + } + +private: + HA_Device_Repository &rep_; +}; + +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + HA_Device_Repository rep; + HA_CommandHandler handler (rep); + handler.activate (THR_NEW_LWP | THR_JOINABLE, + HA_CommandHandler::N_THREADS); + handler.wait (); + return 0; +} +// Listing 2 + +#else /* defined (ACE_HAS_TOKENS_LIBRARY) */ + +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("local tokens not supported ") + ACE_TEXT ("on this platform\n"))); + return 0; +} + +#endif /* defined (ACE_HAS_TOKENS_LIBRARY) */ diff --git a/ACE/examples/APG/ThreadSafety/Tokens_Deadlock.cpp b/ACE/examples/APG/ThreadSafety/Tokens_Deadlock.cpp new file mode 100644 index 00000000000..f6c6d22491f --- /dev/null +++ b/ACE/examples/APG/ThreadSafety/Tokens_Deadlock.cpp @@ -0,0 +1,69 @@ +// $Id$ + +#include "ace/Local_Tokens.h" +#include "ace/Task.h" +#include "ace/OS_NS_unistd.h" + +#if defined (ACE_HAS_TOKENS_LIBRARY) + +// Listing 1 code/ch14 +class ThreadOne : public ACE_Task_Base +{ +public: + virtual int svc (void) + { + ACE_Local_Mutex mutex1 (ACE_TEXT ("resource1"), + 0, // Deadlock detection enabled. + 1);// Debugging enabled. + mutex1.acquire (); + ACE_OS::sleep (2); + ACE_Local_Mutex mutex2 (ACE_TEXT ("resource2"), 0, 1); + mutex2.acquire (); + return 0; + } +}; + +class ThreadTwo : public ACE_Task_Base +{ +public: + virtual int svc (void) + { + ACE_Local_Mutex mutex2 (ACE_TEXT ("resource2"), + 0, // Deadlock detection enabled. + 1);// Debugging enabled. + mutex2.acquire (); + ACE_OS::sleep (2); + ACE_Local_Mutex mutex1 (ACE_TEXT ("resource1"), + 0, // Deadlock detection enabled. + 1);// Debugging enabled. + mutex1.acquire (); + return 0; + } +}; + +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ThreadOne t1; + ThreadTwo t2; + + t1.activate (); + ACE_OS::sleep (1); + t2.activate (); + t1.wait (); + t2.wait (); + + return 0; +} +// Listing 1 + +#else /* defined (ACE_HAS_TOKENS_LIBRARY) */ + +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("local tokens not supported ") + ACE_TEXT ("on this platform\n"))); + return 0; +} + +#endif /* defined (ACE_HAS_TOKENS_LIBRARY) */ diff --git a/ACE/examples/APG/ThreadSafety/threadsafety.mpc b/ACE/examples/APG/ThreadSafety/threadsafety.mpc new file mode 100644 index 00000000000..3598d274917 --- /dev/null +++ b/ACE/examples/APG/ThreadSafety/threadsafety.mpc @@ -0,0 +1,60 @@ +// -*- MPC -*- +// $Id$ + +project(Atomic Op) : aceexe { + exename = Atomic_Op + Source_Files { + Atomic_Op.cpp + } +} + +project(Barrier) : aceexe { + exename = Barrier + Source_Files { + Barrier.cpp + } +} + +project(Mutex) : aceexe { + exename = Mutex + Source_Files { + Mutex.cpp + } +} + +project(RW Lock) : aceexe { + avoids += ace_for_tao + exename = RW_Lock + Source_Files { + RW_Lock.cpp + } +} + +project(Semaphore) : aceexe { + avoids += ace_for_tao + exename = Semaphore + Source_Files { + Semaphore.cpp + } +} + +project(Tokens) : aceexe { + exename = Tokens + Source_Files { + Tokens.cpp + } +} + +project(Tokens Deadlock) : aceexe { + exename = Tokens_Deadlock + Source_Files { + Tokens_Deadlock.cpp + } +} + +project(TSS) : aceexe { + exename = TSS + Source_Files { + TSS.cpp + } +} diff --git a/ACE/examples/APG/Threads/.cvsignore b/ACE/examples/APG/Threads/.cvsignore new file mode 100644 index 00000000000..feb9ec3ab97 --- /dev/null +++ b/ACE/examples/APG/Threads/.cvsignore @@ -0,0 +1,12 @@ +Activate +Activate +Condition_Variables +Condition_Variables +Guards +Guards +Message_Blocks +Message_Blocks +Message_Queue +Message_Queue +Mutexes +Mutexes diff --git a/ACE/examples/APG/Threads/Activate.cpp b/ACE/examples/APG/Threads/Activate.cpp new file mode 100644 index 00000000000..2afa6316f91 --- /dev/null +++ b/ACE/examples/APG/Threads/Activate.cpp @@ -0,0 +1,33 @@ +// $Id$ + +// Listing 1 code/ch12 +#include "ace/Task.h" +#include "ace/OS_NS_unistd.h" + +class HA_CommandHandler : public ACE_Task_Base +{ +public: + virtual int svc (void) + { + ACE_DEBUG + ((LM_DEBUG, ACE_TEXT ("(%t) Handler Thread running\n"))); + ACE_OS::sleep (4); + return 0; + } +}; + +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_DEBUG + ((LM_DEBUG, ACE_TEXT ("(%t) Main Thread running\n"))); + + HA_CommandHandler handler; + int result = handler.activate (); + ACE_ASSERT (result == 0); + + ACE_UNUSED_ARG (result); + + handler.wait (); + return 0; +} +// Listing 1 diff --git a/ACE/examples/APG/Threads/Condition_Variables.cpp b/ACE/examples/APG/Threads/Condition_Variables.cpp new file mode 100644 index 00000000000..ccb29895032 --- /dev/null +++ b/ACE/examples/APG/Threads/Condition_Variables.cpp @@ -0,0 +1,118 @@ +// $Id$ + +#include "ace/config-lite.h" +#if defined (ACE_HAS_THREADS) + +#include "ace/Task.h" +#include "ace/Synch.h" + +// Listing 1 code/ch12 +class HA_Device_Repository +{ +public: + HA_Device_Repository() : owner_(0) + { } + + int is_free (void) + { return (this->owner_ == 0); } + + int is_owner (ACE_Task_Base* tb) + { return (this->owner_ == tb); } + + ACE_Task_Base *get_owner (void) + { return this->owner_; } + + void set_owner (ACE_Task_Base *owner) + { this->owner_ = owner; } + + int update_device (int device_id); + +private: + ACE_Task_Base * owner_; +}; +// Listing 1 + +class HA_CommandHandler : public ACE_Task_Base +{ +public: + enum {NUM_USES = 10}; + + HA_CommandHandler (HA_Device_Repository& rep, + ACE_Condition<ACE_Thread_Mutex> &wait, + ACE_Thread_Mutex& mutex) + : rep_(rep), waitCond_(wait), mutex_(mutex) + { } + + virtual int svc (void); + +private: + HA_Device_Repository &rep_; + ACE_Condition<ACE_Thread_Mutex> &waitCond_; + ACE_Thread_Mutex &mutex_; +}; +// Listing 2 code/ch12 +int +HA_CommandHandler::svc (void) +{ + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%t) Handler Thread running\n"))); + + for (int i = 0; i < NUM_USES; i++) + { + this->mutex_.acquire (); + while (!this->rep_.is_free ()) + this->waitCond_.wait (); + this->rep_.set_owner (this); + this->mutex_.release (); + + this->rep_.update_device (i); + + ACE_ASSERT (this->rep_.is_owner (this)); + this->rep_.set_owner (0); + + this->waitCond_.signal (); + } + + return 0; +} +// Listing 2 +int +HA_Device_Repository::update_device (int device_id) +{ + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) Updating device %d\n"), + device_id)); + + ACE_OS::sleep (1); + return 0; +} +// Listing 3 code/ch12 +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + HA_Device_Repository rep; + ACE_Thread_Mutex rep_mutex; + ACE_Condition<ACE_Thread_Mutex> wait (rep_mutex); + + HA_CommandHandler handler1 (rep, wait, rep_mutex); + HA_CommandHandler handler2 (rep, wait, rep_mutex); + + handler1.activate (); + handler2.activate (); + + handler1.wait (); + handler2.wait (); + + return 0; +} +// Listing 3 + +#else +#include "ace/OS_main.h" +#include "ace/OS_NS_stdio.h" + +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_OS::puts (ACE_TEXT ("This example requires threads.")); + return 0; +} + +#endif /* ACE_HAS_THREADS */ diff --git a/ACE/examples/APG/Threads/Guards.cpp b/ACE/examples/APG/Threads/Guards.cpp new file mode 100644 index 00000000000..7ef23e1e4da --- /dev/null +++ b/ACE/examples/APG/Threads/Guards.cpp @@ -0,0 +1,95 @@ +// $Id$ +#include "ace/config-lite.h" +#if defined (ACE_HAS_THREADS) + +#include "ace/OS_main.h" +#include "ace/OS_Memory.h" +#include "ace/Guard_T.h" +#include "ace/Log_Msg.h" +#include "ace/Thread_Mutex.h" + +// This file exists primarily to get code into the book to show different +// ways to do the same thing. For complete context and explanation, please +// see APG chapter 12. + +class HA_Device_Repository { +public: + int update_device (int device_id); + +private: + ACE_Thread_Mutex mutex_; +}; + +class Object { +}; +static Object *object; + +#if 0 +// This is less-desired way to do this... + +// Listing 1 code/ch12 +int +HA_Device_Repository::update_device (int device_id) +{ + this->mutex_.acquire (); + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) Updating device %d\n"), + device_id)); + + // Allocate a new object. + ACE_NEW_RETURN (object, Object, -1); + // ... + // Use the object + + this->mutex_.release (); +} +// Listing 1 +// Listing 2 code/ch12 +int +HA_Device_Repository::update_device (int device_id) +{ + // Construct a guard specifying the type of the mutex as + // a template parameter and passing in the mutex to hold + // as a parameter. + ACE_Guard<ACE_Thread_Mutex> guard (this->mutex_); + + // This can throw an exception that is not caught here. + ACE_NEW_RETURN (object, Object, -1); + // .. + // Use the object. + // .. + // Guard is destroyed, automatically releasing the lock. +} +// Listing 2 +#endif /* 0 */ + +// Listing 3 code/ch12 +int +HA_Device_Repository::update_device (int /* device_id */) +{ + ACE_GUARD_RETURN (ACE_Thread_Mutex, mon, mutex_, -1); + + ACE_NEW_RETURN (object, Object, -1); + // Use the object. + // ... + return 0; +} +// Listing 3 + +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + HA_Device_Repository rep; + rep.update_device (42); + return 0; +} + +#else +#include "ace/OS_main.h" +#include "ace/OS_NS_stdio.h" + +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_OS::puts (ACE_TEXT ("This example requires threads.")); + return 0; +} + +#endif /* ACE_HAS_THREADS */ diff --git a/ACE/examples/APG/Threads/Makefile.am b/ACE/examples/APG/Threads/Makefile.am new file mode 100644 index 00000000000..a5a1b77d76a --- /dev/null +++ b/ACE/examples/APG/Threads/Makefile.am @@ -0,0 +1,104 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +ACE_BUILDDIR = $(top_builddir) +ACE_ROOT = $(top_srcdir) + +## Makefile.Activate.am +noinst_PROGRAMS = Activate + +Activate_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +Activate_SOURCES = \ + Activate.cpp \ + Message_Receiver.h + +Activate_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Condition_Variables.am +noinst_PROGRAMS += Condition_Variables + +Condition_Variables_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +Condition_Variables_SOURCES = \ + Condition_Variables.cpp \ + Message_Receiver.h + +Condition_Variables_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Guards.am +noinst_PROGRAMS += Guards + +Guards_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +Guards_SOURCES = \ + Guards.cpp \ + Message_Receiver.h + +Guards_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Message_Blocks.am +noinst_PROGRAMS += Message_Blocks + +Message_Blocks_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +Message_Blocks_SOURCES = \ + Message_Blocks.cpp \ + Message_Receiver.h + +Message_Blocks_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Message_Queue.am +noinst_PROGRAMS += Message_Queue + +Message_Queue_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +Message_Queue_SOURCES = \ + Message_Queue.cpp \ + Message_Receiver.h + +Message_Queue_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Mutexes.am +noinst_PROGRAMS += Mutexes + +Mutexes_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +Mutexes_SOURCES = \ + Mutexes.cpp \ + Message_Receiver.h + +Mutexes_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Clean up template repositories, etc. +clean-local: + -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.* + -rm -f gcctemp.c gcctemp so_locations *.ics + -rm -rf cxx_repository ptrepository ti_files + -rm -rf templateregistry ir.out + -rm -rf ptrepository SunWS_cache Templates.DB diff --git a/ACE/examples/APG/Threads/Message_Blocks.cpp b/ACE/examples/APG/Threads/Message_Blocks.cpp new file mode 100644 index 00000000000..96cbf3e8cfe --- /dev/null +++ b/ACE/examples/APG/Threads/Message_Blocks.cpp @@ -0,0 +1,50 @@ +// $Id$ + +#include "ace/OS_main.h" +#include "ace/OS_Memory.h" +#include "ace/OS_NS_stdio.h" +#include "ace/OS_NS_string.h" +#include "ace/Log_Msg.h" +#include "ace/Message_Block.h" + +int ACE_TMAIN (int, ACE_TCHAR **) +{ +#if 0 +// Just for the book... + +// Listing 1 code/ch12 + ACE_Message_Block *mb; + ACE_NEW_RETURN (mb, ACE_Message_Block (128), -1); + + const char *deviceAddr= "Dev#12"; + mb->copy (deviceAddr, ACE_OS::strlen (deviceAddr)+1); +// Listing 1 +#endif /* 0 */ +// Listing 2 code/ch12 + ACE_Message_Block *mb; + ACE_NEW_RETURN (mb, ACE_Message_Block (128), -1); + + const char *commandSeq= "CommandSeq#14"; + ACE_OS::sprintf (mb->wr_ptr (), commandSeq); + // Move the wr_ptr() forward in the buffer by the + // amount of data we just put in. + mb->wr_ptr (ACE_OS::strlen (commandSeq) +1); +// Listing 2 +// Listing 3 code/ch12 + ACE_DEBUG((LM_DEBUG, + ACE_TEXT ("Command Sequence --> %C\n"), + mb->rd_ptr ())); + mb->rd_ptr (ACE_OS::strlen (mb->rd_ptr ())+1); + mb->release (); +// Listing 3 +// Listing 4 code/ch12 + // Send a hangup notification to the receiver. + ACE_NEW_RETURN + (mb, ACE_Message_Block (128, ACE_Message_Block::MB_HANGUP), -1); + // Send an error notification to the receiver. + mb->msg_type (ACE_Message_Block::MB_ERROR); +// Listing 4 + mb->release (); + + return 0; +} diff --git a/ACE/examples/APG/Threads/Message_Queue.cpp b/ACE/examples/APG/Threads/Message_Queue.cpp new file mode 100644 index 00000000000..3544d6bcefa --- /dev/null +++ b/ACE/examples/APG/Threads/Message_Queue.cpp @@ -0,0 +1,179 @@ +// $Id$ + +#include "ace/config-lite.h" +#if defined (ACE_HAS_THREADS) + +#include "ace/SOCK_Acceptor.h" +#include "ace/Acceptor.h" +#include "Message_Receiver.h" + +// Listing 5 code/ch12 +int +HA_CommandHandler::svc (void) +{ + while(1) + { + ACE_Message_Block *mb; + if (this->getq (mb) == -1) + break; + if (mb->msg_type () == ACE_Message_Block::MB_HANGUP) + { + mb->release (); + break; + } + else + { + // Get header pointer, then move past header to payload. + DeviceCommandHeader *dch + = (DeviceCommandHeader*)mb->rd_ptr (); + mb->rd_ptr (sizeof (DeviceCommandHeader)); + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("Message for device #%d with ") + ACE_TEXT ("command payload of:\n%s"), + dch->deviceId_, mb->rd_ptr ())); + this->rep_.update_device (dch->deviceId_, + mb->rd_ptr ()); + mb->release (); + } + } + + ACE_Reactor::instance ()->end_reactor_event_loop (); + + return 0; +} +// Listing 5 + +// Listing 4 code/ch12 +ACE_Message_Block * +Message_Receiver::shut_down_message (void) +{ + ACE_Message_Block *mb; + ACE_NEW_RETURN + (mb, ACE_Message_Block (0, ACE_Message_Block::MB_HANGUP), 0); + return mb; +} +// Listing 4 + +int +Message_Receiver::read_header (DeviceCommandHeader *dch) +{ + ssize_t result = + this->peer ().recv_n (dch, sizeof (DeviceCommandHeader)); + if (result <= 0) + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), + ACE_TEXT ("Recieve Failure")), + -1); + return 0; +} +// Listing 3 code/ch12 +int +Message_Receiver::copy_payload (ACE_Message_Block *mb, + int payload_length) +{ + ssize_t result = + this->peer ().recv_n (mb->wr_ptr (), payload_length); + + if (result <= 0) + { + mb->release (); + return -1; + } + + mb->wr_ptr (payload_length); + return 0; +} +// Listing 3 +// Listing 2 code/ch12 +int +Message_Receiver::handle_input (ACE_HANDLE) +{ + DeviceCommandHeader dch; + if (this->read_header (&dch) < 0) + return -1; + + if (dch.deviceId_ < 0) + { + // Handle shutdown. + this->handler_->putq (shut_down_message ()); + return -1; + } + + ACE_Message_Block *mb; + ACE_NEW_RETURN + (mb, ACE_Message_Block (dch.length_ + sizeof dch), -1); + // Copy the header. + mb->copy ((const char*)&dch, sizeof dch); + // Copy the payload. + if (this->copy_payload (mb, dch.length_) < 0) + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), + ACE_TEXT ("Recieve Failure")), -1); + // Pass it off to the handler thread. + this->handler_->putq (mb); + return 0; +} +// Listing 2 + +static void report_usage (int argc, ACE_TCHAR *argv[]) +{ + if (argc < 2) + { + ACE_DEBUG ((LM_ERROR, ACE_TEXT ("%s port\n"), argv[1])); + ACE_OS::exit (-1); + } +} + + +class Acceptor : public ACE_Acceptor<Message_Receiver, ACE_SOCK_ACCEPTOR> +{ +public: + Acceptor(HA_CommandHandler *handler) : handler_(handler) + { } + +protected: + virtual int make_svc_handler (Message_Receiver *&mr) + { + ACE_NEW_RETURN (mr, Message_Receiver (handler_), -1); + return 0; + } + +private: + HA_CommandHandler *handler_; +}; + +int ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + report_usage (argc, argv); + + u_short port = ACE_OS::atoi (argv[1]); + + HA_Device_Repository rep; + HA_CommandHandler handler (rep); + ACE_ASSERT(handler.activate()==0); + //start up the handler. + + Acceptor acceptor (&handler); + ACE_INET_Addr addr (port); + if (acceptor.open (addr) == -1) + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), + ACE_TEXT ("Failed to open connection")), -1); + + ACE_Reactor::instance()->run_reactor_event_loop (); + //run the reactive event loop + + handler.wait (); + //reap the handler before exiting. + + return 0; +} + +#else +#include "ace/OS_main.h" +#include "ace/OS_NS_stdio.h" + +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_OS::puts (ACE_TEXT ("This example requires threads.")); + return 0; +} + +#endif /* ACE_HAS_THREADS */ diff --git a/ACE/examples/APG/Threads/Message_Receiver.h b/ACE/examples/APG/Threads/Message_Receiver.h new file mode 100644 index 00000000000..dee0731f007 --- /dev/null +++ b/ACE/examples/APG/Threads/Message_Receiver.h @@ -0,0 +1,90 @@ +/** + * $Id$ + * + * Sample code from The ACE Programmer's Guide, + * copyright 2003 Addison-Wesley. All Rights Reserved. + */ + +#ifndef __MESSAGE_RECEIVER_H_ +#define __MESSAGE_RECEIVER_H_ + +#include "ace/Log_Msg.h" +#include "ace/Message_Block.h" +#include "ace/SOCK_Stream.h" +#include "ace/Svc_Handler.h" +#include "ace/Synch.h" +#include "ace/Task.h" + +// Listing 1 code/ch12 +struct DeviceCommandHeader +{ + int length_; + int deviceId_; +}; +// Listing 1 + +class HA_Device_Repository +{ +public: + HA_Device_Repository (); + + int update_device (int device_id, char *commands); + +private: + ACE_Task_Base *owner_; +}; + +HA_Device_Repository::HA_Device_Repository () +{ } + +int +HA_Device_Repository::update_device (int, char *) +{ + return 0; +} + +class HA_CommandHandler : public ACE_Task<ACE_MT_SYNCH> +{ +public: + HA_CommandHandler (HA_Device_Repository &rep) : rep_(rep) + { } + + virtual int svc(); + +private: + HA_Device_Repository &rep_; +}; + +class Message_Receiver : + public ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_MT_SYNCH> +{ +public: + Message_Receiver () : handler_(0) + { + ACE_ASSERT(0); + } + + Message_Receiver (HA_CommandHandler *ch) : handler_(ch) + { } + + ACE_Message_Block *shut_down_message (void); + + virtual int handle_input (ACE_HANDLE fd); + + virtual int handle_close (ACE_HANDLE = ACE_INVALID_HANDLE, + ACE_Reactor_Mask = ACE_Event_Handler::ALL_EVENTS_MASK) + { + this->peer ().close (); + delete this; + return 0; + } + +private: + int read_header (DeviceCommandHeader *dch); + int copy_payload (ACE_Message_Block *mb, int payload_length); + +private: + HA_CommandHandler *handler_; +}; + +#endif /* __MESSAGE_RECEIVER_H */ diff --git a/ACE/examples/APG/Threads/Mutexes.cpp b/ACE/examples/APG/Threads/Mutexes.cpp new file mode 100644 index 00000000000..ca5ebcdcbe4 --- /dev/null +++ b/ACE/examples/APG/Threads/Mutexes.cpp @@ -0,0 +1,75 @@ +// $Id$ + +#include "ace/config-lite.h" +#if defined (ACE_HAS_THREADS) + +#include "ace/Synch.h" +#include "ace/Task.h" + +// Listing 1 code/ch12 +class HA_Device_Repository +{ +public: + HA_Device_Repository () + { } + + void update_device (int device_id) + { + mutex_.acquire (); + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) Updating device %d\n"), + device_id)); + ACE_OS::sleep (1); + mutex_.release (); + } + +private: + ACE_Thread_Mutex mutex_; +}; +// Listing 1 +// Listing 2 code/ch12 +class HA_CommandHandler : public ACE_Task_Base +{ +public: + enum {NUM_USES = 10}; + + HA_CommandHandler (HA_Device_Repository& rep) : rep_(rep) + { } + + virtual int svc (void) + { + ACE_DEBUG + ((LM_DEBUG, ACE_TEXT ("(%t) Handler Thread running\n"))); + for (int i=0; i < NUM_USES; i++) + this->rep_.update_device (i); + return 0; + } + +private: + HA_Device_Repository & rep_; +}; + +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + HA_Device_Repository rep; + HA_CommandHandler handler1 (rep); + HA_CommandHandler handler2 (rep); + handler1.activate (); + handler2.activate (); + + handler1.wait (); + handler2.wait (); + return 0; +} +// Listing 2 + +#else +#include "ace/OS_main.h" +#include "ace/OS_NS_stdio.h" + +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_OS::puts (ACE_TEXT ("This example requires threads.")); + return 0; +} + +#endif /* ACE_HAS_THREADS */ diff --git a/ACE/examples/APG/Threads/threads.mpc b/ACE/examples/APG/Threads/threads.mpc new file mode 100644 index 00000000000..a980a867d26 --- /dev/null +++ b/ACE/examples/APG/Threads/threads.mpc @@ -0,0 +1,44 @@ +// -*- MPC -*- +// $Id$ + +project(Activate) : aceexe { + exename = Activate + Source_Files { + Activate.cpp + } +} + +project(Condition Variables) : aceexe { + exename = Condition_Variables + Source_Files { + Condition_Variables.cpp + } +} + +project(Guards) : aceexe { + exename = Guards + Source_Files { + Guards.cpp + } +} + +project(Message Blocks) : aceexe { + exename = Message_Blocks + Source_Files { + Message_Blocks.cpp + } +} + +project(Message Queue) : aceexe { + exename = Message_Queue + Source_Files { + Message_Queue.cpp + } +} + +project(Mutexes) : aceexe { + exename = Mutexes + Source_Files { + Mutexes.cpp + } +} diff --git a/ACE/examples/APG/Timers/.cvsignore b/ACE/examples/APG/Timers/.cvsignore new file mode 100644 index 00000000000..9137f2e897a --- /dev/null +++ b/ACE/examples/APG/Timers/.cvsignore @@ -0,0 +1,8 @@ +Alarm +Alarm +Task +Task +Timers +Timers +Upcall +Upcall diff --git a/ACE/examples/APG/Timers/Alarm.cpp b/ACE/examples/APG/Timers/Alarm.cpp new file mode 100644 index 00000000000..c12d39b367d --- /dev/null +++ b/ACE/examples/APG/Timers/Alarm.cpp @@ -0,0 +1,57 @@ +// $Id$ + +#include "ace/OS_NS_unistd.h" +#include "ace/OS_NS_sys_time.h" + +// Listing 1 code/ch20 +#include "ace/Timer_Queue_Adapters.h" +#include "ace/Timer_Heap.h" + +typedef ACE_Async_Timer_Queue_Adapter<ACE_Timer_Heap> Timer; +// Listing 1 + +class CB : public ACE_Event_Handler +{ +public: + CB (int id) : id_(id) { } + + virtual int handle_timeout (const ACE_Time_Value &, + const void *arg) + { + ACE_TRACE (ACE_TEXT ("CB::handle_timeout")); + + const int *val = static_cast<const int*> (arg); + ACE_ASSERT ((*val) == id_); + + ACE_UNUSED_ARG (val); + + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Timer expired\n"))); + return 0; + } + +private: + int id_; +}; + +// Listing 2 code/ch20 +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + // Create the timer such that it blocks all signals + // when it goes off. + Timer timer; + + // Schedule a timer to go off 2 seconds later and then + // after every 4 seconds. + CB cb (1); + int arg = 1; + ACE_Time_Value initial (2); + ACE_Time_Value repeat (4); + initial += ACE_OS::gettimeofday (); + timer.schedule (&cb, &arg, initial, repeat); + + while (1) // Don't let the main thread exit. + ACE_OS::sleep (2); + ACE_NOTREACHED (return 0); // Not reached. +} +// Listing 2 + diff --git a/ACE/examples/APG/Timers/CB.cpp b/ACE/examples/APG/Timers/CB.cpp new file mode 100644 index 00000000000..0a86ae7edeb --- /dev/null +++ b/ACE/examples/APG/Timers/CB.cpp @@ -0,0 +1,70 @@ +// $Id$ + +#include "ace/Log_Msg.h" +#include "CB.h" +#include "TimerDispatcher.h" + +CB::CB () : count_(0) +{ + ACE_TRACE (ACE_TEXT ("CB::CB")); +} + +// Listing 1 code/ch20 +int CB::handle_timeout (const ACE_Time_Value &, + const void *arg) +{ + ACE_TRACE (ACE_TEXT ("CB::handle_timeout")); + + const int *val = static_cast<const int*> (arg); + ACE_ASSERT ((*val) == timerID_); + + ACE_UNUSED_ARG (val); + + if (count_ == 5) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("Reseting interval for timer %d\n"), + timerID_)); + + // New interval is 10 ms. + ACE_Time_Value interval (0L, 1000L); + int status = Timer::instance ()->reset_interval + (timerID_, interval); +#if defined (ACE_NDEBUG) + ACE_UNUSED_ARG (status); +#else + ACE_ASSERT (status != -1); +#endif + } + + if (count_++ == 10) + { + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Canceling %d\n"), + timerID_)); + ACE_ASSERT ((Timer::instance ()->cancel (this)) != 0); + } + + return 0; +} +// Listing 1 + +void +CB::setID (long timerID) +{ + ACE_TRACE (ACE_TEXT ("CB::setID")); + timerID_ = timerID; +} + +long +CB::getID (void) +{ + ACE_TRACE (ACE_TEXT ("CB::getID")); + return timerID_; +} + +int +CB::handle_close (ACE_HANDLE, ACE_Reactor_Mask) +{ + ACE_TRACE (ACE_TEXT ("CB::handle_close")); + return 0; +} diff --git a/ACE/examples/APG/Timers/CB.h b/ACE/examples/APG/Timers/CB.h new file mode 100644 index 00000000000..716ad4e4f50 --- /dev/null +++ b/ACE/examples/APG/Timers/CB.h @@ -0,0 +1,36 @@ +/* -*- C++ -*- */ +// $Id$ + +#if !defined(CB_H) +#define CB_H + +#include "ace/Event_Handler.h" + +#include "TimerDispatcher.h" + +// Listing 1 code/ch20 +class CB : public ACE_Event_Handler +{ +public: + CB (); + + // Set the timer id that is being handled by this instance. + void setID (long timerID); + + // Get the timer id. + long getID (void); + + // Handle the timeout. + virtual int handle_timeout(const ACE_Time_Value &tv, + const void *arg = 0); + + virtual int handle_close (ACE_HANDLE handle, + ACE_Reactor_Mask close_mask); + +private: + long timerID_; + int count_; +}; +// Listing 1 + +#endif /*CB_H*/ diff --git a/ACE/examples/APG/Timers/Makefile.am b/ACE/examples/APG/Timers/Makefile.am new file mode 100644 index 00000000000..33976800fec --- /dev/null +++ b/ACE/examples/APG/Timers/Makefile.am @@ -0,0 +1,91 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +ACE_BUILDDIR = $(top_builddir) +ACE_ROOT = $(top_srcdir) + +## Makefile.Alarm.am +noinst_PROGRAMS = Alarm + +Alarm_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +Alarm_SOURCES = \ + Alarm.cpp \ + CB.h \ + PCB.h \ + PTimerDispatcher.h \ + TimerDispatcher.h \ + Upcall.h + +Alarm_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Task.am +noinst_PROGRAMS += Task + +Task_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +Task_SOURCES = \ + Task.cpp \ + CB.h \ + PCB.h \ + PTimerDispatcher.h \ + TimerDispatcher.h \ + Upcall.h + +Task_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Timers.am +noinst_PROGRAMS += Timers + +Timers_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +Timers_SOURCES = \ + CB.cpp \ + TimerDispatcher.cpp \ + Timers.cpp \ + CB.h \ + TimerDispatcher.h + +Timers_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Upcall.am +noinst_PROGRAMS += Upcall + +Upcall_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +Upcall_SOURCES = \ + PCB.cpp \ + PTimerDispatcher.cpp \ + Upcall.cpp \ + PCB.h \ + PTimerDispatcher.h \ + Upcall.h + +Upcall_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Clean up template repositories, etc. +clean-local: + -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.* + -rm -f gcctemp.c gcctemp so_locations *.ics + -rm -rf cxx_repository ptrepository ti_files + -rm -rf templateregistry ir.out + -rm -rf ptrepository SunWS_cache Templates.DB diff --git a/ACE/examples/APG/Timers/PCB.cpp b/ACE/examples/APG/Timers/PCB.cpp new file mode 100644 index 00000000000..d3401c65116 --- /dev/null +++ b/ACE/examples/APG/Timers/PCB.cpp @@ -0,0 +1,79 @@ +// $Id$ + +#include "ace/Log_Msg.h" +#include "PCB.h" +#include "PTimerDispatcher.h" + +PCB::PCB() : count_(0) +{ + ACE_TRACE (ACE_TEXT ("PCB::PCB")); +} + +PCB::~PCB() +{ +} + +int PCB::handleEvent (const void *arg) +{ + ACE_TRACE (ACE_TEXT ("PCB::handle_timeout")); + + const int *val = static_cast<const int*> (arg); + ACE_ASSERT ((*val) == timerID_); + + ACE_UNUSED_ARG (val); + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT("Timer %d expiry handled by thread %t\n"), + timerID_)); + if (count_ == 5) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("Reseting interval for timer %d\n"), + timerID_)); + + // New interval is 10 ms. + ACE_Time_Value interval (0L, 1000L); + if (PTimer::instance ()->reset_interval (timerID_, interval) != -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("reset_interval")), + -1); + } + + if (count_++ == 10) + { + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Canceling %d\n"), + timerID_)); + PTimer::instance ()->cancel (this); + } + + return 0; +} + +void +PCB::setID (long timerID) +{ + ACE_TRACE (ACE_TEXT ("PCB::setID")); + timerID_ = timerID; +} + +long +PCB::getID (void) const +{ + ACE_TRACE (ACE_TEXT ("PCB::getID")); + return timerID_; +} + +int +PCB::handleClose (void) +{ + ACE_TRACE (ACE_TEXT ("PCB::handle_close")); + return 0; +} + +int +PCB::handleCancel (void) +{ + ACE_TRACE (ACE_TEXT ("PCB::handleCancel")); + return 0; +} diff --git a/ACE/examples/APG/Timers/PCB.h b/ACE/examples/APG/Timers/PCB.h new file mode 100644 index 00000000000..7fdb9d2d1cf --- /dev/null +++ b/ACE/examples/APG/Timers/PCB.h @@ -0,0 +1,29 @@ +/* -*- C++ -*- */ +// $Id$ + +#if !defined(PCB_H) +#define PCB_H + +// Listing 1 code/ch20 +class PCB +{ +public: + PCB (); + virtual ~PCB (); + + // Set/get the timer id that is being handled by this instance. + void setID (long timerID); + long getID (void) const; + + // Handle a timeout event, cancel, and close. + virtual int handleEvent (const void *arg); + virtual int handleCancel (void); + virtual int handleClose (void); + +private: + long timerID_; + int count_; +}; +// Listing 1 + +#endif /*PCB_H*/ diff --git a/ACE/examples/APG/Timers/PTimerDispatcher.cpp b/ACE/examples/APG/Timers/PTimerDispatcher.cpp new file mode 100644 index 00000000000..405c5771789 --- /dev/null +++ b/ACE/examples/APG/Timers/PTimerDispatcher.cpp @@ -0,0 +1,69 @@ +// $Id$ + +#include "PTimerDispatcher.h" + +void PTimer_Dispatcher::wait_for_event (void) +{ + ACE_TRACE (ACE_TEXT ("PTimer_Dispatcher::wait_for_event")); + + while (1) + { + ACE_Time_Value max_tv = timer_queue_->gettimeofday (); + + ACE_Time_Value *this_timeout = + this->timer_queue_->calculate_timeout (&max_tv); + + if (*this_timeout == ACE_Time_Value::zero) + this->timer_queue_->expire (); + else + { + // Convert to absolute time. + ACE_Time_Value next_timeout = + timer_queue_->gettimeofday (); + next_timeout += *this_timeout; + if (this->timer_.wait (&next_timeout) == -1 ) + this->timer_queue_->expire (); + } + } +} + +long +PTimer_Dispatcher::schedule (PCB *cb, + void *arg, + const ACE_Time_Value &abs_time, + const ACE_Time_Value &interval) +{ + ACE_TRACE (ACE_TEXT ("PTimer_Dispatcher::schedule_timer")); + + return this->timer_queue_->schedule + (cb, arg, abs_time, interval); +} + +int +PTimer_Dispatcher::cancel (PCB *cb, + int dont_call_handle_close) +{ + ACE_TRACE (ACE_TEXT ("PTimer_Dispatcher::cancel")); + return timer_queue_->cancel (cb, dont_call_handle_close); +} + +void PTimer_Dispatcher::set (PTimerQueue *timer_queue) +{ + ACE_TRACE (ACE_TEXT ("PTimer_Dispatcher::set")); + + timer_queue_ = timer_queue; +} + +int +PTimer_Dispatcher::reset_interval (long timer_id, + const ACE_Time_Value &interval) +{ + ACE_TRACE (ACE_TEXT ("PTimer_Dispatcher::reset_interval")); + + return timer_queue_->reset_interval (timer_id, interval); +} + +#if defined (ACE_HAS_EXPLICIT_STATIC_TEMPLATE_MEMBER_INSTANTIATION) +template ACE_Singleton<PTimer_Dispatcher, ACE_Null_Mutex> * + ACE_Singleton<PTimer_Dispatcher, ACE_Null_Mutex>::singleton_; +# endif /* ACE_HAS_EXPLICIT_STATIC_TEMPLATE_MEMBER_INSTANTIATION */ diff --git a/ACE/examples/APG/Timers/PTimerDispatcher.h b/ACE/examples/APG/Timers/PTimerDispatcher.h new file mode 100644 index 00000000000..8a530f41709 --- /dev/null +++ b/ACE/examples/APG/Timers/PTimerDispatcher.h @@ -0,0 +1,39 @@ +/* -*- C++ -*- */ +// $Id$ + +#if !defined(PTIMER_DISPATCHER_H) +#define PTIMER_DISPATCHER_H + +#include "ace/Singleton.h" +#include "ace/Synch.h" // needed for ACE_Event + +#include "Upcall.h" +class PCB; + +class PTimer_Dispatcher +{ +public: + void wait_for_event (void); + + long schedule (PCB *cb, + void *arg, + const ACE_Time_Value &abs_time, + const ACE_Time_Value &interval); + + int cancel (PCB *cb, + int dont_call_handle_close = 1); + + int reset_interval (long timer_id, + const ACE_Time_Value &interval); + + void set (PTimerQueue *timer_queue); + +private: + PTimerQueue *timer_queue_; + ACE_Event timer_; +}; + +typedef ACE_Singleton<PTimer_Dispatcher, ACE_Null_Mutex> PTimer; + +#endif /*TIMER_DISPATCHER_H*/ + diff --git a/ACE/examples/APG/Timers/Task.cpp b/ACE/examples/APG/Timers/Task.cpp new file mode 100644 index 00000000000..4774eb1444f --- /dev/null +++ b/ACE/examples/APG/Timers/Task.cpp @@ -0,0 +1,73 @@ +// $Id$ + +#include "ace/OS_NS_sys_time.h" + +// Listing 1 code/ch20 +#include "ace/Timer_Queue_Adapters.h" +#include "ace/Timer_Heap.h" + +typedef ACE_Thread_Timer_Queue_Adapter<ACE_Timer_Heap> + ActiveTimer; + +// Listing 1 +// Listing 2 code/ch20 +class CB : public ACE_Event_Handler +{ +public: + CB (int id) : id_(id) { } + + virtual int handle_timeout (const ACE_Time_Value &, + const void *arg) + { + ACE_TRACE (ACE_TEXT ("CB::handle_timeout")); + + const int *val = static_cast<const int*> (arg); + ACE_ASSERT((*val) == id_); + + ACE_UNUSED_ARG (val); + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("Expiry handled by thread %t\n"))); + return 0; + } + +private: + int id_; +}; +// Listing 2 + +// Listing 3 code/ch20 +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("the main thread %t has started \n"))); + + // Create an "active" timer and start its thread. + ActiveTimer atimer; + atimer.activate (); + + CB cb1 (1); + CB cb2 (2); + int arg1 = 1; + int arg2 = 2; + + // Schedule timers to go off 3 & 4 seconds from now + // and then with an interval of 1.1 seconds. + const ACE_Time_Value curr_tv = ACE_OS::gettimeofday (); + ACE_Time_Value interval = ACE_Time_Value (1, 100000); + + atimer.schedule (&cb1, + &arg1, + curr_tv + ACE_Time_Value (3L), + interval); + atimer.schedule (&cb2, + &arg2, + curr_tv + ACE_Time_Value (4L), + interval); + + ACE_Thread_Manager::instance ()->wait (); // Wait forever. + + return 0; +} +// Listing 3 + diff --git a/ACE/examples/APG/Timers/TimerDispatcher.cpp b/ACE/examples/APG/Timers/TimerDispatcher.cpp new file mode 100644 index 00000000000..818d762b738 --- /dev/null +++ b/ACE/examples/APG/Timers/TimerDispatcher.cpp @@ -0,0 +1,73 @@ +// $Id$ + +#include "TimerDispatcher.h" +// Listing 1 code/ch20 +void Timer_Dispatcher::wait_for_event (void) +{ + ACE_TRACE (ACE_TEXT ("Timer_Dispatcher::wait_for_event")); + + while (1) + { + ACE_Time_Value max_tv = timer_queue_->gettimeofday (); + + ACE_Time_Value *this_timeout = + this->timer_queue_->calculate_timeout (&max_tv); + + if (*this_timeout == ACE_Time_Value::zero) + this->timer_queue_->expire (); + else + { + // Convert to absolute time. + ACE_Time_Value next_timeout = + timer_queue_->gettimeofday (); + next_timeout += *this_timeout; + if (this->timer_.wait (&next_timeout) == -1 ) + this->timer_queue_->expire (); + } + } +} +// Listing 1 +// Listing 2 code/ch20 +long +Timer_Dispatcher::schedule (ACE_Event_Handler *cb, + void *arg, + const ACE_Time_Value &abs_time, + const ACE_Time_Value &interval) +{ + ACE_TRACE (ACE_TEXT ("Timer_Dispatcher::schedule_timer")); + + return this->timer_queue_->schedule + (cb, arg, abs_time, interval); +} +// Listing 2 +// Listing 3 code/ch20 +int +Timer_Dispatcher::cancel (ACE_Event_Handler *cb, + int dont_call_handle_close) +{ + ACE_TRACE (ACE_TEXT ("Timer_Dispatcher::cancel")); + return timer_queue_->cancel (cb, dont_call_handle_close); +} +// Listing 3 +// Listing 4 code/ch20 +void Timer_Dispatcher::set (ACE_Timer_Queue *timer_queue) +{ + ACE_TRACE (ACE_TEXT ("Timer_Dispatcher::set")); + + timer_queue_ = timer_queue; +} +// Listing 4 + +int +Timer_Dispatcher::reset_interval (long timer_id, + const ACE_Time_Value &interval) +{ + ACE_TRACE (ACE_TEXT ("Timer_Dispatcher::reset_interval")); + + return timer_queue_->reset_interval(timer_id, interval); +} + +#if defined (ACE_HAS_EXPLICIT_STATIC_TEMPLATE_MEMBER_INSTANTIATION) +template ACE_Singleton<Timer_Dispatcher, ACE_Null_Mutex> * + ACE_Singleton<Timer_Dispatcher, ACE_Null_Mutex>::singleton_; +# endif /* ACE_HAS_EXPLICIT_STATIC_TEMPLATE_MEMBER_INSTANTIATION */ diff --git a/ACE/examples/APG/Timers/TimerDispatcher.h b/ACE/examples/APG/Timers/TimerDispatcher.h new file mode 100644 index 00000000000..fc519b77615 --- /dev/null +++ b/ACE/examples/APG/Timers/TimerDispatcher.h @@ -0,0 +1,40 @@ +/* -*- C++ -*- */ +// $Id$ + +#if !defined(TIMER_DISPATCHER_H) +#define TIMER_DISPATCHER_H + +#include "ace/Event_Handler.h" +#include "ace/Singleton.h" +#include "ace/Synch.h" // needed for ACE_Event +#include "ace/Timer_Queue.h" + +// Listing 1 code/ch20 +class Timer_Dispatcher +{ +public: + void wait_for_event (void); + + long schedule (ACE_Event_Handler *cb, + void *arg, + const ACE_Time_Value &abs_time, + const ACE_Time_Value &interval); + + int cancel (ACE_Event_Handler *cb, + int dont_call_handle_close = 1); + + int reset_interval (long timer_id, + const ACE_Time_Value &interval); + + void set (ACE_Timer_Queue *timer_queue); + +private: + ACE_Timer_Queue *timer_queue_; + ACE_Event timer_; +}; + +typedef ACE_Singleton<Timer_Dispatcher, ACE_Null_Mutex> Timer; +// Listing 1 + +#endif /*TIMER_DISPATCHER_H*/ + diff --git a/ACE/examples/APG/Timers/Timers.cpp b/ACE/examples/APG/Timers/Timers.cpp new file mode 100644 index 00000000000..761f03a650c --- /dev/null +++ b/ACE/examples/APG/Timers/Timers.cpp @@ -0,0 +1,58 @@ +// $Id$ + +// Listing 1 code/ch20 +#include "ace/Timer_Queue.h" +#include "ace/Timer_Heap.h" +#include "ace/Timer_Wheel.h" +#include "ace/Timer_Hash.h" +#include "ace/Timer_List.h" + +#include "CB.h" +#include "TimerDispatcher.h" + +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_Timer_Queue *timer_queue; + +#if defined(HEAP) + + ACE_NEW_RETURN (timer_queue, ACE_Timer_Heap, -1); +#elsif defined(HASH) + + ACE_NEW_RETURN (timer_queue, ACE_Timer_Hash, -1); +#elsif defined(WHEEL) + + ACE_NEW_RETURN (timer_queue, ACE_Timer_Wheel, -1); +#else + + ACE_NEW_RETURN (timer_queue, ACE_Timer_List, -1); +#endif + + // setup the timer queue + Timer::instance ()->set (timer_queue); + + CB cb[10]; + long args[10]; + for (long i = 0; i < 10 ; i++) + { + ACE_Time_Value const timeout (i); + long timerID = + Timer::instance ()->schedule + (&cb[i], + &args[i], + timer_queue->gettimeofday () + (ACE_Time_Value)5, + timeout); + + // Set the timerID state variable of the handler. + cb[i].setID (timerID); + + // Implicitly send the handler it's timer id. + args[i] = timerID; + } + + // "run" the timer. + Timer::instance ()->wait_for_event (); + + return 0; +} +// Listing 1 diff --git a/ACE/examples/APG/Timers/Upcall.cpp b/ACE/examples/APG/Timers/Upcall.cpp new file mode 100644 index 00000000000..cb00ae6113a --- /dev/null +++ b/ACE/examples/APG/Timers/Upcall.cpp @@ -0,0 +1,172 @@ +// $Id$ + +#include "ace/OS_NS_sys_time.h" +#include "ace/Log_Msg.h" +#include "Upcall.h" +#include "PTimerDispatcher.h" + +// Listing 2 code/ch20 +// The signature of this method changed at ACE 5.4. The 'recurring_timer' +// parameter was added. +int +UpcallHandler::timeout (PTimerQueue &, + PCB *handler, + const void *arg, + int /* recurring_timer */, + const ACE_Time_Value &) +{ + ACE_TRACE (ACE_TEXT ("UpcallHandler::timeout")); + + return (*handler).handleEvent (arg); +} + +#if 0 +// This method was removed at ACE 5.4. Replaced by cancel_type() and +// cancel_timer(). +int +UpcallHandler::cancellation (PTimerQueue &, + PCB *handler) +{ + ACE_TRACE (ACE_TEXT ("UpcallHandler::cancellation")); + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("Handler %d has been cancelled\n"), + handler->getID ())); + + return handler->handleCancel (); +} +#endif /* 0 */ + +// This method is called when the timer is canceled +int +UpcallHandler::deletion (PTimerQueue &, + PCB *handler, + const void *) +{ + ACE_TRACE (ACE_TEXT ("UpcallHandler::deletion")); + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("Handler %d has been deleted\n"), + handler->getID ())); + + return handler->handleClose (); +} +// Listing 2 + +// *** The rest of the UpcallHandler methods were added for ACE 5.4 *** + +// This method is called when a timer is registered. +int +UpcallHandler::registration (PTimerQueue &, + PCB *handler, + const void *) +{ + ACE_TRACE (ACE_TEXT ("UpcallHandler::registration")); + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("Handler %d has been registered.\n"), + handler->getID ())); + return 0; +} + +// This method is called at expiration time, before the actual upcall +// to the handler is made. ACE uses this to adjust reference counts +// when needed. +int +UpcallHandler::preinvoke (PTimerQueue &, + PCB *handler, + const void *, + int, + const ACE_Time_Value &, + const void *&) +{ + ACE_TRACE (ACE_TEXT ("UpcallHandler::preinvoke")); + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("Handler %d is about to upcalled.\n"), + handler->getID ())); + return 0; +} + +// This method is called at expiration time, after the actual upcall +// to the handler returns. ACE uses this to adjust reference counts +// when needed. +int +UpcallHandler::postinvoke (PTimerQueue &, + PCB *handler, + const void *, + int, + const ACE_Time_Value &, + const void *) +{ + ACE_TRACE (ACE_TEXT ("UpcallHandler::postinvoke")); + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("Handler %d returned from upcall.\n"), + handler->getID ())); + return 0; +} + +// This method is called when a handler is cancelled +int +UpcallHandler::cancel_type (PTimerQueue &, + PCB *handler, + int dont_call, + int &) +{ + ACE_TRACE (ACE_TEXT ("UpcallHandler::cancel_type")); + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("Handler %d has been cancelled\n"), + handler->getID ())); + if (!dont_call) + return handler->handleCancel (); + return 0; +} + +// This method is called when a timer is cancelled +int +UpcallHandler::cancel_timer (PTimerQueue &, + PCB *handler, + int dont_call, + int) +{ + ACE_TRACE (ACE_TEXT ("UpcallHandler::cancel_timer")); + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("Handler %d has been cancelled\n"), + handler->getID ())); + if (!dont_call) + return handler->handleCancel (); + return 0; +} + + +// Listing 3 code/ch20 +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + PCB cb1, cb2; + cb1.setID (1); + cb2.setID (2); + int arg1 = 1, arg2 = 2; + + PTimerQueue *timerQueue; + + ACE_NEW_RETURN (timerQueue, PTimerHeap (), -1); + + PTimer::instance ()->set (timerQueue); + + ACE_Time_Value tv = ACE_OS::gettimeofday (); + tv += 20L; + + // Schedule two different timers to go off. + PTimer::instance ()->schedule (&cb1, &arg1, tv, ACE_Time_Value (1)); + PTimer::instance ()->schedule (&cb2, &arg2, tv, ACE_Time_Value (2)); + + // Run the timer event loop forever. + PTimer::instance ()->wait_for_event (); + + return 0; +} +// Listing 3 + diff --git a/ACE/examples/APG/Timers/Upcall.h b/ACE/examples/APG/Timers/Upcall.h new file mode 100644 index 00000000000..6a154f3b8b1 --- /dev/null +++ b/ACE/examples/APG/Timers/Upcall.h @@ -0,0 +1,87 @@ +/* -*- C++ -*- */ +// $Id$ + +#if !defined(UPCALL_H) +#define UPCALL_H + +#include "ace/Timer_Queue_T.h" +#include "ace/Timer_Heap_T.h" +#include "ace/Synch.h" + +#include "PCB.h" + +// Listing 1 code/ch20 +class UpcallHandler; + +typedef ACE_Timer_Queue_T<PCB*, UpcallHandler, ACE_Null_Mutex> + PTimerQueue; + +// Create a special heap-based timer queue that allows you to +// control exactly how timer evetns are handled. +typedef ACE_Timer_Heap_T<PCB*, UpcallHandler, ACE_Null_Mutex> + PTimerHeap; +// Listing 1 + +class UpcallHandler +{ +public: + // The signature of this method changed at ACE 5.4. The 'recurring_timer' + // parameter was added. + int timeout (PTimerQueue &timer_queue, + PCB *handler, + const void *arg, + int recurring_timer, + const ACE_Time_Value &cur_time); + +#if 0 + // This method was removed at ACE 5.4. Replaced by cancel_type() and + // cancel_timer(). + // This method is called when the timer is canceled. + int cancellation (PTimerQueue &timer_queue, + PCB *handler); +#endif + + // This method is called when the timer queue is destroyed and + // the timer is still contained in it. + int deletion (PTimerQueue &timer_queue, + PCB *handler, + const void *arg); + + // The following methods don't appear before ACE 5.4, so aren't + // referenced in APG (it's based on ACE 5.3). + + // This method is called when a timer is registered. + int registration (PTimerQueue &timer_queue, + PCB *handler, + const void *arg); + + // This method is called before the timer expires. + int preinvoke (PTimerQueue &timer_queue, + PCB *handler, + const void *arg, + int recurring_timer, + const ACE_Time_Value &cur_time, + const void *&upcall_act); + + // This method is called after the timer expires. + int postinvoke (PTimerQueue &timer_queue, + PCB *handler, + const void *arg, + int recurring_timer, + const ACE_Time_Value &cur_time, + const void *upcall_act); + + // This method is called when a handler is cancelled + int cancel_type (PTimerQueue &timer_queue, + PCB *handler, + int dont_call, + int &requires_reference_counting); + + // This method is called when a timer is cancelled + int cancel_timer (PTimerQueue &timer_queue, + PCB *handler, + int dont_call, + int requires_reference_counting); +}; + +#endif /*UPCALL_H*/ diff --git a/ACE/examples/APG/Timers/timers.mpc b/ACE/examples/APG/Timers/timers.mpc new file mode 100644 index 00000000000..295b2bb97d5 --- /dev/null +++ b/ACE/examples/APG/Timers/timers.mpc @@ -0,0 +1,34 @@ +// -*- MPC -*- +// $Id$ + +project(Alarm) : aceexe { + exename = Alarm + Source_Files { + Alarm.cpp + } +} + +project(Task) : aceexe { + exename = Task + Source_Files { + Task.cpp + } +} + +project(Timers) : aceexe { + exename = Timers + Source_Files { + Timers.cpp + CB.cpp + TimerDispatcher.cpp + } +} + +project(Upcall) : aceexe { + exename = Upcall + Source_Files { + Upcall.cpp + PCB.cpp + PTimerDispatcher.cpp + } +} diff --git a/ACE/examples/ASX/.cvsignore b/ACE/examples/ASX/.cvsignore new file mode 100644 index 00000000000..1eb7e8a0b93 --- /dev/null +++ b/ACE/examples/ASX/.cvsignore @@ -0,0 +1 @@ +Mess diff --git a/ACE/examples/ASX/CCM_App/.cvsignore b/ACE/examples/ASX/CCM_App/.cvsignore new file mode 100644 index 00000000000..955ffdc75d5 --- /dev/null +++ b/ACE/examples/ASX/CCM_App/.cvsignore @@ -0,0 +1,4 @@ +client +client +server +server diff --git a/ACE/examples/ASX/CCM_App/ASX_CCM_App.mpc b/ACE/examples/ASX/CCM_App/ASX_CCM_App.mpc new file mode 100644 index 00000000000..b5c40beb84c --- /dev/null +++ b/ACE/examples/ASX/CCM_App/ASX_CCM_App.mpc @@ -0,0 +1,26 @@ +// -*- MPC -*- +// $Id$ + +project(*Lib) : acelib { + sharedname = ccm_app + Source_Files { + CCM_App.cpp + } +} + +project(*Server) : aceexe { + exename = server + after += ASX_CCM_App_Lib + Source_Files { + SC_Server.cpp + } +} + +project(*Client) : aceexe { + exename = client + after += ASX_CCM_App_Server + Source_Files { + SC_Client.cpp + } +} + diff --git a/ACE/examples/ASX/CCM_App/CCM_App.cpp b/ACE/examples/ASX/CCM_App/CCM_App.cpp new file mode 100644 index 00000000000..ac72730edb7 --- /dev/null +++ b/ACE/examples/ASX/CCM_App/CCM_App.cpp @@ -0,0 +1,119 @@ +// $Id$ + +#define ACE_BUILD_SVC_DLL + +#include "ace/Stream.h" +#include "ace/Task.h" +#include "ace/Module.h" +#include "ace/svc_export.h" + +ACE_RCSID(CCM_App, CCM_App, "$Id$") + +typedef ACE_Task<ACE_SYNCH> MT_Task; +typedef ACE_Stream<ACE_SYNCH> MT_Stream; +typedef ACE_Module<ACE_SYNCH> MT_Module; + +class ACE_Svc_Export Test_Task : public MT_Task +{ +public: + virtual int open (void *); + virtual int close (u_long); + virtual int init (int, ACE_TCHAR *[]); + virtual int fini (void); + virtual int suspend (void); + virtual int resume (void); +}; + +int +Test_Task::open (void *) +{ + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("opening %s\n"), + this->name () ? this->name () : ACE_TEXT ("task"))); + return 0; +} + +int +Test_Task::close (u_long) +{ + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("closing %s\n"), + this->name () ? this->name () : ACE_TEXT ("task"))); + return 0; +} + +int +Test_Task::suspend (void) +{ + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("suspending in %s\n"), + this->name () ? this->name () : ACE_TEXT ("task"))); + return 0; +} + +int +Test_Task::resume (void) +{ + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("resuming in %s\n"), + this->name () ? this->name () : ACE_TEXT ("task"))); + return 0; +} + +int +Test_Task::init (int, ACE_TCHAR *[]) +{ + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("initializing %s\n"), + this->name () ? this->name () : ACE_TEXT ("task"))); + + return 0; +} + +int +Test_Task::fini (void) +{ + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("finalizing %s\n"), + this->name () ? this->name () : ACE_TEXT ("task"))); + return 0; +} + +// Factories used to control configuration. + +ACE_SVC_FACTORY_DECLARE (Test_Task) +ACE_SVC_FACTORY_DEFINE (Test_Task) + +// Dynamically linked functions used to control configuration. + +extern "C" ACE_Svc_Export MT_Stream *make_stream (void); +extern "C" ACE_Svc_Export MT_Module *make_da (void); +extern "C" ACE_Svc_Export MT_Module *make_ea (void); +extern "C" ACE_Svc_Export MT_Module *make_mr (void); + +MT_Stream * +make_stream (void) +{ + return new MT_Stream; +} + +MT_Module * +make_da (void) +{ + return new MT_Module (ACE_TEXT ("Device_Adapter"), + new Test_Task, new Test_Task); +} + +MT_Module * +make_ea (void) +{ + return new MT_Module (ACE_TEXT ("Event_Analyzer"), + new Test_Task, new Test_Task); +} + +MT_Module * +make_mr (void) +{ + return new MT_Module (ACE_TEXT ("Multicast_Router"), + new Test_Task, new Test_Task); +} diff --git a/ACE/examples/ASX/CCM_App/Makefile.am b/ACE/examples/ASX/CCM_App/Makefile.am new file mode 100644 index 00000000000..e4051c952ad --- /dev/null +++ b/ACE/examples/ASX/CCM_App/Makefile.am @@ -0,0 +1,57 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +ACE_BUILDDIR = $(top_builddir) +ACE_ROOT = $(top_srcdir) + +## Makefile.ASX_CCM_App_Lib.am + +noinst_LTLIBRARIES = libccm_app.la + +libccm_app_la_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +libccm_app_la_SOURCES = \ + CCM_App.cpp + +## Makefile.ASX_CCM_App_Server.am +noinst_PROGRAMS = server + +server_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +server_SOURCES = \ + SC_Server.cpp + +server_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.ASX_CCM_App_Client.am +noinst_PROGRAMS += client + +client_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +client_SOURCES = \ + SC_Client.cpp + +client_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Clean up template repositories, etc. +clean-local: + -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.* + -rm -f gcctemp.c gcctemp so_locations *.ics + -rm -rf cxx_repository ptrepository ti_files + -rm -rf templateregistry ir.out + -rm -rf ptrepository SunWS_cache Templates.DB diff --git a/ACE/examples/ASX/CCM_App/SC_Client.cpp b/ACE/examples/ASX/CCM_App/SC_Client.cpp new file mode 100644 index 00000000000..fbd4439784a --- /dev/null +++ b/ACE/examples/ASX/CCM_App/SC_Client.cpp @@ -0,0 +1,13 @@ +// $Id$ + +#include "ace/ACE.h" + +ACE_RCSID(CCM_App, SC_Client, "$Id$") + +// Pretty simple, eh? ;-) + +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + return 0; +} diff --git a/ACE/examples/ASX/CCM_App/SC_Server.cpp b/ACE/examples/ASX/CCM_App/SC_Server.cpp new file mode 100644 index 00000000000..b93e49005bf --- /dev/null +++ b/ACE/examples/ASX/CCM_App/SC_Server.cpp @@ -0,0 +1,86 @@ +// $Id$ + +// Simple driver program for the server. This driver dynamically +// links in all the services in the <svc.conf> file. + +#include "ace/OS_NS_unistd.h" +#include "ace/OS_main.h" +#include "ace/Service_Config.h" +#include "ace/Thread_Manager.h" +#include "ace/Reactor.h" +#include "ace/Sig_Adapter.h" + +ACE_RCSID(CCM_App, SC_Server, "$Id$") + +class Event_Handler : public ACE_Event_Handler +{ +public: + virtual int handle_input (ACE_HANDLE handle); + virtual int handle_close (ACE_HANDLE, + ACE_Reactor_Mask); +}; + +int +Event_Handler::handle_input (ACE_HANDLE handle) +{ + char buf[BUFSIZ]; + ssize_t n = ACE_OS::read (handle, buf, sizeof buf); + + if (n == -1) + return -1; + else if (n == 0) + ACE_ERROR_RETURN ((LM_DEBUG, + ACE_TEXT ("shutting down on EOF\n")), + -1); + else if (ACE_OS::write (ACE_STDOUT, buf, n) != n) + ACE_ERROR_RETURN ((LM_DEBUG, + ACE_TEXT ("%p\n"), ACE_TEXT ("write failed")), + -1); + else + return 0; +} + +int +Event_Handler::handle_close (ACE_HANDLE, ACE_Reactor_Mask) +{ + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("closing Event_Handler\n"))); + ACE_Reactor::instance ()->end_reactor_event_loop (); + return 0; +} + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + ACE_Service_Config loggerd; + Event_Handler handler; + ACE_Sig_Adapter shutdown_handler ((ACE_Sig_Handler_Ex) ACE_Reactor::end_event_loop); + + if (ACE_Event_Handler::register_stdin_handler (&handler, + ACE_Reactor::instance (), + ACE_Thread_Manager::instance ()) == -1) + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("register_stdin_handler"))); + + if (loggerd.open (argc, + argv, + ACE_DEFAULT_LOGGER_KEY, + // Don't ignore static services! + 0) == -1 && errno != ENOENT) + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("%p\n%a"), + ACE_TEXT ("open"), + 1)); + else if (ACE_Reactor::instance ()->register_handler + (SIGINT, &shutdown_handler) == -1) + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("%p\n%a"), + ACE_TEXT ("register_handler"), + 1)); + + // Perform logging service until we receive SIGINT. + + ACE_Reactor::instance ()->run_reactor_event_loop (); + return 0; +} diff --git a/ACE/examples/ASX/CCM_App/svc.conf b/ACE/examples/ASX/CCM_App/svc.conf new file mode 100644 index 00000000000..b894e6e69e5 --- /dev/null +++ b/ACE/examples/ASX/CCM_App/svc.conf @@ -0,0 +1,21 @@ +static ACE_Service_Manager "-d -p 4911" + +dynamic Test_Task Service_Object *CCM_App:_make_Test_Task() "-p 3000" + +stream dynamic CCM_App STREAM *CCM_App:make_stream() active +{ + dynamic Device_Adapter Module *CCM_App:make_da() + dynamic Event_Analyzer Module *CCM_App:make_ea() + dynamic Multicast_Router Module *CCM_App:make_mr() "-p 3001" +} + +stream CCM_App +{ + remove Device_Adapter +# remove Event_Analyzer +# remove Multicast_Router +} + +# remove CCM_App +remove Test_Task + diff --git a/ACE/examples/ASX/CCM_App/svc.conf.xml b/ACE/examples/ASX/CCM_App/svc.conf.xml new file mode 100644 index 00000000000..e743d4ed986 --- /dev/null +++ b/ACE/examples/ASX/CCM_App/svc.conf.xml @@ -0,0 +1,33 @@ +<?xml version='1.0'?> +<!-- Converted from svc.conf by svcconf-convert.pl --> +<ACE_Svc_Conf> + <static id="ACE_Service_Manager" params="-d -p 4911"/> + <dynamic id="Test_Task" type="Service_Object"> + <initializer path="CCM_App" init="_make_Test_Task" params="-p 3000"/> + </dynamic> + <streamdef> + <dynamic id="CCM_App" type="STREAM"> + <initializer path="CCM_App" init="make_stream"/> + </dynamic> + <module> + <dynamic id="Device_Adapter" type="Module"> + <initializer path="CCM_App" init="make_da"/> + </dynamic> + <dynamic id="Event_Analyzer" type="Module"> + <initializer path="CCM_App" init="make_ea"/> + </dynamic> + <dynamic id="Multicast_Router" type="Module"> + <initializer path="CCM_App" init="make_mr" params="-p 3001"/> + </dynamic> + </module> + </streamdef> + <stream id="CCM_App"> + <module> + <remove id="Device_Adapter"/> + <!-- remove Event_Analyzer --> + <!-- remove Multicast_Router --> + </module> + </stream> + <!-- remove CCM_App --> + <remove id="Test_Task"/> +</ACE_Svc_Conf> diff --git a/ACE/examples/ASX/Event_Server/Event_Server/Consumer_Router.cpp b/ACE/examples/ASX/Event_Server/Event_Server/Consumer_Router.cpp new file mode 100644 index 00000000000..d5215ffcd26 --- /dev/null +++ b/ACE/examples/ASX/Event_Server/Event_Server/Consumer_Router.cpp @@ -0,0 +1,159 @@ +// $Id$ + +#include "ace/os_include/os_assert.h" +#include "ace/OS_NS_stdio.h" +#include "ace/OS_NS_string.h" +#include "Consumer_Router.h" +#include "Options.h" + +ACE_RCSID(Event_Server, Consumer_Router, "$Id$") + +Consumer_Router::Consumer_Router (Peer_Router_Context *prc) + : Peer_Router (prc) +{ + this->context ()->duplicate (); +} + +// Initialize the Router. + +int +Consumer_Router::open (void *) +{ + if (this->is_writer ()) + { + // Set the <Peer_Router_Context> to point back to us so that if + // any Consumer's "accidentally" send us data we'll be able to + // handle it by passing it down the stream. + this->context ()->peer_router (this); + + // Increment the reference count. + this->context ()->duplicate (); + + // Make this an active object to handle the error cases in a + // separate thread. This is mostly just for illustration, i.e., + // it's probably overkill to use a thread for this! + return this->activate (Options::instance ()->t_flags ()); + } + else // if (this->is_reader ()) + + // Nothing to do since this side is primarily used to transmit to + // Consumers, rather than receive. + return 0; +} + +int +Consumer_Router::close (u_long) +{ + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) closing Consumer_Router %s\n"), + this->is_reader () ? ACE_TEXT ("reader") : ACE_TEXT ("writer"))); + + if (this->is_writer ()) + // Inform the thread to shut down. + this->msg_queue ()->deactivate (); + + // Both writer and reader call <release>, so the context knows when + // to clean itself up. + this->context ()->release (); + return 0; +} + +// Handle incoming messages in a separate thread. + +int +Consumer_Router::svc (void) +{ + assert (this->is_writer ()); + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%t) starting svc in Consumer_Router\n"))); + + for (ACE_Message_Block *mb = 0; + this->getq (mb) >= 0; + ) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%t) warning: Consumer_Router is ") + ACE_TEXT ("forwarding a message to Supplier_Router\n"))); + + // Pass this message down to the next Module's writer Task. + if (this->put_next (mb) == -1) + ACE_ERROR_RETURN + ((LM_ERROR, + ACE_TEXT ("(%t) send_peers failed in Consumer_Router\n")), + -1); + } + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%t) stopping svc in Consumer_Router\n"))); + return 0; + // Note the implicit ACE_OS::thr_exit() via destructor. +} + +// Send a <Message_Block> to the supplier(s). + +int +Consumer_Router::put (ACE_Message_Block *mb, + ACE_Time_Value *) +{ + // Perform the necessary control operations before passing the + // message down the stream. + + if (mb->msg_type () == ACE_Message_Block::MB_IOCTL) + { + this->control (mb); + return this->put_next (mb); + } + + // If we're the reader then we're responsible for broadcasting + // messages to Consumers. + + else if (this->is_reader ()) + { + if (this->context ()->send_peers (mb) == -1) + ACE_ERROR_RETURN + ((LM_ERROR, + ACE_TEXT ("(%t) send_peers failed in Consumer_Router\n")), + -1); + else + return 0; + } + else // if (this->is_writer ()) + + // Queue up the message to processed by <Consumer_Router::svc> + // Since we don't expect to be getting many of these messages, we + // queue them up and run them in a separate thread to avoid taxing + // the main thread. + return this->putq (mb); +} + +// Return information about the <Consumer_Router>. +#if defined (ACE_WIN32) || !defined (ACE_USES_WCHAR) +# define FMTSTR ACE_TEXT ("%s\t %d/%s %s (%s)\n") +#else +# define FMTSTR ACE_TEXT ("%ls\t %d/%ls %ls (%ls)\n") +#endif /* ACE_WIN32 || !ACE_USES_WCHAR */ + +int +Consumer_Router::info (ACE_TCHAR **strp, size_t length) const +{ + ACE_TCHAR buf[BUFSIZ]; + ACE_INET_Addr addr; + const ACE_TCHAR *mod_name = this->name (); + + if (this->context ()->acceptor ().get_local_addr (addr) == -1) + return -1; + + ACE_OS::sprintf (buf, + FMTSTR, + mod_name, + addr.get_port_number (), + ACE_TEXT ("tcp"), + ACE_TEXT ("# consumer router"), + this->is_reader () ? ACE_TEXT ("reader") : ACE_TEXT ("writer")); + if (*strp == 0 && (*strp = ACE_OS::strdup (mod_name)) == 0) + return -1; + else + ACE_OS::strncpy (*strp, mod_name, length); + + return ACE_OS::strlen (mod_name); +} diff --git a/ACE/examples/ASX/Event_Server/Event_Server/Consumer_Router.h b/ACE/examples/ASX/Event_Server/Event_Server/Consumer_Router.h new file mode 100644 index 00000000000..062a07116ea --- /dev/null +++ b/ACE/examples/ASX/Event_Server/Event_Server/Consumer_Router.h @@ -0,0 +1,71 @@ +/* -*- C++ -*- */ +// $Id$ + +#ifndef _CONSUMER_ROUTER_H +#define _CONSUMER_ROUTER_H + +#include "ace/SOCK_Acceptor.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/UPIPE_Acceptor.h" +#include "ace/Svc_Handler.h" +#include "ace/RW_Thread_Mutex.h" +#include "Peer_Router.h" + +class Consumer_Router : public Peer_Router +{ + // = TITLE + // Provides the interface between one or more Consumers and the + // Event Server <ACE_Stream>. + // + // = DESCRIPTION + // This class normally sits on "top" of the Stream and routes + // messages coming from "downstream" to all the Consumers + // connected to it via its "read" <Task>. Normally, the messages + // flow up the stream from <Supplier_Router>s. However, if + // Consumers transmit data to the <Consumer_Router>, we dutifully + // push it out to the Suppliers via the <Supplier_Router>. + // + // When used on the "reader" side of a Stream, the + // <Consumer_Router> simply forwards all messages up the stream. + // When used on the "writer" side, the <Consumer_Router> queues + // up outgoing messages to suppliers and sends them down to the + // <Supplier_Router> in a separate thread. The reason for this + // is that it's really an "error" for a <Consumer_Router> to + // send messages to Suppliers, so we don't expect this to happen + // very much. When it does we use a separate thread to avoid + // taxing the main thread, which processes "normal" messages. + // + // All of the methods in this class except the constructor are + // called via base class pointers by the <ACE_Stream>. + // Therefore, we can put them in the protected section. +public: + Consumer_Router (Peer_Router_Context *prc); + // Initialization method. + +protected: + // = ACE_Task hooks. + virtual int open (void *a = 0); + // Called by the Stream to initialize the router. + + virtual int close (u_long flags = 0); + // Called by the Stream to shutdown the router. + + virtual int put (ACE_Message_Block *msg, ACE_Time_Value * = 0); + // Called by the <Peer_Handler> to pass a message to the + // <Consumer_Router>. The <Consumer_Router> queues up this message, + // which is then processed in the <svc> method in a separate thread. + + virtual int svc (void); + // Runs in a separate thread to dequeue messages and pass them up + // the stream. + + // = Dynamic linking hooks. + virtual int info (ACE_TCHAR **info_string, size_t length) const; + // Returns information about this service. +}; + +#endif /* _CONSUMER_ROUTER_H */ diff --git a/ACE/examples/ASX/Event_Server/Event_Server/Event.mpc b/ACE/examples/ASX/Event_Server/Event_Server/Event.mpc new file mode 100644 index 00000000000..f99e912ce04 --- /dev/null +++ b/ACE/examples/ASX/Event_Server/Event_Server/Event.mpc @@ -0,0 +1,15 @@ +// -*- MPC -*- +// $Id$ + +project(*Server) : aceexe { + avoids += ace_for_tao + exename = Event_Server + Source_Files { + Consumer_Router.cpp + Event_Analyzer.cpp + Options.cpp + Peer_Router.cpp + Supplier_Router.cpp + event_server.cpp + } +} diff --git a/ACE/examples/ASX/Event_Server/Event_Server/Event_Analyzer.cpp b/ACE/examples/ASX/Event_Server/Event_Server/Event_Analyzer.cpp new file mode 100644 index 00000000000..a064da6459a --- /dev/null +++ b/ACE/examples/ASX/Event_Server/Event_Server/Event_Analyzer.cpp @@ -0,0 +1,80 @@ +// $Id$ + +#include "ace/OS_NS_string.h" +#include "Options.h" +#include "Event_Analyzer.h" + +ACE_RCSID(Event_Server, Event_Analyzer, "$Id$") + +int +Event_Analyzer::open (void *) +{ + // No-op for now... + return 0; +} + +int +Event_Analyzer::close (u_long) +{ + // No-op for now... + return 0; +} + +int +Event_Analyzer::control (ACE_Message_Block *mb) +{ + ACE_IO_Cntl_Msg *ioc = (ACE_IO_Cntl_Msg *) mb->rd_ptr (); + ACE_IO_Cntl_Msg::ACE_IO_Cntl_Cmds cmd; + + switch (cmd = ioc->cmd ()) + { + case ACE_IO_Cntl_Msg::SET_LWM: + case ACE_IO_Cntl_Msg::SET_HWM: + this->water_marks (cmd, *(size_t *) mb->cont ()->rd_ptr ()); + break; + default: + break; + } + return 0; +} + +int +Event_Analyzer::put (ACE_Message_Block *mb, ACE_Time_Value *) +{ + if (Options::instance ()->debug ()) + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%t) passing through Event_Analyser::put() (%s)\n"), + this->is_reader () ? ACE_TEXT ("reader") : ACE_TEXT ("writer"))); + + if (mb->msg_type () == ACE_Message_Block::MB_IOCTL) + this->control (mb); + + // Just pass the message along to the next Module in the stream... + return this->put_next (mb); +} + +int +Event_Analyzer::init (int, ACE_TCHAR *[]) +{ + // No-op for now. + return 0; +} + +int +Event_Analyzer::fini (void) +{ + // No-op for now. + return 0; +} + +int +Event_Analyzer::info (ACE_TCHAR **strp, size_t length) const +{ + const ACE_TCHAR *mod_name = this->name (); + + if (*strp == 0 && (*strp = ACE_OS::strdup (mod_name)) == 0) + return -1; + else + ACE_OS::strncpy (*strp, mod_name, length); + return ACE_OS::strlen (mod_name); +} diff --git a/ACE/examples/ASX/Event_Server/Event_Server/Event_Analyzer.h b/ACE/examples/ASX/Event_Server/Event_Server/Event_Analyzer.h new file mode 100644 index 00000000000..d4f88c8b68d --- /dev/null +++ b/ACE/examples/ASX/Event_Server/Event_Server/Event_Analyzer.h @@ -0,0 +1,44 @@ +/* -*- C++ -*- */ +// $Id$ + +#ifndef _EVENT_ANALYZER_H +#define _EVENT_ANALYZER_H + +#include "ace/Stream.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Module.h" +#include "ace/Task.h" + +class Event_Analyzer : public ACE_Task<ACE_SYNCH> +{ + // = TITLE + // This class forwards all the <ACE_Message_Block>s it receives + // onto its neighboring Module in the Stream. + // + // = DESCRIPTION + // In a "real" event service, application-specific processing + // would be done in the <put> (or <svc>) method in this class. +public: + // = Initialization hooks called by <ACE_Stream> (not used). + virtual int open (void *a = 0); + virtual int close (u_long flags = 0); + + virtual int put (ACE_Message_Block *msg, + ACE_Time_Value * = 0); + // Entry point into this task. + + // Dynamic linking hooks (not used). + virtual int init (int argc, ACE_TCHAR *argv[]); + virtual int fini (void); + virtual int info (ACE_TCHAR **info_string, + size_t length) const; +private: + virtual int control (ACE_Message_Block *); + // Implements the watermark control processing. +}; + +#endif /* _EVENT_ANALYZER_H */ diff --git a/ACE/examples/ASX/Event_Server/Event_Server/Makefile.am b/ACE/examples/ASX/Event_Server/Event_Server/Makefile.am new file mode 100644 index 00000000000..5e17126f991 --- /dev/null +++ b/ACE/examples/ASX/Event_Server/Event_Server/Makefile.am @@ -0,0 +1,49 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +ACE_BUILDDIR = $(top_builddir) +ACE_ROOT = $(top_srcdir) + + +## Makefile.Event_Server.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS = Event_Server + +Event_Server_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +Event_Server_SOURCES = \ + Consumer_Router.cpp \ + Event_Analyzer.cpp \ + Options.cpp \ + Peer_Router.cpp \ + Supplier_Router.cpp \ + event_server.cpp \ + Consumer_Router.h \ + Event_Analyzer.h \ + Options.h \ + Options.i \ + Peer_Router.h \ + Supplier_Router.h + +Event_Server_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Clean up template repositories, etc. +clean-local: + -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.* + -rm -f gcctemp.c gcctemp so_locations *.ics + -rm -rf cxx_repository ptrepository ti_files + -rm -rf templateregistry ir.out + -rm -rf ptrepository SunWS_cache Templates.DB diff --git a/ACE/examples/ASX/Event_Server/Event_Server/Options.cpp b/ACE/examples/ASX/Event_Server/Event_Server/Options.cpp new file mode 100644 index 00000000000..6ef846f2f31 --- /dev/null +++ b/ACE/examples/ASX/Event_Server/Event_Server/Options.cpp @@ -0,0 +1,206 @@ +// $Id$ + +#include "ace/Get_Opt.h" +#include "ace/Thread.h" +#include "ace/Log_Msg.h" +#include "ace/OS_NS_stdio.h" +#if defined (ACE_HAS_TRACE) +# include "ace/OS_NS_strings.h" +#endif /* ACE_HAS_TRACE */ + +#include "Options.h" + +ACE_RCSID(Event_Server, Options, "$Id$") + +/* static */ +Options *Options::instance_ = 0; + +Options * +Options::instance (void) +{ + if (Options::instance_ == 0) + Options::instance_ = new Options; + + return Options::instance_; +} + +Options::Options (void) + : thr_count_ (4), + t_flags_ (0), + high_water_mark_ (8 * 1024), + low_water_mark_ (1024), + message_size_ (128), + initial_queue_length_ (0), + iterations_ (100000), + debugging_ (0), + verbosity_ (0), + consumer_port_ (ACE_DEFAULT_SERVER_PORT), + supplier_port_ (ACE_DEFAULT_SERVER_PORT + 1) +{ +} + +Options::~Options (void) +{ +} + +void Options::print_results (void) +{ +#if !defined (ACE_WIN32) + ACE_Profile_Timer::ACE_Elapsed_Time et; + + this->itimer_.elapsed_time (et); + + if (this->verbose ()) + { +#if defined (ACE_HAS_PRUSAGE_T) + ACE_Profile_Timer::Rusage rusage; + this->itimer_.get_rusage (rusage); + + ACE_OS::printf ("final concurrency hint = %d\n", ACE_Thread::getconcurrency ()); + ACE_OS::printf ("%8d = lwpid\n" + "%8d = lwp count\n" + "%8d = minor page faults\n" + "%8d = major page faults\n" + "%8d = input blocks\n" + "%8d = output blocks\n" + "%8d = messages sent\n" + "%8d = messages received\n" + "%8d = signals received\n" + "%8ds, %dms = wait-cpu (latency) time\n" + "%8ds, %dms = user lock wait sleep time\n" + "%8ds, %dms = all other sleep time\n" + "%8d = voluntary context switches\n" + "%8d = involuntary context switches\n" + "%8d = system calls\n" + "%8d = chars read/written\n", + (int) rusage.pr_lwpid, + (int) rusage.pr_count, + (int) rusage.pr_minf, + (int) rusage.pr_majf, + (int) rusage.pr_inblk, + (int) rusage.pr_oublk, + (int) rusage.pr_msnd, + (int) rusage.pr_mrcv, + (int) rusage.pr_sigs, + (int) rusage.pr_wtime.tv_sec, (int) rusage.pr_wtime.tv_nsec / 1000000, + (int) rusage.pr_ltime.tv_sec, (int) rusage.pr_ltime.tv_nsec / 1000000, + (int) rusage.pr_slptime.tv_sec, (int) rusage.pr_slptime.tv_nsec / 1000000, + (int) rusage.pr_vctx, + (int) rusage.pr_ictx, + (int) rusage.pr_sysc, + (int) rusage.pr_ioch); +#else + /* Someone needs to write the corresponding dump for rusage... */ +#endif /* ACE_HAS_PRUSAGE_T */ + } + + ACE_OS::printf ("---------------------\n" + "real time = %.3f\n" + "user time = %.3f\n" + "system time = %.3f\n" + "---------------------\n", + et.real_time, et.user_time, et.system_time); +#endif /* ACE_WIN32 */ +} + +void +Options::parse_args (int argc, ACE_TCHAR *argv[]) +{ + ACE_LOG_MSG->open (argv[0]); + + ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("c:bdH:i:L:l:M:ns:t:T:v")); + int c; + + while ((c = get_opt ()) != EOF) + switch (c) + { + case 'b': + this->t_flags (THR_BOUND); + break; + case 'c': + this->consumer_port (ACE_OS::atoi (get_opt.opt_arg ())); + break; + case 'd': + this->debugging_ = 1; + break; + case 'H': + this->high_water_mark (ACE_OS::atoi (get_opt.opt_arg ())); + break; + case 'i': + this->iterations (ACE_OS::atoi (get_opt.opt_arg ())); + break; + case 'L': + this->low_water_mark (ACE_OS::atoi (get_opt.opt_arg ())); + break; + case 'l': + this->initial_queue_length (ACE_OS::atoi (get_opt.opt_arg ())); + break; + case 'M': + this->message_size (ACE_OS::atoi (get_opt.opt_arg ())); + break; + case 'n': + this->t_flags (THR_NEW_LWP); + break; + case 's': + this->supplier_port (ACE_OS::atoi (get_opt.opt_arg ())); + break; + case 'T': +#if defined (ACE_HAS_TRACE) + if (ACE_OS::strcasecmp (get_opt.opt_arg (), ACE_TEXT ("ON")) == 0) + ACE_Trace::start_tracing (); + else if (ACE_OS::strcasecmp (get_opt.opt_arg (), ACE_TEXT ("OFF")) == 0) + ACE_Trace::stop_tracing (); +#endif /* ACE_HAS_TRACE */ + break; + case 't': + this->thr_count (ACE_OS::atoi (get_opt.opt_arg ())); + break; + case 'v': + this->verbosity_ = 1; + break; + default: + ::fprintf (stderr, "%s\n" + "\t[-b] (THR_BOUND)\n" + "\t[-c consumer port]\n" + "\t[-d] (enable debugging)\n" + "\t[-H high water mark]\n" + "\t[-i number of test iterations]\n" + "\t[-L low water mark]\n" + "\t[-M] message size \n" + "\t[-n] (THR_NEW_LWP)\n" + "\t[-q max queue size]\n" + "\t[-s supplier port]\n" + "\t[-t number of threads]\n" + "\t[-v] (verbose) \n", + ACE_TEXT_ALWAYS_CHAR (argv[0])); + ::exit (1); + /* NOTREACHED */ + break; + } + + // This is a major hack to get the size_t format spec to be a narrow + // char, same as the other strings for printf() here. It only works + // because this is the end of the source file. It makes the + // ACE_SIZE_T_FORMAT_SPECIFIER not use ACE_LIB_TEXT, effectively. +#undef ACE_LIB_TEXT +#define ACE_LIB_TEXT(A) A + if (this->verbose ()) + ACE_OS::printf ("%8d = initial concurrency hint\n" + ACE_SIZE_T_FORMAT_SPECIFIER " = total iterations\n" + ACE_SIZE_T_FORMAT_SPECIFIER " = thread count\n" + ACE_SIZE_T_FORMAT_SPECIFIER " = low water mark\n" + ACE_SIZE_T_FORMAT_SPECIFIER " = high water mark\n" + ACE_SIZE_T_FORMAT_SPECIFIER " = message_size\n" + ACE_SIZE_T_FORMAT_SPECIFIER " = initial queue length\n" + "%8d = THR_BOUND\n" + "%8d = THR_NEW_LWP\n", + ACE_Thread::getconcurrency (), + this->iterations (), + this->thr_count (), + this->low_water_mark (), + this->high_water_mark (), + this->message_size (), + this->initial_queue_length (), + (this->t_flags () & THR_BOUND) != 0, + (this->t_flags () & THR_NEW_LWP) != 0); +} diff --git a/ACE/examples/ASX/Event_Server/Event_Server/Options.h b/ACE/examples/ASX/Event_Server/Event_Server/Options.h new file mode 100644 index 00000000000..96e2cad3627 --- /dev/null +++ b/ACE/examples/ASX/Event_Server/Event_Server/Options.h @@ -0,0 +1,122 @@ +/* -*- C++ -*- */ +// $Id$ + +#ifndef OPTIONS_H +#define OPTIONS_H + +#include "ace/config-all.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Profile_Timer.h" + +class Options +{ + // = TITLE + // Option Singleton for Event Server. +public: + static Options *instance (void); + // Singleton access point. + + void parse_args (int argc, ACE_TCHAR *argv[]); + // Parse the command-line arguments and set the options. + + // = Timer management. + void stop_timer (void); + void start_timer (void); + + // = Set/get the number of threads. + void thr_count (size_t count); + size_t thr_count (void); + + // = Set/get the size of the queue. + void initial_queue_length (size_t length); + size_t initial_queue_length (void); + + // = Set/get the high water mark. + void high_water_mark (size_t size); + size_t high_water_mark (void); + + // = Set/get the high water mark. + void low_water_mark (size_t size); + size_t low_water_mark (void); + + // = Set/get the size of a message. + void message_size (size_t size); + size_t message_size (void); + + // = Set/get the number of iterations. + void iterations (size_t n); + size_t iterations (void); + + // Set/get threading flags. + void t_flags (long flag); + long t_flags (void); + + // Set/get supplier port number. + void supplier_port (u_short port); + u_short supplier_port (void); + + // Set/get consumer port number. + void consumer_port (u_short port); + u_short consumer_port (void); + + // Enabled if we're in debugging mode. + int debug (void); + + // Enabled if we're in verbose mode. + int verbose (void); + + // Print the results to the STDERR. + void print_results (void); + +private: + // = Ensure we're a Singleton. + Options (void); + ~Options (void); + + ACE_Profile_Timer itimer_; + // Time the process. + + size_t thr_count_; + // Number of threads to spawn. + + long t_flags_; + // Flags to <thr_create>. + + size_t high_water_mark_; + // ACE_Task high water mark. + + size_t low_water_mark_; + // ACE_Task low water mark. + + size_t message_size_; + // Size of a message. + + size_t initial_queue_length_; + // Initial number of items in the queue. + + size_t iterations_; + // Number of iterations to run the test program. + + int debugging_; + // Extra debugging info. + + int verbosity_; + // Extra verbose messages. + + u_short consumer_port_; + // Port that the Consumer_Router is using. + + u_short supplier_port_; + // Port that the Supplier_Router is using. + + static Options *instance_; + // Static Singleton. + +}; + +#include "Options.i" +#endif /* OPTIONS_H */ diff --git a/ACE/examples/ASX/Event_Server/Event_Server/Options.i b/ACE/examples/ASX/Event_Server/Event_Server/Options.i new file mode 100644 index 00000000000..87ff395c503 --- /dev/null +++ b/ACE/examples/ASX/Event_Server/Event_Server/Options.i @@ -0,0 +1,141 @@ +/* -*- C++ -*- */ +// $Id$ + +/* Option manager for ustreams */ + +// Since this is only included in Options.h these should stay +// inline, not ACE_INLINE. +// FUZZ: disable check_for_inline + +inline void +Options::supplier_port (u_short port) +{ + this->supplier_port_ = port; +} + +inline u_short +Options::supplier_port (void) +{ + return this->supplier_port_; +} + +inline void +Options::consumer_port (u_short port) +{ + this->consumer_port_ = port; +} + +inline u_short +Options::consumer_port (void) +{ + return this->consumer_port_; +} + +inline void +Options::start_timer (void) +{ + this->itimer_.start (); +} + +inline void +Options::stop_timer (void) +{ + this->itimer_.stop (); +} + +inline void +Options::thr_count (size_t count) +{ + this->thr_count_ = count; +} + +inline size_t +Options::thr_count (void) +{ + return this->thr_count_; +} + +inline void +Options::initial_queue_length (size_t length) +{ + this->initial_queue_length_ = length; +} + +inline size_t +Options::initial_queue_length (void) +{ + return this->initial_queue_length_; +} + +inline void +Options::high_water_mark (size_t size) +{ + this->high_water_mark_ = size; +} + +inline size_t +Options::high_water_mark (void) +{ + return this->high_water_mark_; +} + +inline void +Options::low_water_mark (size_t size) +{ + this->low_water_mark_ = size; +} + +inline size_t +Options::low_water_mark (void) +{ + return this->low_water_mark_; +} + +inline void +Options::message_size (size_t size) +{ + this->message_size_ = size; +} + +inline size_t +Options::message_size (void) +{ + return this->message_size_; +} + +inline void +Options::iterations (size_t n) +{ + this->iterations_ = n; +} + +inline size_t +Options::iterations (void) +{ + return this->iterations_; +} + +inline void +Options::t_flags (long flag) +{ + this->t_flags_ |= flag; +} + +inline long +Options::t_flags (void) +{ + return this->t_flags_; +} + +inline int +Options::debug (void) +{ + return this->debugging_; +} + +inline int +Options::verbose (void) +{ + return this->verbosity_; +} + diff --git a/ACE/examples/ASX/Event_Server/Event_Server/Peer_Router.cpp b/ACE/examples/ASX/Event_Server/Event_Server/Peer_Router.cpp new file mode 100644 index 00000000000..cb82eec16df --- /dev/null +++ b/ACE/examples/ASX/Event_Server/Event_Server/Peer_Router.cpp @@ -0,0 +1,435 @@ +// $Id$ + +#if !defined (_PEER_ROUTER_C) +#define _PEER_ROUTER_C + +#include "ace/Service_Config.h" +#include "ace/Get_Opt.h" +#include "Options.h" +#include "Peer_Router.h" + +ACE_RCSID(Event_Server, Peer_Router, "$Id$") + +// Send the <ACE_Message_Block> to all the peers. Note that in a +// "real" application this logic would most likely be more selective, +// i.e., it would actually do "routing" based on addressing +// information passed in the <ACE_Message_Block>. + +int +Peer_Router_Context::send_peers (ACE_Message_Block *mb) +{ + PEER_ITERATOR map_iter = this->peer_map_; + int bytes = 0; + int iterations = 0; + + // Skip past the header and get the message to send. + ACE_Message_Block *data_block = mb->cont (); + + // Use an iterator to "multicast" the data to *all* the registered + // peers. Note that this doesn't really multicast, it just makes a + // "logical" copy of the <ACE_Message_Block> and enqueues it in the + // appropriate <Peer_Handler> corresponding to each peer. Note that + // a "real" application would probably "route" the data to a subset + // of connected peers here, rather than send it to all the peers. + + for (PEER_ENTRY *ss = 0; + map_iter.next (ss) != 0; + map_iter.advance ()) + { + if (Options::instance ()->debug ()) + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%t) sending to peer via handle %d\n"), + ss->ext_id_)); + + iterations++; + + // Increment reference count before sending since the + // <Peer_Handler> might be running in its own thread of control. + bytes += ss->int_id_->put (data_block->duplicate ()); + } + + mb->release (); + return bytes == 0 ? 0 : bytes / iterations; +} + +// Remove the <Peer_Handler> from the peer connection map. + +int +Peer_Router_Context::unbind_peer (ROUTING_KEY key) +{ + return this->peer_map_.unbind (key); +} + +// Add the <Peer_Handler> to the peer connection map. + +int +Peer_Router_Context::bind_peer (ROUTING_KEY key, + Peer_Handler *peer_handler) +{ + return this->peer_map_.bind (key, peer_handler); +} + +void +Peer_Router_Context::duplicate (void) +{ + this->reference_count_++; +} + +void +Peer_Router_Context::release (void) +{ + ACE_ASSERT (this->reference_count_ > 0); + this->reference_count_--; + + if (this->reference_count_ == 0) + delete this; +} + +Peer_Router_Context::Peer_Router_Context (u_short port) + : reference_count_ (0) +{ + // Initialize the Acceptor's "listen-mode" socket. + ACE_INET_Addr endpoint (port); + if (this->open (endpoint) == -1) + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("Acceptor::open"))); + + // Initialize the connection map. + else if (this->peer_map_.open () == -1) + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("Map_Manager::open"))); + else + { + ACE_INET_Addr addr; + + if (this->acceptor ().get_local_addr (addr) != -1) + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%t) initializing %C on port = %d, handle = %d, this = %u\n"), + addr.get_port_number () == Options::instance ()->supplier_port () + ? "Supplier_Handler" : "Consumer_Handler", + addr.get_port_number (), + this->acceptor().get_handle (), + this)); + else + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("get_local_addr"))); + } +} + +Peer_Router_Context::~Peer_Router_Context (void) +{ + // Free up the handle and close down the listening socket. + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%t) closing down Peer_Router_Context\n"))); + + // Close down the Acceptor and take ourselves out of the Reactor. + this->handle_close (); + + PEER_ITERATOR map_iter = this->peer_map_; + + // Make sure to take all the handles out of the map to avoid + // "resource leaks." + + for (PEER_ENTRY *ss = 0; + map_iter.next (ss) != 0; + map_iter.advance ()) + { + if (Options::instance ()->debug ()) + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%t) closing down peer on handle %d\n"), + ss->ext_id_)); + + if (ACE_Reactor::instance ()->remove_handler + (ss->ext_id_, + ACE_Event_Handler::READ_MASK) == -1) + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("(%t) p\n"), + ACE_TEXT ("remove_handle"))); + } + + // Close down the map. + this->peer_map_.close (); +} + +Peer_Router * +Peer_Router_Context::peer_router (void) +{ + return this->peer_router_; +} + +void +Peer_Router_Context::peer_router (Peer_Router *pr) +{ + this->peer_router_ = pr; +} + +// Factory Method that creates a new <Peer_Handler> for each +// connection. + +int +Peer_Router_Context::make_svc_handler (Peer_Handler *&sh) +{ + ACE_NEW_RETURN (sh, + Peer_Handler (this), + -1); + return 0; +} + +Peer_Handler::Peer_Handler (Peer_Router_Context *prc) + : peer_router_context_ (prc) +{ +} + +// Send output to a peer. Note that this implementation "blocks" if +// flow control occurs. This is undesirable for "real" applications. +// The best way around this is to make the <Peer_Handler> an Active +// Object, e.g., as done in the $ACE_ROOT/apps/Gateway/Gateway +// application. + +int +Peer_Handler::put (ACE_Message_Block *mb, + ACE_Time_Value *tv) +{ +#if 0 + // If we're running as Active Objects just enqueue the message here. + return this->putq (mb, tv); +#else + ACE_UNUSED_ARG (tv); + + int result = this->peer ().send_n (mb->rd_ptr (), + mb->length ()); + // Release the memory. + mb->release (); + + return result; +#endif /* 0 */ +} + +// Initialize a newly connected handler. + +int +Peer_Handler::open (void *) +{ + ACE_TCHAR buf[BUFSIZ], *p = buf; + + if (this->peer_router_context_->peer_router ()->info (&p, + sizeof buf) != -1) + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%t) creating handler for %s, handle = %d\n"), + buf, + this->get_handle ())); + else + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("info")), + -1); +#if 0 + // If we're running as an Active Object activate the Peer_Handler + // here. + if (this->activate (Options::instance ()->t_flags ()) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("activation of thread failed")), + -1); + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%t) Peer_Handler::open registering with Reactor for handle_input\n"))); +#else + + // Register with the Reactor to receive messages from our Peer. + if (ACE_Reactor::instance ()->register_handler + (this, ACE_Event_Handler::READ_MASK) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("register_handler")), + -1); +#endif /* 0 */ + + // Insert outselves into the routing map. + else if (this->peer_router_context_->bind_peer (this->get_handle (), + this) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("bind_peer")), + -1); + else + return 0; +} + +// Receive a message from a Peer. + +int +Peer_Handler::handle_input (ACE_HANDLE h) +{ + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%t) input arrived on handle %d\n"), + h)); + + ACE_Message_Block *db; + + ACE_NEW_RETURN (db, ACE_Message_Block (BUFSIZ), -1); + + ACE_Message_Block *hb = new ACE_Message_Block (sizeof (ROUTING_KEY), + ACE_Message_Block::MB_PROTO, db); + // Check for memory failures. + if (hb == 0) + { + db->release (); + errno = ENOMEM; + return -1; + } + + ssize_t n = this->peer ().recv (db->rd_ptr (), + db->size ()); + + if (n == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p"), + ACE_TEXT ("recv failed")), + -1); + else if (n == 0) // Client has closed down the connection. + { + if (this->peer_router_context_->unbind_peer (this->get_handle ()) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p"), + ACE_TEXT ("unbind failed")), + -1); + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%t) shutting down handle %d\n"), h)); + // Instruct the <ACE_Reactor> to deregister us by returning -1. + return -1; + } + else + { + // Transform incoming buffer into an <ACE_Message_Block>. + + // First, increment the write pointer to the end of the newly + // read data block. + db->wr_ptr (n); + + // Second, copy the "address" into the header block. Note that + // for this implementation the HANDLE we receive the message on + // is considered the "address." A "real" application would want + // to do something more sophisticated. + *(ACE_HANDLE *) hb->rd_ptr () = this->get_handle (); + + // Third, update the write pointer in the header block. + hb->wr_ptr (sizeof (ACE_HANDLE)); + + // Finally, pass the message through the stream. Note that we + // use <Task::put> here because this gives the method at *our* + // level in the stream a chance to do something with the message + // before it is sent up the other side. For instance, if we + // receive messages in the <Supplier_Router>, it will just call + // <put_next> and send them up the stream to the + // <Consumer_Router> (which broadcasts them to consumers). + // However, if we receive messages in the <Consumer_Router>, it + // could reply to the Consumer with an error since it's not + // correct for Consumers to send messages (we don't do this in + // the current implementation, but it could be done in a "real" + // application). + + if (this->peer_router_context_->peer_router ()->put (hb) == -1) + return -1; + else + return 0; + } +} + +Peer_Router::Peer_Router (Peer_Router_Context *prc) + : peer_router_context_ (prc) +{ +} + +Peer_Router_Context * +Peer_Router::context (void) const +{ + return this->peer_router_context_; +} + +int +Peer_Router::control (ACE_Message_Block *mb) +{ + ACE_IO_Cntl_Msg *ioc = (ACE_IO_Cntl_Msg *) mb->rd_ptr (); + ACE_IO_Cntl_Msg::ACE_IO_Cntl_Cmds command; + + switch (command = ioc->cmd ()) + { + case ACE_IO_Cntl_Msg::SET_LWM: + case ACE_IO_Cntl_Msg::SET_HWM: + this->water_marks (command, *(size_t *) mb->cont ()->rd_ptr ()); + break; + default: + return -1; + } + return 0; +} + +#if 0 + +// Right now, Peer_Handlers are purely Reactive, i.e., they all run in +// a single thread of control. It would be easy to make them Active +// Objects by calling activate() in Peer_Handler::open(), making +// Peer_Handler::put() enqueue each message on the message queue, and +// (3) then running the following svc() routine to route each message +// to its final destination within a separate thread. Note that we'd +// want to move the svc() call up to the Consumer_Router and +// Supplier_Router level in order to get the right level of control +// for input and output. + +Peer_Handler::svc (void) +{ + ACE_Message_Block *db, *hb; + + // Do an endless loop + for (;;) + { + db = new Message_Block (BUFSIZ); + hb = new Message_Block (sizeof (ROUTING_KEY), + Message_Block::MB_PROTO, + db); + + ssize_t n = this->peer_.recv (db->rd_ptr (), db->size ()); + + if (n == -1) + LM_ERROR_RETURN ((LOG_ERROR, + ACE_TEXT ("%p"), + ACE_TEXT ("recv failed")), + -1); + else if (n == 0) // Client has closed down the connection. + { + if (this->peer_router_context_->peer_router ()->unbind_peer (this->get_handle ()) == -1) + LM_ERROR_RETURN ((LOG_ERROR, + ACE_TEXT ("%p"), + ACE_TEXT ("unbind failed")), + -1); + LM_DEBUG ((LOG_DEBUG, + ACE_TEXT ("(%t) shutting down \n"))); + + // We do not need to be deregistered by reactor + // as we were not registered at all. + return -1; + } + else + { + // Transform incoming buffer into a Message. + db->wr_ptr (n); + *(long *) hb->rd_ptr () = this->get_handle (); // Structure assignment. + hb->wr_ptr (sizeof (long)); + + // Pass the message to the stream. + if (this->peer_router_context_->peer_router ()->reply (hb) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("(%t) %p\n"), + ACE_TEXT ("Peer_Handler.svc : peer_router->reply failed")), + -1); + } + } + return 0; +} +#endif /* 0 */ +#endif /* _PEER_ROUTER_C */ + diff --git a/ACE/examples/ASX/Event_Server/Event_Server/Peer_Router.h b/ACE/examples/ASX/Event_Server/Event_Server/Peer_Router.h new file mode 100644 index 00000000000..044ef07ea07 --- /dev/null +++ b/ACE/examples/ASX/Event_Server/Event_Server/Peer_Router.h @@ -0,0 +1,158 @@ +/* -*- C++ -*- */ +// $Id$ + +#ifndef _PEER_ROUTER_H +#define _PEER_ROUTER_H + +#include "ace/Acceptor.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/SOCK_Acceptor.h" +#include "ace/Svc_Handler.h" +#include "ace/Map_Manager.h" +#include "ace/RW_Thread_Mutex.h" + +// Type of search key for CONSUMER_MAP +typedef ACE_HANDLE ROUTING_KEY; + +// Forward declarations. +class Peer_Router; +class Peer_Router_Context; + +class Peer_Handler : public ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_SYNCH> +{ + // = TITLE + // Receive input from a Peer and forward to the appropriate + // <Peer_Router> (i.e., <Consumer_Router> or <Supplier_Router>). +public: + Peer_Handler (Peer_Router_Context * = 0); + // Initialization method. + + virtual int open (void * = 0); + // Called by the ACE_Acceptor::handle_input() to activate this + // object. + + virtual int handle_input (ACE_HANDLE); + // Receive input from a peer. + + virtual int put (ACE_Message_Block *, ACE_Time_Value *tv = 0); + // Send output to a peer. Note that this implementation "blocks" if + // flow control occurs. This is undesirable for "real" + // applications. The best way around this is to make the + // <Peer_Handler> an Active Object, e.g., as done in the + // $ACE_ROOT/apps/Gateway/Gateway application. + +protected: + Peer_Router_Context *peer_router_context_; + // Pointer to router context. This maintains the state that is + // shared by both Tasks in a <Peer_Router> Module. +}; + +class Peer_Router_Context : public ACE_Acceptor<Peer_Handler, ACE_SOCK_ACCEPTOR> +{ + // = TITLE + // Defines state and behavior shared between both Tasks in a + // <Peer_Router> Module. + // + // = DESCRIPTION + // This class also serves as an <ACE_Acceptor>, which creates + // <Peer_Handlers> when Peers connect. +public: + // = Initialization and termination methods. + Peer_Router_Context (u_short port); + // Constructor. + + virtual int unbind_peer (ROUTING_KEY); + // Remove the <Peer_Handler *> from the <PEER_MAP> that corresponds + // to the <ROUTING_KEY>. + + virtual int bind_peer (ROUTING_KEY, Peer_Handler *); + // Add a <Peer_Handler> to the <PEER_MAP> that's associated with the + // <ROUTING_KEY>. + + int send_peers (ACE_Message_Block *mb); + // Send the <ACE_Message_Block> to all the peers. Note that in a + // "real" application this logic would most likely be more + // selective, i.e., it would actually do "routing" based on + // addressing information passed in the <ACE_Message_Block>. + + int make_svc_handler (Peer_Handler *&sh); + // Factory Method that creates a new <Peer_Handler> for each + // connection. This method overrides the default behavior in + // <ACE_Acceptor>. + + // = Set/Get Router Task. + Peer_Router *peer_router (void); + void peer_router (Peer_Router *); + + void release (void); + // Decrement the reference count and delete <this> when count == 0; + + void duplicate (void); + // Increment the reference count. + +private: + Peer_Router *peer_router_; + // Pointer to the <Peer_Router> that we are accepting for. + + // = Useful typedefs. + typedef ACE_Map_Manager <ROUTING_KEY, Peer_Handler *, ACE_SYNCH_RW_MUTEX> + PEER_MAP; + typedef ACE_Map_Iterator<ROUTING_KEY, Peer_Handler *, ACE_SYNCH_RW_MUTEX> + PEER_ITERATOR; + typedef ACE_Map_Entry<ROUTING_KEY, Peer_Handler *> + PEER_ENTRY; + + PEER_MAP peer_map_; + // Map used to keep track of active peers. + + int reference_count_; + // Keep track of when we can delete ourselves. + + ~Peer_Router_Context (void); + // Private to ensure dynamic allocation. + + friend class Friend_Of_Peer_Router_Context; + // Declare a friend class to avoid compiler warnings because the + // destructor is private. +}; + +class Peer_Router : public ACE_Task<ACE_SYNCH> +{ + // = TITLE + // This abstract base class provides mechanisms for routing + // messages to/from a <ACE_Stream> from/to one or more peers (which + // are typically running on remote hosts). + // + // = DESCRIPTION + // Subclasses of <Peer_Router> (such as <Consumer_Router> or + // <Supplier_Router>) override the <open>, <close>, and + // <put> methods to specialize the behavior of the router to + // meet application-specific requirements. +protected: + Peer_Router (Peer_Router_Context *prc); + // Initialization method. + + virtual int control (ACE_Message_Block *); + // Handle control messages arriving from adjacent Modules. + + Peer_Router_Context *context (void) const; + // Returns the routing context. + + typedef ACE_Task<ACE_SYNCH> inherited; + // Helpful typedef. + +private: + Peer_Router_Context *peer_router_context_; + // Reference to the context shared by the writer and reader Tasks, + // e.g., in the <Consumer_Router> and <Supplier_Router> Modules. + + // = Prevent copies and pass-by-value. + Peer_Router (const Peer_Router &); + void operator= (const Peer_Router &); +}; + +#endif /* _PEER_ROUTER_H */ diff --git a/ACE/examples/ASX/Event_Server/Event_Server/Supplier_Router.cpp b/ACE/examples/ASX/Event_Server/Event_Server/Supplier_Router.cpp new file mode 100644 index 00000000000..72c43ee6312 --- /dev/null +++ b/ACE/examples/ASX/Event_Server/Event_Server/Supplier_Router.cpp @@ -0,0 +1,165 @@ +// $Id$ + +#include "ace/os_include/os_assert.h" +#include "ace/OS_NS_stdio.h" +#include "ace/OS_NS_string.h" +#include "Supplier_Router.h" +#include "Options.h" + +ACE_RCSID(Event_Server, Supplier_Router, "$Id$") + +// Handle outgoing messages in a separate thread. + +int +Supplier_Router::svc (void) +{ + assert (this->is_writer ()); + + ACE_DEBUG ((LM_DEBUG, "(%t) starting svc in Supplier_Router\n")); + + for (ACE_Message_Block *mb = 0; + this->getq (mb) >= 0; + ) + { + ACE_DEBUG ((LM_DEBUG, + "(%t) warning: Supplier_Router is " + "forwarding a message via send_peers\n")); + + // Broadcast the message to the Suppliers, even though this is + // "incorrect" (assuming a oneway flow of events from Suppliers + // to Consumers)! + + if (this->context ()->send_peers (mb) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "(%t) send_peers failed in Supplier_Router\n"), + -1); + } + + ACE_DEBUG ((LM_DEBUG, + "(%t) stopping svc in Supplier_Router\n")); + return 0; +} + +Supplier_Router::Supplier_Router (Peer_Router_Context *prc) + : Peer_Router (prc) +{ + // Increment the reference count. + this->context ()->duplicate (); +} + +// Initialize the Supplier Router. + +int +Supplier_Router::open (void *) +{ + if (this->is_reader ()) + { + // Set the <Peer_Router_Context> to point back to us so that all + // the Peer_Handler's <put> their incoming <Message_Blocks> to + // our reader Task. + this->context ()->peer_router (this); + return 0; + } + + else // if (this->is_writer () + { + // Increment the reference count. + this->context ()->duplicate (); + + // Make this an active object to handle the error cases in a + // separate thread. + return this->activate (Options::instance ()->t_flags ()); + } +} + +// Close down the router. + +int +Supplier_Router::close (u_long) +{ + ACE_DEBUG ((LM_DEBUG, + "(%t) closing Supplier_Router %s\n", + this->is_reader () ? "reader" : "writer")); + + if (this->is_writer ()) + // Inform the thread to shut down. + this->msg_queue ()->deactivate (); + + // Both writer and reader call release(), so the context knows when + // to clean itself up. + this->context ()->release (); + return 0; +} + +// Send an <ACE_Message_Block> to the supplier(s). + +int +Supplier_Router::put (ACE_Message_Block *mb, + ACE_Time_Value *) +{ + // Perform the necessary control operations before passing + // the message up the stream. + + if (mb->msg_type () == ACE_Message_Block::MB_IOCTL) + { + this->control (mb); + return this->put_next (mb); + } + + // If we're the reader then we are responsible for pass messages up + // to the next Module's reader Task. Note that in a "real" + // application this is likely where we'd take a look a the actual + // information that was in the message, e.g., in order to figure out + // what operation it was and what it's "parameters" where, etc. + else if (this->is_reader ()) + return this->put_next (mb); + + else // if (this->is_writer ()) + { + // Someone is trying to write to the Supplier. In this + // implementation this is considered an "error." However, we'll + // just go ahead and forward the message to the Supplier (who + // hopefully is prepared to receive it). + ACE_DEBUG ((LM_WARNING, + "(%t) warning: sending to a Supplier\n")); + + // Queue up the message to processed by <Supplier_Router::svc>. + // Since we don't expect to be getting many of these messages, + // we queue them up and run them in a separate thread to avoid + // taxing the main thread. + return this->putq (mb); + } +} + +// Return information about the <Supplier_Router>. +#if defined (ACE_WIN32) || !defined (ACE_USES_WCHAR) +# define FMTSTR ACE_TEXT ("%s\t %d/%s %s (%s)\n") +#else +# define FMTSTR ACE_TEXT ("%ls\t %d/%ls %ls (%ls)\n") +#endif /* ACE_WIN32 || !ACE_USES_WCHAR */ + +int +Supplier_Router::info (ACE_TCHAR **strp, size_t length) const +{ + ACE_TCHAR buf[BUFSIZ]; + ACE_INET_Addr addr; + const ACE_TCHAR *mod_name = this->name (); + + if (this->context ()->acceptor ().get_local_addr (addr) == -1) + return -1; + + ACE_OS::sprintf (buf, + FMTSTR, + mod_name, + addr.get_port_number (), + ACE_TEXT ("tcp"), + ACE_TEXT ("# supplier router"), + this->is_reader () ? + ACE_TEXT ("reader") : ACE_TEXT ("writer")); + if (*strp == 0 && (*strp = ACE_OS::strdup (mod_name)) == 0) + return -1; + else + ACE_OS::strncpy (*strp, mod_name, length); + + return ACE_OS::strlen (mod_name); +} diff --git a/ACE/examples/ASX/Event_Server/Event_Server/Supplier_Router.h b/ACE/examples/ASX/Event_Server/Event_Server/Supplier_Router.h new file mode 100644 index 00000000000..8a42943c147 --- /dev/null +++ b/ACE/examples/ASX/Event_Server/Event_Server/Supplier_Router.h @@ -0,0 +1,72 @@ +/* -*- C++ -*- */ +// $Id$ + +#ifndef _SUPPLIER_ROUTER_H +#define _SUPPLIER_ROUTER_H + +#include "ace/INET_Addr.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/SOCK_Acceptor.h" +#include "ace/Map_Manager.h" +#include "ace/Svc_Handler.h" +#include "Peer_Router.h" + +class Supplier_Router : public Peer_Router +{ + // = TITLE + // Provides the interface between one or more Suppliers and the + // Event Server ACE_Stream. + // + // = DESCRIPTION + // This class normally sits on "bottom" of the Stream and sends + // all messages coming from Suppliers via its "write" <Task> + // "upstream" to all the Consumers connected to the + // <Consumer_Router>. Normally, the messages flow up the + // stream to <Consumer_Router>s. However, if Consumers + // transmit data to the <Consumer_Router>, we dutifully push it + // out to the Suppliers via the <Supplier_Router>. + // + // When used on the "reader" side of a Stream, the + // <Supplier_Router> simply forwards all messages up the stream. + // When used on the "writer" side, the <Supplier_Router> queues + // up outgoing messages to suppliers and sends them in a + // separate thread. The reason for this is that it's really an + // "error" for a <Supplier_Router> to send messages to + // Suppliers, so we don't expect this to happen very much. When + // it does we use a separate thread to avoid taxing the main + // thread, which processes "normal" messages. + // + // All of these methods are called via base class pointers by + // the <ACE_Stream> apparatus. Therefore, we can put them in + // the protected section. +public: + Supplier_Router (Peer_Router_Context *prc); + // Initialization method. + +protected: + // = ACE_Task hooks. + + virtual int open (void *a = 0); + // Called by the Stream to initialize the router. + + virtual int close (u_long flags = 0); + // Called by the Stream to shutdown the router. + + virtual int put (ACE_Message_Block *msg, ACE_Time_Value * = 0); + // Called by the <SUPPLIER_HANDLER> to pass a message to the Router. + // The Router queues up this message, which is then processed in the + // <svc> method in a separate thread. + + virtual int svc (void); + // Runs in a separate thread to dequeue messages and pass them up + // the stream. + + virtual int info (ACE_TCHAR **info_string, size_t length) const; + // Dynamic linking hook. +}; + +#endif /* _SUPPLIER_ROUTER_H */ diff --git a/ACE/examples/ASX/Event_Server/Event_Server/event_server.cpp b/ACE/examples/ASX/Event_Server/Event_Server/event_server.cpp new file mode 100644 index 00000000000..3858bad1fc2 --- /dev/null +++ b/ACE/examples/ASX/Event_Server/Event_Server/event_server.cpp @@ -0,0 +1,258 @@ +// $Id$ + +// Main driver program for the event server example. + +#include "ace/OS_main.h" +#include "ace/Service_Config.h" +#include "ace/OS_NS_unistd.h" +#include "Options.h" +#include "Consumer_Router.h" +#include "Event_Analyzer.h" +#include "Supplier_Router.h" +#include "ace/Sig_Adapter.h" +#include "ace/Stream.h" + +ACE_RCSID (Event_Server, + event_server, + "$Id$") + +// Typedef these components to handle multi-threading correctly. +typedef ACE_Stream<ACE_SYNCH> MT_Stream; +typedef ACE_Module<ACE_SYNCH> MT_Module; + + +class Event_Server : public ACE_Sig_Adapter +{ + // = TITLE + // Run the logic for the <Event_Server>. + + // + // = DESCRIPTION + // In addition to packaging the <Event_Server> components, this + // class also handles SIGINT and terminate the entire + // application process. There are several ways to terminate + // this application process: + // + // 1. Send a SIGINT signal (e.g., via ^C) + // 2. Type any character on the STDIN. + // + // Note that by inheriting from the <ACE_Sig_Adapter> we can + // shutdown the <ACE_Reactor> cleanly when a SIGINT is + // generated. +public: + Event_Server (void); + // Constructor. + + int svc (void); + // Run the event-loop for the event server. + +private: + virtual int handle_input (ACE_HANDLE handle); + // Hook method called back when a user types something into the + // STDIN in order to shut down the program. + + int configure_stream (void); + // Setup the plumbing in the stream. + + int set_watermarks (void); + // Set the high and low queue watermarks. + + int run_event_loop (void); + // Run the event-loop for the <Event_Server>. + + MT_Stream event_server_; + // The <ACE_Stream> that contains the <Event_Server> application + // <Modules>. +}; + +Event_Server::Event_Server (void) + : ACE_Sig_Adapter (ACE_Sig_Handler_Ex (ACE_Reactor::end_event_loop)) + // Shutdown the <ACE_Reactor>'s event loop when a SIGINT is + // received. +{ + // Register to trap STDIN from the user. + if (ACE_Event_Handler::register_stdin_handler (this, + ACE_Reactor::instance (), + ACE_Thread_Manager::instance ()) == -1) + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("register_stdin_handler"))); + // Register to trap the SIGINT signal. + else if (ACE_Reactor::instance ()->register_handler + (SIGINT, this) == -1) + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("register_handler"))); +} + +int +Event_Server::handle_input (ACE_HANDLE) +{ + // This code here will make sure we actually wait for the user to + // type something. On platforms like Win32, <handle_input> is called + // prematurely (even when there is no data). + char temp_buffer [BUFSIZ]; + + ssize_t n = ACE_OS::read (ACE_STDIN, + temp_buffer, + sizeof (temp_buffer)); + // This ought to be > 0, otherwise something very strange has + // happened!! + ACE_ASSERT (n > 0); + ACE_UNUSED_ARG (n); // To avoid compile warning with ACE_NDEBUG. + + Options::instance ()->stop_timer (); + + ACE_DEBUG ((LM_INFO, + ACE_TEXT ("(%t) closing down the test\n"))); + Options::instance ()->print_results (); + + ACE_Reactor::instance ()->end_reactor_event_loop (); + return -1; +} + +int +Event_Server::configure_stream (void) +{ + Peer_Router_Context *src; + // Create the <Supplier_Router>'s routing context. This contains a + // context shared by both the write-side and read-side of the + // <Supplier_Router> Module. + ACE_NEW_RETURN (src, + Peer_Router_Context (Options::instance ()->supplier_port ()), + -1); + + MT_Module *srm = 0; + // Create the <Supplier_Router> module. + ACE_NEW_RETURN (srm, + MT_Module + (ACE_TEXT ("Supplier_Router"), + new Supplier_Router (src), + new Supplier_Router (src)), + -1); + + MT_Module *eam = 0; + // Create the <Event_Analyzer> module. + ACE_NEW_RETURN (eam, + MT_Module + (ACE_TEXT ("Event_Analyzer"), + new Event_Analyzer, + new Event_Analyzer), + -1); + + Peer_Router_Context *crc; + // Create the <Consumer_Router>'s routing context. This contains a + // context shared by both the write-side and read-side of the + // <Consumer_Router> Module. + ACE_NEW_RETURN (crc, + Peer_Router_Context (Options::instance ()->consumer_port ()), + -1); + + MT_Module *crm = 0; + // Create the <Consumer_Router> module. + ACE_NEW_RETURN (crm, + MT_Module + (ACE_TEXT ("Consumer_Router"), + new Consumer_Router (crc), + new Consumer_Router (crc)), + -1); + + // Push the Modules onto the event_server stream. + + if (this->event_server_.push (srm) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("push (Supplier_Router)")), + -1); + else if (this->event_server_.push (eam) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("push (Event_Analyzer)")), + -1); + else if (this->event_server_.push (crm) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("push (Consumer_Router)")), + -1); + return 0; +} + +int +Event_Server::set_watermarks (void) +{ + // Set the high and low water marks appropriately. The water marks + // control how much data can be buffered before the queues are + // considered "full." + size_t wm = Options::instance ()->low_water_mark (); + + if (this->event_server_.control (ACE_IO_Cntl_Msg::SET_LWM, + &wm) == -1) + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), + ACE_TEXT ("push (setting low watermark)")), + -1); + + wm = Options::instance ()->high_water_mark (); + if (this->event_server_.control (ACE_IO_Cntl_Msg::SET_HWM, + &wm) == -1) + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), + ACE_TEXT ("push (setting high watermark)")), + -1); + return 0; +} + +int +Event_Server::run_event_loop (void) +{ + // Begin the timer. + Options::instance ()->start_timer (); + + // Perform the main event loop waiting for the user to type ^C or to + // enter a line on the ACE_STDIN. + + ACE_Reactor::instance ()->run_reactor_event_loop (); + + // Close down the stream and call the <close> hooks on all the + // <ACE_Task>s in the various Modules in the Stream. + this->event_server_.close (); + + // Wait for the threads in the <Consumer_Router> and + // <Supplier_Router> to exit. + return ACE_Thread_Manager::instance ()->wait (); +} + +int +Event_Server::svc (void) +{ + if (this->configure_stream () == -1) + return -1; + else if (this->set_watermarks () == -1) + return -1; + else if (this->run_event_loop () == -1) + return -1; + else + return 0; +} + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ +#if defined (ACE_HAS_THREADS) + Options::instance ()->parse_args (argc, argv); + + // Initialize the <Event_Server>. + Event_Server event_server; + + // Run the event server's event-loop. + int result = event_server.svc (); + + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("exiting main\n"))); + + return result; +#else + ACE_UNUSED_ARG (argc); + ACE_UNUSED_ARG (argv); + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("threads not supported on this platform\n")), + 1); +#endif /* ACE_HAS_THREADS */ +} diff --git a/ACE/examples/ASX/Event_Server/Makefile.am b/ACE/examples/ASX/Event_Server/Makefile.am new file mode 100644 index 00000000000..b337a11860a --- /dev/null +++ b/ACE/examples/ASX/Event_Server/Makefile.am @@ -0,0 +1,14 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +SUBDIRS = \ + Event_Server \ + Transceiver + diff --git a/ACE/examples/ASX/Event_Server/README b/ACE/examples/ASX/Event_Server/README new file mode 100644 index 00000000000..262b7ee9633 --- /dev/null +++ b/ACE/examples/ASX/Event_Server/README @@ -0,0 +1,79 @@ +This subdirectory illustrates a number of the ACE ASX framework +features using an ACE_Stream application called the Event Server. For +more information on the design and use of the ACE ASX framework please +see http://www.cs.wustl.edu/~schmidt/C++-USENIX-94.ps.gz and +http://www.cs.wustl.edu/~schmidt/ACE-concurrency.ps.gz. For more +information on the Event Server, please see +http://www.cs.wustl.edu/~schmidt/DSEJ-94.ps.gz. + +The Event Server example works as follows: + +1. When the ./Event_Server/event_server executable is run it + creates two SOCK_Acceptors, which listen for and accept incoming + connections from Consumers and Suppliers. + +2. The ./Event_Server/Transceiver/transceiver application plays + the role of either a Consumer or a Supplier (with the current + implementation it can only play one role at a time). The + transceiver process can be started multiple times. Each call + should be either: + + # Consumer + % transceiver -p 10002 -h hostname -C + + or + + # Supplier + % transceiver -p 10003 -h hostname -S + + where 10002 and 10003 are the default Consumer listening port and + the Supplier listening port, respectively, on the event server, + "hostname" is the name of the machine the event_server is running, + and -C and -S indicate that the transceiver plays the role of a + Consumer or Supplier, respectively. I typically run the + Consumer(s) and Supplier(s) in different windows to make it easier + to understand the output. + +3. Once the Consumer(s) and Supplier(s) are connected, you can + type data from any Supplier window. This data will be routed + through the Modules/Tasks in the event_server's Stream and be + forwarded to the Consumer(s). + + Since the transceivers are full-duplex you can also send messages + from the Consumer(s) to Supplier(s). However, the Event Server will + warn you about this since it's not really kosher to have Consumers + sending to Suppliers... + +4. When you want to shut down the tranceivers or event server + just type ^C (which generates a SIGINT) or type any input in the + window running the Event Server application. + +What makes this example particularly interesting is that once you've +got the hang of the ASX Streams architecture, you can "push" new +filtering Modules onto the event_server Stream and modify the +application's behavior transparently to the other components. + +There are a bunch of features that aren't implemented in this +prototype that you'd probably want to do for a "real" application. +Some of the more interesting things to add would be: + +0. Complete "full-duplex" support, i.e., Peers could play the + role of Suppliers and Consumers simultaneously. + +1. Support for "commands", which would change the behavior + of the Event_Server based on messages it got from Suppliers + (or Consumers). + +3. Support for "pull" operations, as well as "push" operations. + This would basically involve adding a "MIB Module" to get/set + the "values" associated with "names" passed in by Peers. This + could probably replace the Event_Analysis Module. + +4. Filtering and correlation (this should probably be done + via a separate Module that handles filtering and correlation). + +5. More flexible concurrency model(s), e.g., "Active Object per-Consumer". + This would enable the Event Server process to handle flow control + more gracefully than it does not (it currently "hangs," which isn't + desirable). + diff --git a/ACE/examples/ASX/Event_Server/Transceiver/Makefile.am b/ACE/examples/ASX/Event_Server/Transceiver/Makefile.am new file mode 100644 index 00000000000..9407ab5873b --- /dev/null +++ b/ACE/examples/ASX/Event_Server/Transceiver/Makefile.am @@ -0,0 +1,34 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +ACE_BUILDDIR = $(top_builddir) +ACE_ROOT = $(top_srcdir) + +## Makefile.Transceiver.am +noinst_PROGRAMS = Transceiver + +Transceiver_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +Transceiver_SOURCES = \ + transceiver.cpp \ + transceiver.h + +Transceiver_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Clean up template repositories, etc. +clean-local: + -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.* + -rm -f gcctemp.c gcctemp so_locations *.ics + -rm -rf cxx_repository ptrepository ti_files + -rm -rf templateregistry ir.out + -rm -rf ptrepository SunWS_cache Templates.DB diff --git a/ACE/examples/ASX/Event_Server/Transceiver/Transceiver.mpc b/ACE/examples/ASX/Event_Server/Transceiver/Transceiver.mpc new file mode 100644 index 00000000000..a6a3309727c --- /dev/null +++ b/ACE/examples/ASX/Event_Server/Transceiver/Transceiver.mpc @@ -0,0 +1,9 @@ +// -*- MPC -*- +// $Id$ + +project(*) : aceexe { + exename = Transceiver + Source_Files { + transceiver.cpp + } +} diff --git a/ACE/examples/ASX/Event_Server/Transceiver/transceiver.cpp b/ACE/examples/ASX/Event_Server/Transceiver/transceiver.cpp new file mode 100644 index 00000000000..37bbaad7d3d --- /dev/null +++ b/ACE/examples/ASX/Event_Server/Transceiver/transceiver.cpp @@ -0,0 +1,238 @@ +// $Id$ + +// Test program for the event transceiver. This program can play the +// role of either Consumer or Supplier. You can terminate this +// program by typing ^C.... + +#include "ace/OS_main.h" +#include "ace/OS_NS_string.h" +#include "ace/Service_Config.h" +#include "ace/SOCK_Connector.h" +#include "ace/Connector.h" +#include "ace/Get_Opt.h" +#include "ace/Signal.h" +#include "ace/OS_NS_unistd.h" + +#include "transceiver.h" + +ACE_RCSID (Transceiver, + transceiver, + "$Id$") + +// Handle the command-line arguments. + +int +Event_Transceiver::parse_args (int argc, ACE_TCHAR *argv[]) +{ + ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("Ch:p:S")); + + this->port_number_ = ACE_DEFAULT_SERVER_PORT; + this->host_name_ = ACE_DEFAULT_SERVER_HOST; + this->role_ = ACE_TEXT ("Supplier"); + + for (int c; (c = get_opt ()) != -1; ) + switch (c) + { + case 'C': + this->role_ = ACE_TEXT ("Consumer"); + break; + case 'h': + this->host_name_ = get_opt.opt_arg (); + break; + case 'p': + this->port_number_ = ACE_OS::atoi (get_opt.opt_arg ()); + break; + case 'S': + this->role_ = ACE_TEXT ("Supplier"); + break; + default: + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("usage: %n [-CS] [-h host_name] [-p portnum] \n")), + -1); + /* NOTREACHED */ + break; + } + + // Increment by 1 if we're the supplier to mirror the default + // behavior of the Event_Server (which sets the Consumer port to + // ACE_DEFAULT_SERVER_PORT and the Supplier port to + // ACE_DEFAULT_SERVER_PORT + 1). Note that this is kind of a + // hack... + if (ACE_OS::strcmp (this->role_, ACE_TEXT ("Supplier")) == 0 + && this->port_number_ == ACE_DEFAULT_SERVER_PORT) + this->port_number_++; + return 0; +} + +int +Event_Transceiver::handle_close (ACE_HANDLE, + ACE_Reactor_Mask) +{ + ACE_Reactor::instance ()->end_reactor_event_loop (); + return 0; +} + +// Close down via SIGINT or SIGQUIT. + +int +Event_Transceiver::handle_signal (int, + siginfo_t *, + ucontext_t *) +{ + ACE_Reactor::instance ()->end_reactor_event_loop (); + return 0; +} + +Event_Transceiver::Event_Transceiver (void) +{ +} + +Event_Transceiver::Event_Transceiver (int argc, ACE_TCHAR *argv[]) +{ + if (this->parse_args (argc, argv) == -1) + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("parse_args"))); + else + { + ACE_Sig_Set sig_set; + + sig_set.sig_add (SIGINT); + sig_set.sig_add (SIGQUIT); + + // Register to handle the SIGINT and SIGQUIT signals. + if (ACE_Reactor::instance ()->register_handler + (sig_set, + this) == -1) + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("register_handler"))); + + // We need to register <this> here before we're connected since + // otherwise <get_handle> will return the connection socket + // handle for the peer. + else if (ACE_Event_Handler::register_stdin_handler (this, + ACE_Reactor::instance (), + ACE_Thread_Manager::instance ()) == -1) + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("register_stdin_handler"))); + + // Address of the server. + ACE_INET_Addr server_addr (this->port_number_, + this->host_name_); + + ACE_Connector<Event_Transceiver, ACE_SOCK_CONNECTOR> connector; + + // We need a pointer here because connect takes a reference to a + // pointer! + Event_Transceiver *etp = this; + + // Establish the connection to the Event Server. + if (connector.connect (etp, + server_addr) == -1) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("%p\n"), + this->host_name_)); + ACE_Reactor::instance()->remove_handler (sig_set); + ACE_Event_Handler::remove_stdin_handler (ACE_Reactor::instance(), + ACE_Thread_Manager::instance()); + } + } +} + +int +Event_Transceiver::open (void *) +{ + // Register ourselves to be notified when there's data to read on + // the socket. + if (ACE_Reactor::instance ()->register_handler + (this, + ACE_Event_Handler::READ_MASK) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("register_handler")), + -1); + return 0; +} + +int +Event_Transceiver::handle_input (ACE_HANDLE handle) +{ + // Determine whether we play the role of a consumer or a supplier. + if (handle == ACE_STDIN) + return this->transmitter (); + else + return this->receiver (); +} + +int +Event_Transceiver::transmitter (void) +{ + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) entering %s transmitter\n"), + this->role_)); + + char buf[BUFSIZ]; + ssize_t n = ACE_OS::read (ACE_STDIN, buf, sizeof buf); + int result = 0; + + if (n <= 0 || this->peer ().send_n (buf, n) != n) + result = -1; + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) leaving %s transmitter\n"), + this->role_)); + return result; +} + +int +Event_Transceiver::receiver (void) +{ + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) entering %s receiver\n"), + this->role_)); + + char buf[BUFSIZ]; + + ssize_t n = this->peer ().recv (buf, sizeof buf); + int result = 0; + + if (n <= 0 + || ACE_OS::write (ACE_STDOUT, buf, n) != n) + result = -1; + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) leaving %s receiver\n"), + this->role_)); + return result; +} + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + if (ACE_Service_Config::open (argv[0]) == -1 + && errno != ENOENT) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("open")), + -1); + + // Create and initialize the transceiver. + Event_Transceiver transceiver (argc, argv); + + // Demonstrate how we can check if a constructor failed... + if (ACE_LOG_MSG->op_status () == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("Event_Transceiver constructor failed")), + -1); + + + // Run event loop until either the event server shuts down or we get + // a SIGINT. + ACE_Reactor::instance ()->run_reactor_event_loop (); + return 0; +} + diff --git a/ACE/examples/ASX/Event_Server/Transceiver/transceiver.h b/ACE/examples/ASX/Event_Server/Transceiver/transceiver.h new file mode 100644 index 00000000000..864b88a0b48 --- /dev/null +++ b/ACE/examples/ASX/Event_Server/Transceiver/transceiver.h @@ -0,0 +1,60 @@ +/* -*- C++ -*- */ +// $Id$ + +#ifndef ACE_TRANSCEIVER_H +#define ACE_TRANSCEIVER_H + +#include "ace/SOCK_Stream.h" +#include "ace/Svc_Handler.h" + +class Event_Transceiver : public ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH> +{ + // = TITLE + // Generate and receives messages from the event server. + // + // = DESCRIPTION + // This class is both a consumer and supplier of events, i.e., + // it's a ``transceiver.'' +public: + // = Initialization method. + Event_Transceiver (int argc, ACE_TCHAR *argv[]); + // Performs the actual initialization. + + Event_Transceiver (void); + // No-op constructor (required by the <ACE_Connector>). + + // = Svc_Handler hook called by the <ACE_Connector>. + virtual int open (void *); + // Initialize the transceiver when we are connected. + + // = Demultplexing hooks from the <ACE_Reactor>. + virtual int handle_input (ACE_HANDLE); + // Receive data from STDIN or socket. + + virtual int handle_signal (int signum, siginfo_t *, ucontext_t *); + // Close down via SIGINT. + + virtual int handle_close (ACE_HANDLE, ACE_Reactor_Mask); + // Close down the event loop. + +private: + int receiver (void); + // Reads data from socket and writes to ACE_STDOUT. + + int transmitter (void); + // Writes data from ACE_STDIN to socket. + + int parse_args (int argc, ACE_TCHAR *argv[]); + // Parse the command-line arguments. + + u_short port_number_; + // Port number of event server. + + const ACE_TCHAR *host_name_; + // Name of event server. + + const ACE_TCHAR *role_; + // Are we playing the Consumer or Supplier role? +}; + +#endif /* ACE_TRANSCEIVER_H */ diff --git a/ACE/examples/ASX/Makefile.am b/ACE/examples/ASX/Makefile.am new file mode 100644 index 00000000000..ecfcb575851 --- /dev/null +++ b/ACE/examples/ASX/Makefile.am @@ -0,0 +1,16 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +SUBDIRS = \ + CCM_App \ + Event_Server \ + Message_Queue \ + UPIPE_Event_Server + diff --git a/ACE/examples/ASX/Message_Queue/.cvsignore b/ACE/examples/ASX/Message_Queue/.cvsignore new file mode 100644 index 00000000000..2b68761db9c --- /dev/null +++ b/ACE/examples/ASX/Message_Queue/.cvsignore @@ -0,0 +1,6 @@ +bounded_buffer +bounded_buffer +buffer_stream +buffer_stream +priority_buffer +priority_buffer diff --git a/ACE/examples/ASX/Message_Queue/ASX_Message_Queue.mpc b/ACE/examples/ASX/Message_Queue/ASX_Message_Queue.mpc new file mode 100644 index 00000000000..8c1853bcee7 --- /dev/null +++ b/ACE/examples/ASX/Message_Queue/ASX_Message_Queue.mpc @@ -0,0 +1,25 @@ +// -*- MPC -*- +// $Id$ + +project(*Bounded_Buffer) : aceexe { + exename = bounded_buffer + Source_Files { + bounded_buffer.cpp + } +} + +project(*Buffer_Stream) : aceexe { + avoids += uses_wchar + exename = buffer_stream + Source_Files { + buffer_stream.cpp + } +} + +project(*Priority_Buffer) : aceexe { + exename = priority_buffer + Source_Files { + priority_buffer.cpp + } +} + diff --git a/ACE/examples/ASX/Message_Queue/Makefile.am b/ACE/examples/ASX/Message_Queue/Makefile.am new file mode 100644 index 00000000000..67e75b6c241 --- /dev/null +++ b/ACE/examples/ASX/Message_Queue/Makefile.am @@ -0,0 +1,64 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +ACE_BUILDDIR = $(top_builddir) +ACE_ROOT = $(top_srcdir) + + +## Makefile.ASX_Message_Queue_Bounded_Buffer.am +noinst_PROGRAMS = bounded_buffer + +bounded_buffer_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +bounded_buffer_SOURCES = \ + bounded_buffer.cpp + +bounded_buffer_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.ASX_Message_Queue_Buffer_Stream.am + +if !BUILD_USES_WCHAR +noinst_PROGRAMS += buffer_stream + +buffer_stream_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +buffer_stream_SOURCES = \ + buffer_stream.cpp + +buffer_stream_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_USES_WCHAR + +## Makefile.ASX_Message_Queue_Priority_Buffer.am +noinst_PROGRAMS += priority_buffer + +priority_buffer_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +priority_buffer_SOURCES = \ + priority_buffer.cpp + +priority_buffer_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Clean up template repositories, etc. +clean-local: + -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.* + -rm -f gcctemp.c gcctemp so_locations *.ics + -rm -rf cxx_repository ptrepository ti_files + -rm -rf templateregistry ir.out + -rm -rf ptrepository SunWS_cache Templates.DB diff --git a/ACE/examples/ASX/Message_Queue/bounded_buffer.cpp b/ACE/examples/ASX/Message_Queue/bounded_buffer.cpp new file mode 100644 index 00000000000..2cdc50f2116 --- /dev/null +++ b/ACE/examples/ASX/Message_Queue/bounded_buffer.cpp @@ -0,0 +1,140 @@ +// $Id$ + +// This short program copies stdin to stdout via the use of an ASX +// Message_Queue. It illustrates an implementation of the classic +// "bounded buffer" program. + +#include "ace/Message_Queue.h" +#include "ace/Thread_Manager.h" +#include "ace/OS_NS_time.h" +#include "ace/OS_NS_unistd.h" + +ACE_RCSID(Message_Queue, bounded_buffer, "$Id$") + +#if defined (ACE_HAS_THREADS) + +// The producer reads data from the stdin stream, creates a message, +// and then queues the message in the message list, where it is +// removed by the consumer thread. A 0-sized message is enqueued when +// there is no more data to read. The consumer uses this as a flag to +// know when to exit. + +static void * +producer (ACE_Message_Queue<ACE_MT_SYNCH> *msg_queue) +{ + // Keep reading stdin, until we reach EOF. + + for (int n; ; ) + { + // Allocate a new message. + ACE_Message_Block *mb; + + ACE_NEW_RETURN (mb, ACE_Message_Block (BUFSIZ), 0); + + n = ACE_OS::read (ACE_STDIN, mb->wr_ptr (), mb->size ()); + + if (n <= 0) + { + // Send a shutdown message to the other thread and exit. + mb->length (0); + if (msg_queue->enqueue_tail (mb) == -1) + ACE_ERROR ((LM_ERROR, + "(%t) %p\n", + "put_next")); + break; + } + + // Send the message to the other thread. + else + { + mb->msg_priority (n); + mb->wr_ptr (n); + if (msg_queue->enqueue_tail (mb) == -1) + ACE_ERROR ((LM_ERROR, + "(%t) %p\n", + "put_next")); + } + } + + return 0; +} + +// The consumer dequeues a message from the ACE_Message_Queue, writes +// the message to the stderr stream, and deletes the message. The +// producer sends a 0-sized message to inform the consumer to stop +// reading and exit. + +static void *consumer (ACE_Message_Queue<ACE_MT_SYNCH> *msg_queue) +{ + int result = 0; + + // Keep looping, reading a message out of the queue, until we timeout + // or get a message with a length == 0, which signals us to quit. + + for (;;) + { + ACE_Message_Block *mb; + + ACE_Time_Value timeout (ACE_OS::time (0) + 4, 0); // Wait for upto 4 seconds + + result = msg_queue->dequeue_head (mb, &timeout); + + if (result == -1) + break; + + int length = mb->length (); + + if (length > 0) + ACE_OS::write (ACE_STDOUT, mb->rd_ptr (), length); + + mb->release (); + + if (length == 0) + break; + } + + if (result == -1 && errno == EWOULDBLOCK) + ACE_ERROR ((LM_ERROR, + "(%t) %p\n%a", + "timed out waiting for message", + 1)); + return 0; +} + +// Spawn off two threads that copy stdin to stdout. + +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + // Message list. + ACE_Message_Queue<ACE_MT_SYNCH> msg_queue; + + if (ACE_Thread_Manager::instance ()->spawn + (ACE_THR_FUNC (producer), + (void *) &msg_queue, + THR_NEW_LWP | THR_DETACHED) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "spawn"), + 1); + else if (ACE_Thread_Manager::instance ()->spawn + (ACE_THR_FUNC (consumer), + (void *) &msg_queue, + THR_NEW_LWP | THR_DETACHED) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "spawn"), + 1); + + // Wait for producer and consumer threads to exit. + ACE_Thread_Manager::instance ()->wait (); + return 0; +} +#else +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_ERROR ((LM_ERROR, "threads not supported on this platform\n")); + return 0; +} +#endif /* ACE_HAS_THREADS */ diff --git a/ACE/examples/ASX/Message_Queue/buffer_stream.cpp b/ACE/examples/ASX/Message_Queue/buffer_stream.cpp new file mode 100644 index 00000000000..b1f918cfef5 --- /dev/null +++ b/ACE/examples/ASX/Message_Queue/buffer_stream.cpp @@ -0,0 +1,311 @@ +// $Id$ + +// This short program copies stdin to stdout via the use of an ASX +// Stream. It illustrates an implementation of the classic "bounded +// buffer" program using an ASX Stream containing two Modules. Each +// ACE_Module contains two Tasks. Each ACE_Task contains a +// ACE_Message_Queue and a pointer to a ACE_Thread_Manager. Note how +// the use of these reusable components reduces the reliance on global +// variables, as compared with the bounded_buffer.C example. + +#include "ace/OS_main.h" +#include "ace/OS_NS_stdio.h" +#include "ace/OS_NS_string.h" +#include "ace/OS_NS_time.h" +#include "ace/OS_NS_unistd.h" +#include "ace/Service_Config.h" +#include "ace/Stream.h" +#include "ace/Module.h" +#include "ace/Task.h" + +ACE_RCSID(Message_Queue, buffer_stream, "$Id$") + +#if defined (ACE_HAS_THREADS) + +typedef ACE_Stream<ACE_MT_SYNCH> MT_Stream; +typedef ACE_Module<ACE_MT_SYNCH> MT_Module; +typedef ACE_Task<ACE_MT_SYNCH> MT_Task; + +class Common_Task : public MT_Task + // = TITLE + // Methods that are common to the producer and consumer. +{ +public: + Common_Task (void) {} + // ACE_Task hooks + virtual int open (void * = 0); + virtual int close (u_long = 0); +}; + +// Define the Producer interface. + +class Producer : public Common_Task +{ +public: + Producer (void) {} + + // Read data from stdin and pass to consumer. + virtual int svc (void); +}; + +class Consumer : public Common_Task + // = TITLE + // Define the Consumer interface. +{ +public: + Consumer (void) {} + + virtual int put (ACE_Message_Block *mb, + ACE_Time_Value *tv = 0); + // Enqueue the message on the ACE_Message_Queue for subsequent + // handling in the svc() method. + + virtual int svc (void); + // Receive message from producer and print to stdout. + +private: + + ACE_Time_Value timeout_; +}; + +class Filter : public MT_Task + // = TITLE + // Defines a Filter that prepends a line number in front of each + // line. +{ +public: + Filter (void): count_ (1) {} + + virtual int put (ACE_Message_Block *mb, + ACE_Time_Value *tv = 0); + // Change the size of the message before passing it downstream. + +private: + size_t count_; + // Count the number of lines passing through the filter. +}; + +// Spawn off a new thread. + +int +Common_Task::open (void *) +{ + if (this->activate (THR_NEW_LWP | THR_DETACHED) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("spawn")), + -1); + return 0; +} + +int +Common_Task::close (u_long exit_status) +{ + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%t) thread is exiting with status %d in module %s\n"), + exit_status, + this->name ())); + + // Can do anything here that is required when a thread exits, e.g., + // storing thread-specific information in some other storage + // location, etc. + return 0; +} + +// The Consumer reads data from the stdin stream, creates a message, +// and then queues the message in the message list, where it is +// removed by the consumer thread. A 0-sized message is enqueued when +// there is no more data to read. The consumer uses this as a flag to +// know when to exit. + +int +Producer::svc (void) +{ + // Keep reading stdin, until we reach EOF. + + for (int n; ; ) + { + // Allocate a new message (add one to avoid nasty boundary + // conditions). + + ACE_Message_Block *mb = 0; + + ACE_NEW_RETURN (mb, + ACE_Message_Block (BUFSIZ + 1), + -1); + + n = ACE_OS::read (ACE_STDIN, mb->wr_ptr (), BUFSIZ); + + if (n <= 0) + { + // Send a shutdown message to the other thread and exit. + mb->length (0); + + if (this->put_next (mb) == -1) + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("(%t) %p\n"), + ACE_TEXT ("put_next"))); + break; + } + + // Send the message to the other thread. + else + { + mb->wr_ptr (n); + // NUL-terminate the string (since we use strlen() on it + // later). + mb->rd_ptr ()[n] = '\0'; + + if (this->put_next (mb) == -1) + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("(%t) %p\n"), + ACE_TEXT ("put_next"))); + } + } + + return 0; +} + +// Simply enqueue the Message_Block into the end of the queue. + +int +Consumer::put (ACE_Message_Block *mb, ACE_Time_Value *tv) +{ + return this->putq (mb, tv); +} + +// The consumer dequeues a message from the ACE_Message_Queue, writes +// the message to the stderr stream, and deletes the message. The +// Consumer sends a 0-sized message to inform the consumer to stop +// reading and exit. + +int +Consumer::svc (void) +{ + int result = 0; + + // Keep looping, reading a message out of the queue, until we + // timeout or get a message with a length == 0, which signals us to + // quit. + + for (;;) + { + ACE_Message_Block *mb = 0; + + // Wait for upto 4 seconds. + this->timeout_.sec (ACE_OS::time (0) + 4); + + result = this->getq (mb, &this->timeout_); + + if (result == -1) + break; + + int length = mb->length (); + + if (length > 0) + ACE_OS::write (ACE_STDOUT, + mb->rd_ptr (), + ACE_OS::strlen (mb->rd_ptr ())); + + mb->release (); + + if (length == 0) + break; + } + + if (result == -1 && errno == EWOULDBLOCK) + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("(%t) %p\n%a"), + ACE_TEXT ("timed out waiting for message"), + 1)); + return 0; +} + +int +Filter::put (ACE_Message_Block *mb, + ACE_Time_Value *tv) +{ + if (mb->length () == 0) + return this->put_next (mb, tv); + else + { + char buf[BUFSIZ]; + + // Stash a copy of the buffer away. + ACE_OS::strncpy (buf, mb->rd_ptr (), sizeof buf); + + // Increase the size of the buffer large enough that it will be + // reallocated (in order to test the reallocation mechanisms). + + mb->size (mb->length () + BUFSIZ); + mb->length (mb->size ()); + + // Prepend the line count in front of the buffer. + ACE_OS::sprintf (mb->rd_ptr (), + ACE_SIZE_T_FORMAT_SPECIFIER + ": %s", + this->count_++, + buf); + return this->put_next (mb, tv); + } +} + +// Main driver function. + +int +ACE_TMAIN (int, ACE_TCHAR *argv[]) +{ + ACE_Service_Config daemon (argv[0]); + + // This Stream controls hierachically-related active objects. + MT_Stream stream; + + MT_Module *pm = 0; + MT_Module *fm = 0; + MT_Module *cm = 0; + + ACE_NEW_RETURN (cm, + MT_Module (ACE_TEXT ("Consumer"), + new Consumer), + -1); + ACE_NEW_RETURN (fm, + MT_Module (ACE_TEXT ("Filter"), + new Filter), + -1); + ACE_NEW_RETURN (pm, + MT_Module (ACE_TEXT ("Producer"), + new Producer), + -1); + + // Create Consumer, Filter, and Producer Modules and push them onto + // the Stream. All processing is performed in the Stream. + + if (stream.push (cm) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("push")), + 1); + else if (stream.push (fm) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("push")), + 1); + else if (stream.push (pm) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("push")), + 1); + // Barrier synchronization: wait for the threads to exit, then exit + // ourselves. + ACE_Thread_Manager::instance ()->wait (); + return 0; +} +#else +int +main (int, char *[]) +{ + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("threads not supported on this platform\n"))); + return 0; +} +#endif /* ACE_HAS_THREADS */ diff --git a/ACE/examples/ASX/Message_Queue/priority_buffer.cpp b/ACE/examples/ASX/Message_Queue/priority_buffer.cpp new file mode 100644 index 00000000000..db60a33bcae --- /dev/null +++ b/ACE/examples/ASX/Message_Queue/priority_buffer.cpp @@ -0,0 +1,145 @@ +// $Id$ + +// This short program prints the contents of stdin to stdout sorted by +// the length of each line via the use of an ASX Message_Queue. It +// illustrates how priorities can be used for ACE Message_Queues. + +#include "ace/OS_NS_stdio.h" +#include "ace/Malloc_Base.h" // To get ACE_Allocator +#include "ace/Message_Queue.h" +#include "ace/Read_Buffer.h" +#include "ace/Thread_Manager.h" +#include "ace/Service_Config.h" + +ACE_RCSID(Message_Queue, priority_buffer, "$Id$") + +#if defined (ACE_HAS_THREADS) + +// Global thread manager. +static ACE_Thread_Manager thr_mgr; + +// Make the queue be capable of being *very* large. +static const long max_queue = LONG_MAX; + +// The consumer dequeues a message from the ACE_Message_Queue, writes +// the message to the stderr stream, and deletes the message. The +// producer sends a 0-sized message to inform the consumer to stop +// reading and exit. + +static void * +consumer (ACE_Message_Queue<ACE_MT_SYNCH> *msg_queue) +{ + // Keep looping, reading a message out of the queue, until we + // timeout or get a message with a length == 0, which signals us to + // quit. + + for (;;) + { + ACE_Message_Block *mb; + + if (msg_queue->dequeue_head (mb) == -1) + break; + + int length = mb->length (); + + if (length > 0) + ACE_OS::puts (mb->rd_ptr ()); + + // Free up the buffer memory and the Message_Block. + ACE_Allocator::instance ()->free (mb->rd_ptr ()); + mb->release (); + + if (length == 0) + break; + } + + return 0; +} + +// The producer reads data from the stdin stream, creates a message, +// and then queues the message in the message list, where it is +// removed by the consumer thread. A 0-sized message is enqueued when +// there is no more data to read. The consumer uses this as a flag to +// know when to exit. + +static void * +producer (ACE_Message_Queue<ACE_MT_SYNCH> *msg_queue) +{ + ACE_Read_Buffer rb (ACE_STDIN); + + // Keep reading stdin, until we reach EOF. + + for (;;) + { + // Allocate a new buffer. + char *buffer = rb.read ('\n'); + + ACE_Message_Block *mb; + + if (buffer == 0) + { + // Send a 0-sized shutdown message to the other thread and + // exit. + + ACE_NEW_RETURN (mb, ACE_Message_Block ((size_t) 0), 0); + + if (msg_queue->enqueue_tail (mb) == -1) + ACE_ERROR ((LM_ERROR, "(%t) %p\n", "put_next")); + break; + } + + // Enqueue the message in priority order. + else + { + // Allocate a new message, but have it "borrow" its memory + // from the buffer. + ACE_NEW_RETURN (mb, ACE_Message_Block (rb.size (), + ACE_Message_Block::MB_DATA, + 0, + buffer), + 0); + mb->msg_priority (rb.size ()); + mb->wr_ptr (rb.size ()); + + ACE_DEBUG ((LM_DEBUG, + "enqueueing message of size %d\n", + mb->msg_priority ())); + + // Enqueue in priority order. + if (msg_queue->enqueue_prio (mb) == -1) + ACE_ERROR ((LM_ERROR, "(%t) %p\n", "put_next")); + } + } + + // Now read all the items out in priority order (i.e., ordered by + // the size of the lines!). + consumer (msg_queue); + + return 0; +} + +// Spawn off one thread that copies stdin to stdout in order of the +// size of each line. + +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + // Message queue. + ACE_Message_Queue<ACE_MT_SYNCH> msg_queue (max_queue); + + if (thr_mgr.spawn (ACE_THR_FUNC (producer), (void *) &msg_queue, + THR_NEW_LWP | THR_DETACHED) == -1) + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "spawn"), 1); + + // Wait for producer and consumer threads to exit. + thr_mgr.wait (); + return 0; +} +#else +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_ERROR ((LM_ERROR, "threads not supported on this platform\n")); + return 0; +} +#endif /* ACE_HAS_THREADS */ diff --git a/ACE/examples/ASX/UPIPE_Event_Server/Consumer_Router.cpp b/ACE/examples/ASX/UPIPE_Event_Server/Consumer_Router.cpp new file mode 100644 index 00000000000..b9c9c0cf2bd --- /dev/null +++ b/ACE/examples/ASX/UPIPE_Event_Server/Consumer_Router.cpp @@ -0,0 +1,138 @@ +// $Id$ + +#include "ace/OS_NS_stdio.h" +#include "ace/OS_NS_string.h" +#include "Consumer_Router.h" +#include "Options.h" + +ACE_RCSID(UPIPE_Event_Server, Consumer_Router, "$Id$") + +#if defined (ACE_HAS_THREADS) + +typedef Acceptor_Factory<Consumer_Handler, CONSUMER_KEY> CONSUMER_FACTORY; + +int +Consumer_Handler::open (void *a) +{ + CONSUMER_FACTORY *af = (CONSUMER_FACTORY *) a; + this->router_task_ = af->router (); + return this->Peer_Handler<CONSUMER_ROUTER, CONSUMER_KEY>::open (a); +} + +Consumer_Handler::Consumer_Handler (ACE_Thread_Manager *tm) + : Peer_Handler<CONSUMER_ROUTER, CONSUMER_KEY> (tm) +{ +} + +// Create a new handler that will interact with a consumer and point +// its ROUTER_TASK_ data member to the CONSUMER_ROUTER. + +Consumer_Router::Consumer_Router (ACE_Thread_Manager *tm) + : CONSUMER_ROUTER (tm) +{ +} + +// Initialize the Router.. + +int +Consumer_Router::open (void *) +{ + ACE_ASSERT (this->is_reader ()); + ACE_TCHAR *argv[3]; + + argv[0] = (ACE_TCHAR *) this->name (); + argv[1] = (ACE_TCHAR *) options.consumer_file (); + argv[2] = 0; + + if (this->init (1, &argv[1]) == -1) + return -1; + + // Make this an active object. + // return this->activate (options.t_flags ()); + + // Until that's done, return 1 to indicate that the object wasn't activated. + return 1; +} + +int +Consumer_Router::close (u_long) +{ + ACE_ASSERT (this->is_reader ()); + this->peer_map_.close (); + this->msg_queue ()->deactivate(); + return 0; +} + + +// Handle incoming messages in a separate thread.. + +int +Consumer_Router::svc (void) +{ + ACE_Message_Block *mb = 0; + + ACE_ASSERT (this->is_reader ()); + + if (options.debug ()) + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) starting svc in %s\n"), + this->name ())); + + while (this->getq (mb) > 0) + if (this->put_next (mb) == -1) + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("(%t) put_next failed in %s\n"), + this->name ()), -1); + + return 0; + // Note the implicit ACE_OS::thr_exit() via destructor. +} + +// Send a MESSAGE_BLOCK to the supplier(s).. + +int +Consumer_Router::put (ACE_Message_Block *mb, ACE_Time_Value *) +{ + ACE_ASSERT (this->is_reader ()); + + if (mb->msg_type () == ACE_Message_Block::MB_IOCTL) + { + this->control (mb); + return this->put_next (mb); + } + else +{ +//printf("consumer-Router is routing : send_peers\n"); + return this->send_peers (mb); +} +} + +// Return information about the Client_Router ACE_Module.. + +int +Consumer_Router::info (ACE_TCHAR **strp, size_t length) const +{ + ACE_TCHAR buf[BUFSIZ]; + ACE_UPIPE_Addr addr; + const ACE_TCHAR *mod_name = this->name (); + ACE_UPIPE_Acceptor &sa = (ACE_UPIPE_Acceptor &) *this->acceptor_; + + if (sa.get_local_addr (addr) == -1) + return -1; + +#if !defined (ACE_WIN32) && defined (ACE_USES_WCHAR) +# define FMTSTR ACE_TEXT ("%ls\t %ls/ %ls") +#else +# define FMTSTR ACE_TEXT ("%s\t %s/ %s") +#endif + + ACE_OS::sprintf (buf, FMTSTR, + mod_name, ACE_TEXT ("upipe"), + ACE_TEXT ("# consumer router\n")); + + if (*strp == 0 && (*strp = ACE_OS::strdup (mod_name)) == 0) + return -1; + else + ACE_OS::strncpy (*strp, mod_name, length); + return ACE_OS::strlen (mod_name); +} + +#endif /* ACE_HAS_THREADS */ diff --git a/ACE/examples/ASX/UPIPE_Event_Server/Consumer_Router.h b/ACE/examples/ASX/UPIPE_Event_Server/Consumer_Router.h new file mode 100644 index 00000000000..93a1220dc11 --- /dev/null +++ b/ACE/examples/ASX/UPIPE_Event_Server/Consumer_Router.h @@ -0,0 +1,53 @@ +/* -*- C++ -*- */ +// $Id$ + +// The interface between one or more consumers and an Event Server +// ACE_Stream. + +#ifndef _CONSUMER_ROUTER_H +#define _CONSUMER_ROUTER_H + +#include "ace/Thread_Manager.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/UPIPE_Acceptor.h" +#include "ace/UPIPE_Addr.h" +#include "ace/Svc_Handler.h" +#include "Peer_Router.h" + +#if defined (ACE_HAS_THREADS) + +class Consumer_Handler; // Forward declaration.... + +typedef ACE_HANDLE CONSUMER_KEY; + +typedef Peer_Router<Consumer_Handler, CONSUMER_KEY> CONSUMER_ROUTER; + +class Consumer_Handler + : public Peer_Handler<CONSUMER_ROUTER, CONSUMER_KEY> +{ +public: + Consumer_Handler (ACE_Thread_Manager *tm = 0); + virtual int open (void *); +}; + +class Consumer_Router : public CONSUMER_ROUTER +{ +public: + Consumer_Router (ACE_Thread_Manager *thr_manager); + +protected: + // ACE_Task hooks.. + virtual int open (void *a = 0); + virtual int close (u_long flags = 0); + virtual int put (ACE_Message_Block *msg, ACE_Time_Value * = 0); + virtual int svc (void); + + // Dynamic linking hooks. + virtual int info (ACE_TCHAR **info_string, size_t length) const; +}; +#endif /* ACE_HAS_THREADS */ +#endif /* _CONSUMER_ROUTER_H */ diff --git a/ACE/examples/ASX/UPIPE_Event_Server/Event_Analyzer.cpp b/ACE/examples/ASX/UPIPE_Event_Server/Event_Analyzer.cpp new file mode 100644 index 00000000000..689a9280766 --- /dev/null +++ b/ACE/examples/ASX/UPIPE_Event_Server/Event_Analyzer.cpp @@ -0,0 +1,73 @@ +// $Id$ + +#include "ace/OS_NS_string.h" +#include "Event_Analyzer.h" + +ACE_RCSID(UPIPE_Event_Server, Event_Analyzer, "$Id$") + +#if defined (ACE_HAS_THREADS) + +int +Event_Analyzer::open (void *) +{ + return 0; +} + +int +Event_Analyzer::close (u_long) +{ + return 0; +} + +int +Event_Analyzer::control (ACE_Message_Block *mb) +{ + ACE_IO_Cntl_Msg *ioc = (ACE_IO_Cntl_Msg *) mb->rd_ptr (); + ACE_IO_Cntl_Msg::ACE_IO_Cntl_Cmds cmd; + + switch (cmd = ioc->cmd ()) + { + case ACE_IO_Cntl_Msg::SET_LWM: + case ACE_IO_Cntl_Msg::SET_HWM: + this->water_marks (cmd, *(size_t *) mb->cont ()->rd_ptr ()); + break; + default: + break; + } + return 0; +} + +int +Event_Analyzer::put (ACE_Message_Block *mb, ACE_Time_Value *) +{ + if (mb->msg_type () == ACE_Message_Block::MB_IOCTL) + this->control (mb); + + return this->put_next (mb); +} + +int +Event_Analyzer::init (int, ACE_TCHAR *[]) +{ + return 0; +} + +int +Event_Analyzer::fini (void) +{ + return 0; +} + +int +Event_Analyzer::info (ACE_TCHAR **strp, size_t length) const +{ + const ACE_TCHAR *mod_name = this->name (); + + if (*strp == 0 && (*strp = ACE_OS::strdup (mod_name)) == 0) + return -1; + else + ACE_OS::strncpy (*strp, mod_name, length); + return ACE_OS::strlen (mod_name); +} + +#endif /* ACE_HAS_THREADS */ diff --git a/ACE/examples/ASX/UPIPE_Event_Server/Event_Analyzer.h b/ACE/examples/ASX/UPIPE_Event_Server/Event_Analyzer.h new file mode 100644 index 00000000000..01bc3028964 --- /dev/null +++ b/ACE/examples/ASX/UPIPE_Event_Server/Event_Analyzer.h @@ -0,0 +1,37 @@ +/* -*- C++ -*- */ +// $Id$ + +// Signal router. + +#ifndef _EVENT_ANALYZER_H +#define _EVENT_ANALYZER_H + +#include "ace/Stream.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Module.h" +#include "ace/Task.h" + +#if defined (ACE_HAS_THREADS) + +class Event_Analyzer : public ACE_Task<ACE_MT_SYNCH> +{ +public: + virtual int open (void *a = 0); + virtual int close (u_long flags = 0); + virtual int put (ACE_Message_Block *msg, ACE_Time_Value * = 0); + + // Dynamic linking hooks. + virtual int init (int argc, ACE_TCHAR *argv[]); + virtual int fini (void); + virtual int info (ACE_TCHAR **info_string, size_t length) const; + +private: + virtual int control (ACE_Message_Block *); +}; + +#endif /* ACE_HAS_THREADS */ +#endif /* _EVENT_ANALYZER_H */ diff --git a/ACE/examples/ASX/UPIPE_Event_Server/Makefile.am b/ACE/examples/ASX/UPIPE_Event_Server/Makefile.am new file mode 100644 index 00000000000..ff730184cba --- /dev/null +++ b/ACE/examples/ASX/UPIPE_Event_Server/Makefile.am @@ -0,0 +1,49 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +ACE_BUILDDIR = $(top_builddir) +ACE_ROOT = $(top_srcdir) + + +## Makefile.UPIPE_Event_Server.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS = UPIPE_Event_Server + +UPIPE_Event_Server_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +UPIPE_Event_Server_SOURCES = \ + Consumer_Router.cpp \ + Event_Analyzer.cpp \ + Options.cpp \ + Peer_Router.cpp \ + Supplier_Router.cpp \ + event_server.cpp \ + Consumer_Router.h \ + Event_Analyzer.h \ + Options.h \ + Options.i \ + Peer_Router.h \ + Supplier_Router.h + +UPIPE_Event_Server_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Clean up template repositories, etc. +clean-local: + -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.* + -rm -f gcctemp.c gcctemp so_locations *.ics + -rm -rf cxx_repository ptrepository ti_files + -rm -rf templateregistry ir.out + -rm -rf ptrepository SunWS_cache Templates.DB diff --git a/ACE/examples/ASX/UPIPE_Event_Server/Options.cpp b/ACE/examples/ASX/UPIPE_Event_Server/Options.cpp new file mode 100644 index 00000000000..ca2cbbca887 --- /dev/null +++ b/ACE/examples/ASX/UPIPE_Event_Server/Options.cpp @@ -0,0 +1,207 @@ +// $Id$ + +#include "ace/Get_Opt.h" +#include "ace/Log_Msg.h" +#include "ace/OS_NS_Thread.h" +#include "ace/OS_NS_stdio.h" +#if defined (ACE_HAS_TRACE) +# include "ace/OS_NS_strings.h" +#endif /* ACE_HAS_TRACE */ + +#include "Options.h" + +ACE_RCSID(UPIPE_Event_Server, Options, "$Id$") + +#if defined (ACE_HAS_THREADS) + +Options::Options (void) + : thr_count_ (4), + t_flags_ (THR_DETACHED), + high_water_mark_ (8 * 1024), + low_water_mark_ (1024), + message_size_ (128), + initial_queue_length_ (0), + iterations_ (100000), + debugging_ (0), + verbosity_ (0), + consumer_port_ (ACE_TEXT ("-p 10000")), + supplier_port_ (ACE_TEXT ("-p 10001")), + consumer_file_ (ACE_TEXT ("-f/tmp/conupipe")), + supplier_file_ (ACE_TEXT ("-f/tmp/supupipe")) +{ +} + +Options::~Options (void) +{ +} + +void Options::print_results (void) +{ + ACE_Profile_Timer::ACE_Elapsed_Time et; + this->itimer_.elapsed_time (et); + +#if defined (ACE_HAS_PRUSAGE_T) + prusage_t rusage; + this->itimer_.get_rusage (rusage); + + if (options.verbose ()) + { + ACE_OS::printf ("final concurrency hint = %d\n", ACE_OS::thr_getconcurrency ()); + ACE_OS::printf ("%8d = lwpid\n" + "%8d = lwp count\n" + "%8d = minor page faults\n" + "%8d = major page faults\n" + "%8d = input blocks\n" + "%8d = output blocks\n" + "%8d = messages sent\n" + "%8d = messages received\n" + "%8d = signals received\n" + "%8ds, %dms = wait-cpu (latency) time\n" + "%8ds, %dms = user lock wait sleep time\n" + "%8ds, %dms = all other sleep time\n" + "%8d = voluntary context switches\n" + "%8d = involuntary context switches\n" + "%8d = system calls\n" + "%8d = chars read/written\n", + (int) rusage.pr_lwpid, + (int) rusage.pr_count, + (int) rusage.pr_minf, + (int) rusage.pr_majf, + (int) rusage.pr_inblk, + (int) rusage.pr_oublk, + (int) rusage.pr_msnd, + (int) rusage.pr_mrcv, + (int) rusage.pr_sigs, + (int) rusage.pr_wtime.tv_sec, (int) rusage.pr_wtime.tv_nsec / 1000000, + (int) rusage.pr_ltime.tv_sec, (int) rusage.pr_ltime.tv_nsec / 1000000, + (int) rusage.pr_slptime.tv_sec, (int) rusage.pr_slptime.tv_nsec / 1000000, + (int) rusage.pr_vctx, + (int) rusage.pr_ictx, + (int) rusage.pr_sysc, + (int) rusage.pr_ioch); + } +#endif /* ACE_HAS_PRUSAGE_T */ + + ACE_OS::printf ("---------------------\n" + "real time = %.3f\n" + "user time = %.3f\n" + "system time = %.3f\n" + "---------------------\n", + et.real_time, et.user_time, et.system_time); +} + +// Manages the options. +Options options; + +void +Options::parse_args (int argc, ACE_TCHAR *argv[]) +{ + ACE_LOG_MSG->open (argv[0]); + + ACE_Get_Opt getopt (argc, argv, ACE_TEXT ("C:c:bdH:i:L:l:M:nS:s:t:T:v")); + int c; + + while ((c = getopt ()) != -1) + switch (c) + { + case 'b': + this->t_flags (THR_BOUND); + break; + case 'C': + this->consumer_file (getopt.opt_arg ()); + break; + case 'c': + this->consumer_port (getopt.opt_arg ()); + break; + case 'd': + this->debugging_ = 1; + break; + case 'H': + this->high_water_mark (ACE_OS::atoi (getopt.opt_arg ())); + break; + case 'i': + this->iterations (ACE_OS::atoi (getopt.opt_arg ())); + break; + case 'L': + this->low_water_mark (ACE_OS::atoi (getopt.opt_arg ())); + break; + case 'l': + this->initial_queue_length (ACE_OS::atoi (getopt.opt_arg ())); + break; + case 'M': + this->message_size (ACE_OS::atoi (getopt.opt_arg ())); + break; + case 'n': + this->t_flags (THR_NEW_LWP); + break; + case 'S': + this->supplier_file (getopt.opt_arg ()); + break; + case 's': + this->supplier_port (getopt.opt_arg ()); + break; + case 'T': +#if defined (ACE_HAS_TRACE) + if (ACE_OS::strcasecmp (getopt.opt_arg (), ACE_TEXT ("ON")) == 0) + ACE_Trace::start_tracing (); + else if (ACE_OS::strcasecmp (getopt.opt_arg (), ACE_TEXT ("OFF")) == 0) + ACE_Trace::stop_tracing (); +#endif /* ACE_HAS_TRACE */ + break; + case 't': + this->thr_count (ACE_OS::atoi (getopt.opt_arg ())); + break; + case 'v': + this->verbosity_ = 1; + break; + default: + ::fprintf (stderr, "%s\n" + "\t[-b] (THR_BOUND)\n" + "\t[-C consumer file]\n" + "\t[-c consumer port]\n" + "\t[-d] (enable debugging)\n" + "\t[-H high water mark]\n" + "\t[-i number of test iterations]\n" + "\t[-L low water mark]\n" + "\t[-M] message size \n" + "\t[-n] (THR_NEW_LWP)\n" + "\t[-q max queue size]\n" + "\t[-S supplier file]\n" + "\t[-s supplier port]\n" + "\t[-t number of threads]\n" + "\t[-v] (verbose) \n", + ACE_TEXT_ALWAYS_CHAR (argv[0])); + ::exit (1); + /* NOTREACHED */ + break; + } + + // HACK! This needs to be done to avoid the mismatch from ACE_LIB_TEXT + // in ACE_SIZE_T_FORMAT_SPECIFIER to narrow-char on wide-char builds. + // It only works because it's at the end of the file. +# if defined (ACE_LIB_TEXT) +# undef ACE_LIB_TEXT +# endif +# define ACE_LIB_TEXT(X) X + if (this->verbose ()) + ACE_OS::printf ("%8d = initial concurrency hint\n" + ACE_SIZE_T_FORMAT_SPECIFIER " = total iterations\n" + ACE_SIZE_T_FORMAT_SPECIFIER " = thread count\n" + ACE_SIZE_T_FORMAT_SPECIFIER " = low water mark\n" + ACE_SIZE_T_FORMAT_SPECIFIER " = high water mark\n" + ACE_SIZE_T_FORMAT_SPECIFIER " = message_size\n" + ACE_SIZE_T_FORMAT_SPECIFIER " = initial queue length\n" + "%8d = THR_BOUND\n" + "%8d = THR_NEW_LWP\n", + ACE_OS::thr_getconcurrency (), + this->iterations (), + this->thr_count (), + this->low_water_mark (), + this->high_water_mark (), + this->message_size (), + this->initial_queue_length (), + (this->t_flags () & THR_BOUND) != 0, + (this->t_flags () & THR_NEW_LWP) != 0); +} + +#endif /* ACE_HAS_THREADS */ diff --git a/ACE/examples/ASX/UPIPE_Event_Server/Options.h b/ACE/examples/ASX/UPIPE_Event_Server/Options.h new file mode 100644 index 00000000000..1acad4b9d1f --- /dev/null +++ b/ACE/examples/ASX/UPIPE_Event_Server/Options.h @@ -0,0 +1,88 @@ +/* -*- C++ -*- */ +// $Id$ + +// Option manager for Event Server. + +#ifndef DEVICE_OPTIONS_H +#define DEVICE_OPTIONS_H + +#include "ace/config-all.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Profile_Timer.h" + +#if defined (ACE_HAS_THREADS) + +class Options +{ +public: + Options (void); + ~Options (void); + void parse_args (int argc, ACE_TCHAR *argv[]); + + void stop_timer (void); + void start_timer (void); + + void thr_count (size_t count); + size_t thr_count (void); + + void initial_queue_length (size_t length); + size_t initial_queue_length (void); + + void high_water_mark (size_t size); + size_t high_water_mark (void); + + void low_water_mark (size_t size); + size_t low_water_mark (void); + + void message_size (size_t size); + size_t message_size (void); + + void iterations (size_t n); + size_t iterations (void); + + void t_flags (long flag); + long t_flags (void); + + void supplier_port (const ACE_TCHAR *port); + const ACE_TCHAR *supplier_port (void); + + void consumer_port (const ACE_TCHAR *port); + const ACE_TCHAR *consumer_port (void); + + void supplier_file (const ACE_TCHAR *file); + const ACE_TCHAR *supplier_file (void); + + void consumer_file (const ACE_TCHAR *file); + const ACE_TCHAR *consumer_file (void); + + int debug (void); + int verbose (void); + + void print_results (void); + +private: + ACE_Profile_Timer itimer_; // Time the process. + size_t thr_count_; // Number of threads to spawn. + long t_flags_; // Flags to thr_create(). + size_t high_water_mark_; // ACE_Task high water mark. + size_t low_water_mark_; // ACE_Task low water mark. + size_t message_size_; // Size of a message. + size_t initial_queue_length_; // Initial number of items in the queue. + size_t iterations_; // Number of iterations to run the test program. + int debugging_; // Extra debugging info. + int verbosity_; // Extra verbose messages. + const ACE_TCHAR *consumer_port_; // Port that the Consumer_Router is using. + const ACE_TCHAR *supplier_port_; // Port that the Supplier_Router is using. + const ACE_TCHAR *consumer_file_; // file that the Consumer_Router is using. + const ACE_TCHAR *supplier_file_; // file that the Supplier_Router is using. +}; + +extern Options options; + +#include "Options.i" +#endif /* ACE_HAS_THREADS */ +#endif /* DEVICE_OPTIONS_H */ diff --git a/ACE/examples/ASX/UPIPE_Event_Server/Options.i b/ACE/examples/ASX/UPIPE_Event_Server/Options.i new file mode 100644 index 00000000000..af04f73eb26 --- /dev/null +++ b/ACE/examples/ASX/UPIPE_Event_Server/Options.i @@ -0,0 +1,166 @@ +/* -*- C++ -*- */ +// $Id$ + +// Option manager for ustreams. + +// Since this is only included in Options.h these should stay +// inline, not ACE_INLINE. +// FUZZ: disable check_for_inline + + +inline void +Options::supplier_port (const ACE_TCHAR *port) +{ + this->supplier_port_ = port; +} + +inline const ACE_TCHAR * +Options::supplier_port (void) +{ + return this->supplier_port_; +} + +inline void +Options::supplier_file (const ACE_TCHAR *file) +{ + this->supplier_file_ = file; +} + +inline const ACE_TCHAR * +Options::supplier_file (void) +{ + return this->supplier_file_; +} + +inline void +Options::consumer_file (const ACE_TCHAR *file) +{ + this->consumer_file_ = file; +} + +inline const ACE_TCHAR * +Options::consumer_file (void) +{ + return this->consumer_file_; +} + +inline void +Options::consumer_port (const ACE_TCHAR *port) +{ + this->consumer_port_ = port; +} + +inline const ACE_TCHAR * +Options::consumer_port (void) +{ + return this->consumer_port_; +} + +inline void +Options::start_timer (void) +{ + this->itimer_.start (); +} + +inline void +Options::stop_timer (void) +{ + this->itimer_.stop (); +} + +inline void +Options::thr_count (size_t count) +{ + this->thr_count_ = count; +} + +inline size_t +Options::thr_count (void) +{ + return this->thr_count_; +} + +inline void +Options::initial_queue_length (size_t length) +{ + this->initial_queue_length_ = length; +} + +inline size_t +Options::initial_queue_length (void) +{ + return this->initial_queue_length_; +} + +inline void +Options::high_water_mark (size_t size) +{ + this->high_water_mark_ = size; +} + +inline size_t +Options::high_water_mark (void) +{ + return this->high_water_mark_; +} + +inline void +Options::low_water_mark (size_t size) +{ + this->low_water_mark_ = size; +} + +inline size_t +Options::low_water_mark (void) +{ + return this->low_water_mark_; +} + +inline void +Options::message_size (size_t size) +{ + this->message_size_ = size; +} + +inline size_t +Options::message_size (void) +{ + return this->message_size_; +} + +inline void +Options::iterations (size_t n) +{ + this->iterations_ = n; +} + +inline size_t +Options::iterations (void) +{ + return this->iterations_; +} + +inline void +Options::t_flags (long flag) +{ + this->t_flags_ |= flag; +} + +inline long +Options::t_flags (void) +{ + return this->t_flags_; +} + +inline int +Options::debug (void) +{ + return this->debugging_; +} + +inline int +Options::verbose (void) +{ + return this->verbosity_; +} + diff --git a/ACE/examples/ASX/UPIPE_Event_Server/Peer_Router.cpp b/ACE/examples/ASX/UPIPE_Event_Server/Peer_Router.cpp new file mode 100644 index 00000000000..757eecedc33 --- /dev/null +++ b/ACE/examples/ASX/UPIPE_Event_Server/Peer_Router.cpp @@ -0,0 +1,283 @@ +// $Id$ + +#if !defined (_PEER_ROUTER_C) + +#define _PEER_ROUTER_C + +#include "ace/Get_Opt.h" +#include "ace/Service_Config.h" + +#include "Peer_Router.h" +#include "Options.h" + +ACE_RCSID(UPIPE_Event_Server, Peer_Router, "$Id$") + +#if defined (ACE_HAS_THREADS) + +// Define some short-hand macros to deal with long templates +// names... + +#define PH PEER_HANDLER +#define PA PEER_ACCEPTOR +#define PAD PEER_ADDR +#define PK PEER_KEY +#define PM PEER_MAP + +template <class PH, class PK> int +Acceptor_Factory<PH, PK>::init (int argc, ACE_TCHAR *argv[]) +{ + ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("df:"), 0); + ACE_UPIPE_Addr addr; + + for (int c; (c = get_opt ()) != -1; ) + switch (c) + { + case 'f': + addr.set (get_opt.opt_arg ()); + break; + case 'd': + break; + default: + break; + } + + if (this->open (addr, ACE_Reactor::instance ()) == -1) + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("open")), -1); + return 0; +} + +template <class PH, class PK> +Acceptor_Factory<PH, PK>::Acceptor_Factory (Peer_Router<PH, PK> *pr) + : pr_ (pr) +{ +} + +template <class PH, class PK> Peer_Router<PH, PK> * +Acceptor_Factory<PH, PK>::router (void) +{ + return this->pr_; +} + +template <class ROUTER, class KEY> +Peer_Handler<ROUTER, KEY>::Peer_Handler (ACE_Thread_Manager *tm) + : ACE_Svc_Handler<ACE_UPIPE_STREAM, ACE_MT_SYNCH> (tm) +{ +} + +template <class ROUTER, class KEY> int +Peer_Handler<ROUTER, KEY>::svc (void) +{ + // Just a try !! we're just reading from our ACE_Message_Queue. + ACE_Message_Block *db, *hb; + int n; + // do an endless loop + for (;;) + { + db = new ACE_Message_Block (BUFSIZ); + hb = new ACE_Message_Block (sizeof (KEY), ACE_Message_Block::MB_PROTO, db); + + if ((n = this->peer ().recv (db->rd_ptr (), db->size ())) == -1) + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), + ACE_TEXT ("recv failed")), -1); + else if (n == 0) // Client has closed down the connection. + { + + if (this->router_task_->unbind_peer (this->get_handle ()) == -1) + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), + ACE_TEXT ("unbind failed")), -1); + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) shutting down \n"))); + return -1; // We do not need to be deregistered by reactor + // as we were not registered at all + } + else // Transform incoming buffer into a Message and pass downstream. + { + db->wr_ptr (n); + *(ACE_HANDLE *) hb->rd_ptr () = this->get_handle (); // structure assignment. + hb->wr_ptr (sizeof (long)); + if (this->router_task_->reply (hb) == -1) + { + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Peer_Handler.svc : router_task->reply failed\n"))); + return -1; + } + + // return this->router_task_->reply (hb) == -1 ? -1 : 0; + } + } + ACE_NOTREACHED(return 0); +} + +template <class ROUTER, class KEY> int +Peer_Handler<ROUTER, KEY>::put (ACE_Message_Block *mb, ACE_Time_Value *) +{ + return this->peer ().send_n (mb->rd_ptr (), mb->length ()); +} + +// Create a new handler and point its ROUTER_TASK_ data member to the +// corresponding router. Note that this router is extracted out of +// the Acceptor_Factory * that is passed in via the +// ACE_Acceptor::handle_input() method. + +template <class ROUTER, class KEY> int +Peer_Handler<ROUTER, KEY>::open (void *a) +{ + ACE_TCHAR buf[BUFSIZ], *p = buf; + + if (this->router_task_->info (&p, sizeof buf) != -1) + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%t) creating handler for %s, fd = %d, this = %@\n"), + buf, this->get_handle (), a)); + else + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("info")), -1); + + if ( this->activate (options.t_flags ()) == -1) + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), + ACE_TEXT ("activation of thread failed")), -1); + else if (this->router_task_->bind_peer (this->get_handle (), this) == -1) + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), + ACE_TEXT ("bind_peer")), -1); + return 0; +} + +// Receive a message from a supplier.. + +template <class ROUTER, class KEY> int +Peer_Handler<ROUTER, KEY>::handle_input (ACE_HANDLE h) +{ + + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) input arrived on sd %d\n"), h)); +// ACE_Reactor::instance ()->remove_handler(h, +// ACE_Event_Handler::ALL_EVENTS_MASK +// |ACE_Event_Handler::DONT_CALL); +// this method should be called only if the peer shuts down +// so we deactivate our ACE_Message_Queue to awake our svc thread + + return 0; + +#if 0 + ACE_Message_Block *db = new ACE_Message_Block (BUFSIZ); + ACE_Message_Block *hb = new ACE_Message_Block (sizeof (KEY), ACE_Message_Block::MB_PROTO, db); + int n; + + if ((n = this->peer ().recv (db->rd_ptr (), db->size ())) == -1) + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("recv failed")), -1); + else if (n == 0) // Client has closed down the connection. + { + if (this->router_task_->unbind_peer (this->get_handle ()) == -1) + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), + ACE_TEXT ("unbind failed")), -1); + ACE_DEBUG ((LM_DEBUG, "(%t) shutting down %d\n", h)); + return -1; // Instruct the ACE_Reactor to deregister us by returning -1. + } + else // Transform incoming buffer into a Message and pass downstream. + { + db->wr_ptr (n); + *(long *) hb->rd_ptr () = this->get_handle (); // structure assignment. + hb->wr_ptr (sizeof (long)); + return this->router_task_->reply (hb) == -1 ? -1 : 0; + } +#endif +} + +template <class PH, class PK> +Peer_Router<PH, PK>::Peer_Router (ACE_Thread_Manager *tm) + : ACE_Task<ACE_MT_SYNCH> (tm) +{ +} + +template <class PH, class PK> int +Peer_Router<PH, PK>::send_peers (ACE_Message_Block *mb) +{ + ACE_Map_Iterator<PK, PH *, ACE_RW_Mutex> map_iter = this->peer_map_; + int bytes = 0; + int iterations = 0; + ACE_Message_Block *data_block = mb->cont (); + for (ACE_Map_Entry<PK, PH *> *ss = 0; + map_iter.next (ss) != 0; + map_iter.advance ()) + { + if (options.debug ()) + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) sending to peer via sd %d\n"), + ss->ext_id_)); + + iterations++; + bytes += ss->int_id_->put (data_block); + } + + mb->release (); + return bytes == 0 ? 0 : bytes / iterations; +} + +template <class PH, class PK> +Peer_Router<PH, PK>::~Peer_Router (void) +{ +} + +template <class PH, class PK> int +Peer_Router<PH, PK>::fini (void) +{ + delete this->acceptor_; + return 0; +} + +template <class PH, class PK> int +Peer_Router<PH, PK>::control (ACE_Message_Block *mb) +{ + ACE_IO_Cntl_Msg *ioc = (ACE_IO_Cntl_Msg *) mb->rd_ptr (); + ACE_IO_Cntl_Msg::ACE_IO_Cntl_Cmds command; + + switch (command = ioc->cmd ()) + { + case ACE_IO_Cntl_Msg::SET_LWM: + case ACE_IO_Cntl_Msg::SET_HWM: + this->water_marks (command, *(size_t *) mb->cont ()->rd_ptr ()); + break; + default: + return -1; + } + return 0; +} + +template <class PH, class PK> int +Peer_Router<PH, PK>::unbind_peer (PK key) +{ + return this->peer_map_.unbind (key); +} + +template <class PH, class PK> int +Peer_Router<PH, PK>::bind_peer (PK key, Peer_Handler<Peer_Router<PH, PK>, PK> *ph) +{ + PH *peer_handler = (PH *) ph; + return this->peer_map_.bind (key, peer_handler); +} + +template <class PH, class PK> int +Peer_Router<PH, PK>::init (int argc, ACE_TCHAR *argv[]) +{ + this->acceptor_ = new Acceptor_Factory <PH, PK> (this); + + if (this->acceptor_->init (argc, argv) == -1 + || this->peer_map_.open () == -1) + return -1; + else + { + ACE_UPIPE_Addr addr; + ACE_UPIPE_Acceptor &pa = this->acceptor_->acceptor (); + + if (pa.get_local_addr (addr) != -1) + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%t) initializing %s, file = %s, fd = %d, this = %@\n"), + this->name (), addr.get_path_name (), pa.get_handle (), this)); + else + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), + ACE_TEXT ("get_local_addr")), -1); + } + return 0; +} + +#undef PH +#undef PA +#undef PAD +#undef PK +#undef PM +#endif /* ACE_HAS_THREADS */ +#endif /* _PEER_ROUTER_C */ diff --git a/ACE/examples/ASX/UPIPE_Event_Server/Peer_Router.h b/ACE/examples/ASX/UPIPE_Event_Server/Peer_Router.h new file mode 100644 index 00000000000..3962d371ae0 --- /dev/null +++ b/ACE/examples/ASX/UPIPE_Event_Server/Peer_Router.h @@ -0,0 +1,127 @@ +/* -*- C++ -*- */ +// $Id$ + +// The interface between one or more peers and a stream. A peer +// typically runs remotely on another machine. + +#ifndef _PEER_ROUTER_H +#define _PEER_ROUTER_H + +#include "ace/Acceptor.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Svc_Handler.h" +#include "ace/UPIPE_Acceptor.h" +#include "ace/UPIPE_Addr.h" +#include "ace/Thread_Manager.h" +#include "ace/Map_Manager.h" + +#if defined (ACE_HAS_THREADS) +#include "ace/RW_Mutex.h" + +// Forward declaration. +template <class PEER_HANDLER, class KEY> +class Peer_Router; + +template <class PEER_HANDLER, class KEY> +class Acceptor_Factory : public ACE_Acceptor<PEER_HANDLER, ACE_UPIPE_ACCEPTOR> +{ +public: + Acceptor_Factory (Peer_Router<PEER_HANDLER, KEY> *pr); + Peer_Router<PEER_HANDLER, KEY> *router (void); + + int init (int argc, ACE_TCHAR *argv[]); + // Initialize the acceptor when it's linked dynamically. + +private: + Peer_Router<PEER_HANDLER, KEY> *pr_; +}; + +// Receive input from a Peer.. +template <class ROUTER, class KEY> +class Peer_Handler : public ACE_Svc_Handler<ACE_UPIPE_STREAM, ACE_MT_SYNCH> +{ +public: + Peer_Handler (ACE_Thread_Manager * = 0); + + virtual int open (void * = 0); + // Called by the ACE_Acceptor::handle_input() to activate this object. + + virtual int handle_input (ACE_HANDLE); + // Receive input from the peer.. + + virtual int put (ACE_Message_Block *, ACE_Time_Value *tv = 0); + // Send output to a peer. + +protected: + ROUTER *router_task_; + // Pointer to write task.. + +private: + // Don't need this method here... + virtual int svc (void); +}; + +// This abstract base class provides mechanisms for routing messages +// to/from a ACE_Stream from/to one or more peers (which are typically +// running on remote hosts). A subclass of Peer_Router overrides the +// open(), close(), and put() methods in order to specialize the +// behavior of the router to meet application-specific requirements. + +template <class PEER_HANDLER, class PEER_KEY> +class Peer_Router : public ACE_Task<ACE_MT_SYNCH> +{ +public: + Peer_Router (ACE_Thread_Manager * = 0); + ~Peer_Router (void); + + typedef Peer_Handler<Peer_Router<PEER_HANDLER, PEER_KEY>, PEER_KEY> HANDLER; + + // Remove a PEER_HANDLER from the PEER_MAP. + virtual int unbind_peer (PEER_KEY); + + // Add a PEER_HANDLER to the PEER_MAP. + virtual int bind_peer (PEER_KEY, HANDLER *); + + // Send the message block to the peer(s).. + int send_peers (ACE_Message_Block *mb); + +protected: +// Handle control messages arriving from adjacent Modules. + virtual int control (ACE_Message_Block *); + + // Map used to keep track of active peers. + ACE_Map_Manager <PEER_KEY, PEER_HANDLER *, ACE_RW_Mutex> peer_map_; + + // Dynamic linking initialization hooks inherited from ACE_Task. + virtual int init (int argc, ACE_TCHAR *argv[]); + virtual int fini (void); + + // Factory for accepting new PEER_HANDLERs. + Acceptor_Factory<PEER_HANDLER, PEER_KEY> *acceptor_; + +private: +// Prevent copies and pass-by-value. + ACE_UNIMPLEMENTED_FUNC (Peer_Router (const Peer_Router<PEER_HANDLER, PEER_KEY> &)) + ACE_UNIMPLEMENTED_FUNC (void operator= (const Peer_Router<PEER_HANDLER, PEER_KEY> &)) +}; + +#if defined (__ACE_INLINE__) +#define ACE_INLINE inline +#else +#define ACE_INLINE +#endif /* __ACE_INLINE__ */ + +#if defined (ACE_TEMPLATES_REQUIRE_SOURCE) +#include "Peer_Router.cpp" +#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */ + +#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA) +#pragma implementation ("Peer_Router.cpp") +#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */ + +#endif /* ACE_HAS_THREADS */ +#endif /* _PEER_ROUTER_H */ diff --git a/ACE/examples/ASX/UPIPE_Event_Server/Supplier_Router.cpp b/ACE/examples/ASX/UPIPE_Event_Server/Supplier_Router.cpp new file mode 100644 index 00000000000..8b4a53d6331 --- /dev/null +++ b/ACE/examples/ASX/UPIPE_Event_Server/Supplier_Router.cpp @@ -0,0 +1,137 @@ +// $Id$ + +#include "ace/OS_NS_stdio.h" +#include "ace/OS_NS_string.h" +#include "Options.h" +#include "Supplier_Router.h" + +ACE_RCSID(UPIPE_Event_Server, Supplier_Router, "$Id$") + +#if defined (ACE_HAS_THREADS) + +typedef Acceptor_Factory<Supplier_Handler, SUPPLIER_KEY> SUPPLIER_FACTORY; + +int +Supplier_Handler::open (void *a) +{ + SUPPLIER_FACTORY *af = (SUPPLIER_FACTORY *) a; + this->router_task_ = af->router (); + return this->Peer_Handler<SUPPLIER_ROUTER, SUPPLIER_KEY>::open (a); +} + +Supplier_Handler::Supplier_Handler (ACE_Thread_Manager *tm) + : Peer_Handler<SUPPLIER_ROUTER, SUPPLIER_KEY> (tm) +{ +} + +// Create a new router and associate it with the REACTOR parameter.. + +Supplier_Router::Supplier_Router (ACE_Thread_Manager *tm) + : SUPPLIER_ROUTER (tm) +{ +} + +// Handle incoming messages in a separate thread.. + +int +Supplier_Router::svc (void) +{ + ACE_ASSERT (this->is_writer ()); + + ACE_Message_Block *message_block = 0; + + if (options.debug ()) + ACE_DEBUG ((LM_DEBUG, "(%t) starting svc in %s\n", this->name ())); + + while (this->getq (message_block) > 0) + { + if (this->put_next (message_block) == -1) + ACE_ERROR_RETURN ((LM_ERROR, "(%t) put_next failed in %s\n", this->name ()), -1); + } + + return 0; +} + +// Initialize the Router.. + +int +Supplier_Router::open (void *) +{ + ACE_ASSERT (this->is_writer ()); + ACE_TCHAR *argv[3]; + + argv[0] = (ACE_TCHAR *)this->name (); + argv[1] = (ACE_TCHAR *)options.supplier_file (); + argv[2] = 0; + + if (this->init (1, &argv[1]) == -1) + return -1; + + // Make this an active object. + // return this->activate (options.t_flags ()); + + // Until that's done, return 1 to indicate that the object wasn't activated. + return 1; +} + +// Close down the router.. + +int +Supplier_Router::close (u_long) +{ + ACE_ASSERT (this->is_writer ()); + this->peer_map_.close (); + this->msg_queue ()->deactivate(); + return 0; +} + +// Send a MESSAGE_BLOCK to the supplier(s).. + +int +Supplier_Router::put (ACE_Message_Block *mb, ACE_Time_Value *) +{ + ACE_ASSERT (this->is_writer ()); + + if (mb->msg_type () == ACE_Message_Block::MB_IOCTL) + { + this->control (mb); + return this->put_next (mb); + } + else + { +//printf("supplier-Router is routing: send_peers\n"); + return this->send_peers (mb); + } +} + +// Return information about the Supplier_Router ACE_Module.. + +int +Supplier_Router::info (ACE_TCHAR **strp, size_t length) const +{ + ACE_TCHAR buf[BUFSIZ]; + ACE_UPIPE_Addr addr; + const ACE_TCHAR *mod_name = this->name (); + ACE_UPIPE_Acceptor &sa = (ACE_UPIPE_Acceptor &) *this->acceptor_; + + if (sa.get_local_addr (addr) == -1) + return -1; + +#if !defined (ACE_WIN32) && defined (ACE_USES_WCHAR) +# define FMTSTR ACE_TEXT ("%ls\t %ls/ %ls") +#else +# define FMTSTR ACE_TEXT ("%s\t %s/ %s") +#endif + + ACE_OS::sprintf (buf, FMTSTR, + mod_name, ACE_TEXT ("upipe"), + ACE_TEXT ("# supplier router\n")); + + if (*strp == 0 && (*strp = ACE_OS::strdup (mod_name)) == 0) + return -1; + else + ACE_OS::strncpy (*strp, mod_name, length); + return ACE_OS::strlen (mod_name); +} + +#endif /* ACE_HAS_THREADS */ diff --git a/ACE/examples/ASX/UPIPE_Event_Server/Supplier_Router.h b/ACE/examples/ASX/UPIPE_Event_Server/Supplier_Router.h new file mode 100644 index 00000000000..4d5d440e018 --- /dev/null +++ b/ACE/examples/ASX/UPIPE_Event_Server/Supplier_Router.h @@ -0,0 +1,57 @@ +/* -*- C++ -*- */ +// $Id$ + +// The interface between a supplier and an Event Service ACE_Stream. + +#ifndef _SUPPLIER_ROUTER_H +#define _SUPPLIER_ROUTER_H + +#include "ace/UPIPE_Addr.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/UPIPE_Acceptor.h" +#include "ace/Map_Manager.h" +#include "ace/Svc_Handler.h" +#include "Peer_Router.h" + +#if defined (ACE_HAS_THREADS) + +// Forward declaration. +class Supplier_Handler; + +// Type of search key for SUPPLIER_MAP. +typedef ACE_HANDLE SUPPLIER_KEY; + +// Instantiated type for routing messages to suppliers. + +typedef Peer_Router<Supplier_Handler, SUPPLIER_KEY> SUPPLIER_ROUTER; + +class Supplier_Handler + : public Peer_Handler<SUPPLIER_ROUTER, SUPPLIER_KEY> +{ +public: + Supplier_Handler (ACE_Thread_Manager *tm = 0); + virtual int open (void *); +}; + +class Supplier_Router : public SUPPLIER_ROUTER +{ +public: + Supplier_Router (ACE_Thread_Manager *); + +protected: + // ACE_Task hooks.. + virtual int open (void *a = 0); + virtual int close (u_long flags = 0); + virtual int put (ACE_Message_Block *msg, ACE_Time_Value * = 0); + virtual int svc (void); + + // Dynamic linking hooks inherited from Peer_Router. + virtual int info (ACE_TCHAR **info_string, size_t length) const; +}; + +#endif /* ACE_HAS_THREADS */ +#endif /* _SUPPLIER_ROUTER_H */ diff --git a/ACE/examples/ASX/UPIPE_Event_Server/UPIPE_Event.mpc b/ACE/examples/ASX/UPIPE_Event_Server/UPIPE_Event.mpc new file mode 100644 index 00000000000..a4c93dc1fdb --- /dev/null +++ b/ACE/examples/ASX/UPIPE_Event_Server/UPIPE_Event.mpc @@ -0,0 +1,15 @@ +// -*- MPC -*- +// $Id$ + +project(*Server) : aceexe { + avoids += ace_for_tao + exename = UPIPE_Event_Server + Source_Files { + Consumer_Router.cpp + Event_Analyzer.cpp + Options.cpp + Peer_Router.cpp + Supplier_Router.cpp + event_server.cpp + } +} diff --git a/ACE/examples/ASX/UPIPE_Event_Server/event_server.cpp b/ACE/examples/ASX/UPIPE_Event_Server/event_server.cpp new file mode 100644 index 00000000000..e1d5b8c440d --- /dev/null +++ b/ACE/examples/ASX/UPIPE_Event_Server/event_server.cpp @@ -0,0 +1,269 @@ +// $Id$ + +// Test the event server. + +#include "ace/OS_main.h" +#include "ace/Stream.h" +#include "ace/Service_Config.h" +#include "ace/UPIPE_Acceptor.h" +#include "ace/UPIPE_Connector.h" + +// FUZZ: disable check_for_streams_include +#include "ace/streams.h" + +#include "Options.h" +#include "Consumer_Router.h" +#include "Event_Analyzer.h" +#include "Supplier_Router.h" +#include "ace/Sig_Adapter.h" +#include "ace/OS_NS_unistd.h" + +ACE_RCSID (UPIPE_Event_Server, + event_server, + "$Id$") + +#if defined (ACE_HAS_THREADS) + +typedef ACE_Stream<ACE_MT_SYNCH> MT_Stream; +typedef ACE_Module<ACE_MT_SYNCH> MT_Module; + +// Handle SIGINT and terminate the entire application. + +class Quit_Handler : public ACE_Sig_Adapter +{ +public: + Quit_Handler (void); + virtual int handle_input (ACE_HANDLE fd); +}; + +Quit_Handler::Quit_Handler (void) + : ACE_Sig_Adapter (ACE_Sig_Handler_Ex (ACE_Reactor::end_event_loop)) +{ + // Register to trap input from the user. + if (ACE_Event_Handler::register_stdin_handler (this, + ACE_Reactor::instance (), + ACE_Thread_Manager::instance ()) == -1) + ACE_ERROR ((LM_ERROR, "%p\n", "register_stdin_handler")); + // Register to trap the SIGINT signal. + else if (ACE_Reactor::instance ()->register_handler + (SIGINT, this) == -1) + ACE_ERROR ((LM_ERROR, "%p\n", "register_handler")); +} + +int +Quit_Handler::handle_input (ACE_HANDLE) +{ + options.stop_timer (); + ACE_DEBUG ((LM_INFO, " (%t) closing down the test\n")); + options.print_results (); + + ACE_Reactor::end_event_loop(); + return 0; +} + +static void * +consumer (void *) +{ + ACE_UPIPE_Stream c_stream; + ACE_UPIPE_Addr c_addr (ACE_TEXT ("/tmp/conupipe")); + + int verb = options.verbose (); + int msiz = options.message_size (); + int secs, par1, par2; + time_t currsec; + + if (verb) + cout << "consumer starting connect" << endl; + + ACE_UPIPE_Connector con; + + if (con.connect (c_stream, c_addr) == -1) + ACE_DEBUG ((LM_INFO, " (%t) connect failed\n")); + else + cout << "consumer :we're connected" << endl; + + ACE_Message_Block *mb_p; + + int done = 0; + int cnt = 0; + ACE_OS::time (&currsec); + + par1= (time_t) currsec; + + while (done == 0 + && (c_stream.recv (mb_p) != -1)) + if (mb_p->length () > 1) + { + cnt++; + if (verb) + cout << " consumer received message !!!!!! " + << mb_p->rd_ptr () << endl; + } + else + { + if (verb) + cout << "consumer got last mb" + << (char) * (mb_p->rd_ptr ()) << endl; + c_stream.close (); + done = 1; + } + + ACE_OS::time (&currsec); + par2 = (time_t) currsec; + + secs = par2 - par1; + + if (secs <= 0) + secs=1; + + cout << "consumer got " << cnt << " messages of size " << msiz + << "within " << secs << " seconds" << endl; + + ACE_OS::sleep (2); + cout << "consumer terminating " << endl; + return 0; +} + +static void * +supplier (void *dummy) +{ + ACE_UPIPE_Stream s_stream; + ACE_UPIPE_Addr serv_addr (ACE_TEXT ("/tmp/supupipe")); + ACE_UPIPE_Connector con; + + int iter = options.iterations (); + int verb = options.verbose (); + int msiz = options.message_size (); + cout << "supplier starting connect" << endl; + + if (con.connect (s_stream, serv_addr) == -1) + ACE_DEBUG ((LM_INFO, " (%t) connect failed\n")); + + cout << "supplier : we're connected" << endl; + int n; + n = 0; + ACE_Message_Block * mb_p; + + while (n < iter) + { + mb_p = new ACE_Message_Block (msiz); + strcpy (mb_p->rd_ptr (), (char *) dummy); + mb_p->length (msiz); + if (verb) + cout << "supplier sending 1 message_block" << endl; + if (s_stream.send (mb_p) == -1) + { + cout << "supplier send failed" << endl; + return (void *) -1; + } + n++; + } + + mb_p = new ACE_Message_Block (10); + mb_p->length (1); + *mb_p->rd_ptr () = 'g'; + + cout << "supplier sending last message_block" << endl; + + if (s_stream.send (mb_p) == -1) + { + cout << "supplier send last mb failed" << endl; + return (void *) -1; + } + mb_p = new ACE_Message_Block (10); + mb_p->length (0); + + if (verb) + cout << "supplier sending very last message_block" << endl; + + if (s_stream.send (mb_p) == -1) + { + cout << "supplier send very last mb failed" << endl; + return (void *) -1; + } + + ACE_OS::sleep (2); + cout << "supplier terminating" << endl; + return 0; +} + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + ACE_Service_Config daemon; + + options.parse_args (argc, argv); + options.start_timer (); + + // Primary ACE_Stream for EVENT_SERVER application. + MT_Stream event_server; + + // Enable graceful shutdowns.... + Quit_Handler quit_handler; + + // Create the modules.. + + MT_Module *sr = new MT_Module (ACE_TEXT ("Supplier_Router"), + new Supplier_Router (ACE_Thread_Manager::instance ())); + MT_Module *ea = new MT_Module (ACE_TEXT ("Event_Analyzer"), + new Event_Analyzer, + new Event_Analyzer); + MT_Module *cr = new MT_Module (ACE_TEXT ("Consumer_Router"), + 0, // 0 triggers the creation of a ACE_Thru_Task... + new Consumer_Router (ACE_Thread_Manager::instance ())); + + // Push the modules onto the event_server stream. + + if (event_server.push (sr) == -1) + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), + ACE_TEXT ("push (Supplier_Router)")), -1); + + if (event_server.push (ea) == -1) + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), + ACE_TEXT ("push (Event_Analyzer)")), -1); + + if (event_server.push (cr) == -1) + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), + ACE_TEXT ("push (Consumer_Router)")), -1); + + // Set the high and low water marks appropriately. + + int wm = options.low_water_mark (); + + if (event_server.control (ACE_IO_Cntl_Msg::SET_LWM, &wm) == -1) + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), + ACE_TEXT ("push (setting low watermark)")), -1); + + wm = options.high_water_mark (); + if (event_server.control (ACE_IO_Cntl_Msg::SET_HWM, &wm) == -1) + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), + ACE_TEXT ("push (setting high watermark)")), -1); + + // spawn the two threads. + + if (ACE_Thread_Manager::instance ()->spawn (ACE_THR_FUNC (consumer), (void *) 0, + THR_NEW_LWP | THR_DETACHED) == -1) + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("spawn")), 1); + + else if (ACE_Thread_Manager::instance ()->spawn (ACE_THR_FUNC (supplier), (void *) "hello", + THR_NEW_LWP | THR_DETACHED) == -1) + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("spawn")), 1); + + // Perform the main event loop waiting for the user to type ^C or to + // enter a line on the ACE_STDIN. + + ACE_Reactor::instance ()->run_reactor_event_loop (); + + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("main exiting\n"))); + + return 0; +} +#else +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("test not defined for this platform\n")), + -1); +} +#endif /* ACE_HAS_THREADS */ diff --git a/ACE/examples/Bounded_Packet_Relay/.cvsignore b/ACE/examples/Bounded_Packet_Relay/.cvsignore new file mode 100644 index 00000000000..2f50e8efaee --- /dev/null +++ b/ACE/examples/Bounded_Packet_Relay/.cvsignore @@ -0,0 +1,2 @@ +bpr_thread +bpr_thread diff --git a/ACE/examples/Bounded_Packet_Relay/BPR_Drivers.cpp b/ACE/examples/Bounded_Packet_Relay/BPR_Drivers.cpp new file mode 100644 index 00000000000..fb646962004 --- /dev/null +++ b/ACE/examples/Bounded_Packet_Relay/BPR_Drivers.cpp @@ -0,0 +1,535 @@ +// $Id$ + +// ============================================================================ +// = LIBRARY +// examples +// +// = FILENAME +// BPR_Driver.cpp +// +// = DESCRIPTION +// This code builds an abstraction to factor out common code for +// the different implementations of the Timer_Queue. +// +// = AUTHORS +// Chris Gill <cdgill@cs.wustl.edu> and +// Douglas C. Schmidt <schmidt@cs.wustl.edu> +// +// Based on the Timer Queue Test example written by +// +// Carlos O'Ryan <coryan@cs.wustl.edu> and +// Douglas C. Schmidt <schmidt@cs.wustl.edu> and +// Sergio Flores-Gaitan <sergio@cs.wustl.edu> +// +// ============================================================================ + +#include "ace/OS_NS_sys_time.h" +#include "BPR_Drivers.h" + +ACE_RCSID(Bounded_Packet_Relay, BPR_Drivers, "$Id$") + +// Constructor. + +Input_Device_Wrapper_Base::Input_Device_Wrapper_Base (ACE_Thread_Manager *input_task_mgr) + : ACE_Task_Base (input_task_mgr), + send_input_msg_cmd_ (0), + input_period_ (ACE_ONE_SECOND_IN_USECS), + is_active_ (0), + send_count_ (0) +{ +} + +// Destructor. + +Input_Device_Wrapper_Base::~Input_Device_Wrapper_Base (void) +{ +} + +// Sets send input message command in the input device driver object. + +int +Input_Device_Wrapper_Base::set_send_input_msg_cmd (ACE_Command_Base *send_input_msg_cmd) +{ + // Set the new command. Input device is not responsible + // for deleting the old command, if any. + send_input_msg_cmd_ = send_input_msg_cmd; + return 0; +} + +// Sets period between when input messages are produced. + +int +Input_Device_Wrapper_Base::set_input_period (u_long input_period) +{ + input_period_ = input_period; + return 0; +} + +// Sets count of messages to send. + +int +Input_Device_Wrapper_Base::set_send_count (long count) +{ + send_count_ = count; + return 0; +} + +// Request that the input device stop sending messages +// and terminate its thread. Should return 1 if it will do so, 0 +// if it has already done so, or -1 if there is a problem doing so. + +int +Input_Device_Wrapper_Base::request_stop (void) +{ + if (is_active_) + { + is_active_ = 0; + return 1; + } + + return 0; +} + +// This method runs the input device loop in the new thread. + +int +Input_Device_Wrapper_Base::svc (void) +{ + ACE_Time_Value timeout; + ACE_Message_Block *message; + + // Set a flag to indicate we're active. + is_active_ = 1; + + // Start with the total count of messages to send. + for (current_count_ = send_count_; + // While we're still marked active, and there are packets to send. + (is_active_) && (current_count_ != 0); + ) + { + // Create an input message to send. + message = create_input_message (); + if (message == 0) + { + if (is_active_) + { + is_active_ = 0; + ACE_ERROR_RETURN ((LM_ERROR, "%t %p\n", + "Failed to create input message object"), + -1); + } + + break; + } + + // Make sure there is a send command object. + if (send_input_msg_cmd_ == 0) + { + delete message; + if (is_active_) + { + is_active_ = 0; + ACE_ERROR_RETURN ((LM_ERROR, "%t %p\n", + "send message command object not instantiated"), + -1); + } + + break; + } + + // Send the input message. + if (send_input_msg_cmd_->execute ((void *) message) < 0) + { + delete message; + if (is_active_) + { + is_active_ = 0; + ACE_ERROR_RETURN ((LM_ERROR, "%t %p\n", + "Failed executing send message command object"), + -1); + } + + break; + } + + // If all went well, decrement count of messages to send, and + // run the reactor event loop unti we get a timeout or something + // happens in a registered upcall. + if (current_count_ > 0) + --current_count_; + + timeout = ACE_Time_Value (0, input_period_); + reactor_.run_event_loop (timeout); + } + + is_active_ = 0; + + return 0; +} + +// Sends a newly created message block, carrying data read from the +// underlying input device, by passing a pointer to the message block +// to its command execution. + +int +Input_Device_Wrapper_Base::send_input_message (ACE_Message_Block *amb) +{ + if (send_input_msg_cmd_) + return send_input_msg_cmd_->execute ((void *) amb); + else + { + if (is_active_) + ACE_ERROR ((LM_ERROR, "%t %p\n", + "Input_Device_Wrapper_Base::send_input_message: " + "command object not instantiated")); + + return -1; + } +} + +Output_Device_Wrapper_Base::~Output_Device_Wrapper_Base (void) +{ +} + +// Constructor. + +Bounded_Packet_Relay::Bounded_Packet_Relay (ACE_Thread_Manager *input_task_mgr, + Input_Device_Wrapper_Base *input_wrapper, + Output_Device_Wrapper_Base *output_wrapper) + : is_active_ (0), + input_task_mgr_ (input_task_mgr), + input_wrapper_ (input_wrapper), + output_wrapper_ (output_wrapper), + queue_ (Bounded_Packet_Relay::DEFAULT_HWM, + Bounded_Packet_Relay::DEFAULT_LWM), + queue_hwm_ (Bounded_Packet_Relay::DEFAULT_HWM), + queue_lwm_ (Bounded_Packet_Relay::DEFAULT_LWM), + transmission_number_ (0), + packets_sent_ (0), + status_ (Bounded_Packet_Relay::UN_INITIALIZED), + transmission_start_ (ACE_Time_Value::zero), + transmission_end_ (ACE_Time_Value::zero) +{ + if (input_task_mgr_ == 0) + input_task_mgr_ = ACE_Thread_Manager::instance (); +} + +// Destructor. + +Bounded_Packet_Relay::~Bounded_Packet_Relay (void) +{ + // Reactivate the queue, and then clear it. + queue_.activate (); + while (! queue_.is_empty ()) + { + ACE_Message_Block *msg; + queue_.dequeue_head (msg); + delete msg; + } + +} + +// Requests output be sent to output device. + +int +Bounded_Packet_Relay::send_input (void) +{ + // Don't block, return immediately if queue is empty. + ACE_Message_Block *item; + + // Using a separate (non-const) time value + // is necessary on some platforms + ACE_Time_Value immediate (ACE_Time_Value::zero); + + if (queue_.dequeue_head (item, + &immediate) < 0) + return 1; + + // If a message block was dequeued, send it to the output device. + + if (output_wrapper_->write_output_message ((void *) item) < 0) + { + if (is_active_) + ACE_ERROR ((LM_ERROR, + "%t %p\n", + "failed to write to output device object")); + + return -1; + } + + // If all went OK, increase count of packets sent. + ++packets_sent_; + return 0; +} + +// Requests a transmission be started. + +int +Bounded_Packet_Relay::start_transmission (u_long packet_count, + u_long arrival_period, + int logging_level) +{ + // Serialize access to start and end transmission calls, statistics + // reporting calls. + ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, ace_mon, this->transmission_lock_, -1); + + // If a transmission is already in progress, just return. + if (is_active_) + return 1; + + // Set transmission in progress flag true. + is_active_ = 1; + + // Update statistics for a new transmission. + ++transmission_number_; + packets_sent_ = 0; + status_ = STARTED; + transmission_start_ = ACE_OS::gettimeofday (); + + // Reactivate the queue, and then clear it. + queue_.activate (); + while (! queue_.is_empty ()) + { + ACE_Message_Block *msg; + queue_.dequeue_head (msg); + delete msg; + } + + // Initialize the output device. + if (output_wrapper_->modify_device_settings ((void *) &logging_level) < 0) + { + status_ = ERROR_DETECTED; + transmission_end_ = ACE_OS::gettimeofday (); + is_active_ = 0; + ACE_ERROR_RETURN ((LM_ERROR, "%t %p\n", + "failed to initialize output device object"), + -1); + } + // Initialize the input device. + if (input_wrapper_->modify_device_settings ((void *) &logging_level) < 0) + { + status_ = ERROR_DETECTED; + transmission_end_ = ACE_OS::gettimeofday (); + is_active_ = 0; + ACE_ERROR_RETURN ((LM_ERROR, "%t %p\n", + "failed to initialize output device object"), + -1); + } + else if (input_wrapper_->set_input_period (arrival_period) < 0) + { + status_ = ERROR_DETECTED; + transmission_end_ = ACE_OS::gettimeofday (); + is_active_ = 0; + ACE_ERROR_RETURN ((LM_ERROR, "%t %p\n", + "failed to initialize input device object"), + -1); + } + else if (input_wrapper_->set_send_count (packet_count) < 0) + { + status_ = ERROR_DETECTED; + transmission_end_ = ACE_OS::gettimeofday (); + is_active_ = 0; + ACE_ERROR_RETURN ((LM_ERROR, "%t %p\n", + "failed to initialize input device object"), + -1); + } + // Activate the input device. + else if (input_wrapper_->activate () < 0) + { + status_ = ERROR_DETECTED; + transmission_end_ = ACE_OS::gettimeofday (); + is_active_ = 0; + ACE_ERROR_RETURN ((LM_ERROR, "%t %p\n", + "failed to activate input device object"), + -1); + } + + // If all went well, print a startup message and return success. + ACE_DEBUG ((LM_DEBUG, + "\n\nTransmission %u started\n\n", + transmission_number_)); + return 0; +} + +// Requests a transmission be ended. + +int +Bounded_Packet_Relay::end_transmission (Transmission_Status status) +{ + // Serialize access to start and end transmission calls, + // statistics reporting calls. + ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, ace_mon, this->transmission_lock_, -1); + + // If a transmission is not already in progress, just return. + if (! is_active_) + return 1; + + // Set transmission in progress flag false. + is_active_ = 0; + + // Ask the the input thread to stop. + if (input_wrapper_->request_stop () < 0) + { + status_ = ERROR_DETECTED; + transmission_end_ = ACE_OS::gettimeofday (); + ACE_ERROR_RETURN ((LM_ERROR, "%t %p\n", + "failed asking input device thread to stop"), + -1); + } + + // Deactivate the queue, allowing all waiting threads to continue. + queue_.deactivate (); + + // Wait for input thread to stop. + input_task_mgr_->wait_task (input_wrapper_); + + // Reactivate the queue, and then clear it. + queue_.activate (); + while (! queue_.is_empty ()) + { + ACE_Message_Block *msg; + queue_.dequeue_head (msg); + delete msg; + } + + // If all went well, set passed status, stamp end time, print a + // termination message, and return success. + status_ = status; + transmission_end_ = ACE_OS::gettimeofday (); + ACE_DEBUG ((LM_DEBUG, + "\n\nTransmission %u ended with status: %s\n\n", + transmission_number_, status_msg ())); + return 0; +} + +// Requests a report of statistics from the last transmission. + +int +Bounded_Packet_Relay::report_statistics (void) +{ + // Serialize access to start and end transmission calls, + // statistics reporting calls. + ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, ace_mon, this->transmission_lock_, -1); + + // If a transmission is already in progress, just return. + if (is_active_) + return 1; + + // Calculate duration of trasmission. + ACE_Time_Value duration (transmission_end_); + duration -= transmission_start_; + + // Report transmission statistics. + ACE_DEBUG ((LM_DEBUG, + "\n\nStatisics for transmission %u:\n\n" + "Transmission status: %s\n" + "Start time: %d (sec) %d (usec)\n" + "End time: %d (sec) %d (usec)\n" + "Duration: %d (sec) %d (usec)\n" + "Packets relayed: %u\n\n", + transmission_number_, status_msg (), + transmission_start_.sec (), + transmission_start_.usec (), + transmission_end_.sec (), + transmission_end_.usec (), + duration.sec (), + duration.usec (), + packets_sent_)); + return 0; +} + +// Public entry point to which to push input. + +int +Bounded_Packet_Relay::receive_input (void * arg) +{ + if (! arg) + { + if (is_active_) + ACE_ERROR ((LM_ERROR, "%t %p\n", + "Bounded_Packet_Relay::receive_input: " + "null argument")); + + return -1; + } + ACE_Message_Block *message = static_cast<ACE_Message_Block *> (arg); + if (queue_.enqueue_tail (message) < 0) + { + if (is_active_) + ACE_ERROR ((LM_ERROR, "%t %p\n", + "Bounded_Packet_Relay::receive_input failed")); + + return -1; + } + + return 0; +} + +// Get high water mark for relay queue. + +ACE_UINT32 +Bounded_Packet_Relay::queue_hwm (void) +{ + return queue_lwm_; +} + + +// Set high water mark for relay queue. + +void +Bounded_Packet_Relay::queue_hwm (ACE_UINT32 hwm) +{ + queue_hwm_ = hwm; +} + +// Get low water mark for relay queue. + +ACE_UINT32 +Bounded_Packet_Relay::queue_lwm (void) +{ + return queue_lwm_; +} + +// Set low water mark for relay queue. + +void +Bounded_Packet_Relay::queue_lwm (ACE_UINT32 lwm) +{ + queue_lwm_ = lwm; +} + + + +// Returns string corresponding to current status. + +const char * +Bounded_Packet_Relay::status_msg (void) +{ + const char *status_msg; + switch (status_) + { + case UN_INITIALIZED: + status_msg = "uninitialized"; + break; + case STARTED: + status_msg = "in progress"; + break; + case COMPLETED: + status_msg = "completed with all packets sent"; + break; + case TIMED_OUT: + status_msg = "terminated by transmission duration timer"; + break; + case CANCELLED: + status_msg = "cancelled by external control"; + break; + case ERROR_DETECTED: + status_msg = "error was detected"; + break; + default: + status_msg = "unknown transmission status"; + break; + } + + return status_msg; +} diff --git a/ACE/examples/Bounded_Packet_Relay/BPR_Drivers.h b/ACE/examples/Bounded_Packet_Relay/BPR_Drivers.h new file mode 100644 index 00000000000..f39a544c512 --- /dev/null +++ b/ACE/examples/Bounded_Packet_Relay/BPR_Drivers.h @@ -0,0 +1,290 @@ +/* -*- C++ -*- */ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// examples +// +// = FILENAME +// BPR_Drivers.h +// +// = DESCRIPTION +// This code builds abstractions to factor out common code from +// the different possible implementations of the Timer_Queue based +// bounded packet relay example. +// +// = AUTHORS +// Chris Gill <cdgill@cs.wustl.edu> and +// Douglas C. Schmidt <schmidt@cs.wustl.edu> +// +// Based on the Timer Queue Test example written by +// +// Carlos O'Ryan <coryan@cs.wustl.edu> and +// Douglas C. Schmidt <schmidt@cs.wustl.edu> and +// Sergio Flores-Gaitan <sergio@cs.wustl.edu> +// +// ============================================================================ + +#ifndef _BPR_DRIVERS_H_ +#define _BPR_DRIVERS_H_ + +#include "ace/Functor.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Reactor.h" +#include "ace/Task.h" + +// forward declarations +class Input_Device_Wrapper_Base; +class Output_Device_Wrapper_Base; + +class Bounded_Packet_Relay +{ + // = TITLE + // This class defines a packet relay abstraction for a + // transmission bounded external commands to start and end the + // transmission. The transmission may be bounded by the number + // of packets to send, the dration of the transmission, or any + // other factors. + // + // = DESCRIPTION + // The relay abstraction implemented by this class registers a + // callback command with an input device wrapper, and relays + // input to an output device at a pace specified in the start + // transmission call. +public: + // = Enumerates possible status values for a transmission. + enum Transmission_Status + { + UN_INITIALIZED, + STARTED, + COMPLETED, + TIMED_OUT, + CANCELLED, + ERROR_DETECTED + }; + + enum Queue_Defaults + { + DEFAULT_HWM = 0x7FFFFFFF, + DEFAULT_LWM = 0x7FFFFFFF + }; + + typedef int (Bounded_Packet_Relay::*ACTION) (void *); + // Command entry point type definition. + + // = Initialization method + + Bounded_Packet_Relay (ACE_Thread_Manager *input_task_mgr, + Input_Device_Wrapper_Base *input_wrapper, + Output_Device_Wrapper_Base *output_wrapper); + // Constructor. + + virtual ~Bounded_Packet_Relay (void); + // Destructor. + + int send_input (void); + // Requests output be sent to output device. + + int start_transmission (u_long packet_count, + u_long arrival_period, + int logging_level); + // Requests a transmission be started. + + int end_transmission (Transmission_Status status); + // Requests a transmission be ended. + + int report_statistics (void); + // Requests a report of statistics from the last transmission. + + // = Command accessible entry points. + + int receive_input (void *); + // Public entry point to which to push input. + + // = Accessors and mutators for relay settings + + ACE_UINT32 queue_hwm (void); + // Get high water mark for relay queue. + + void queue_hwm (ACE_UINT32 hwm); + // Set high water mark for relay queue. + + ACE_UINT32 queue_lwm (void); + // Get low water mark for relay queue. + + void queue_lwm (ACE_UINT32 lwm); + // Set low water mark for relay queue. + +private: + // = Concurrency Management. + + int is_active_; + // flag for whether or not a transmission is active + + ACE_Thread_Manager * input_task_mgr_; + // Thread manager for the input device task. + + Input_Device_Wrapper_Base * input_wrapper_; + // Pointer to the input device wrapper. + + Output_Device_Wrapper_Base * output_wrapper_; + // Pointer to the output device wrapper. + + ACE_Message_Queue<ACE_SYNCH> queue_; + // Queue used to buffer input messages. + + ACE_UINT32 queue_hwm_; + // High water mark for relay queue. + + ACE_UINT32 queue_lwm_; + // Low water mark for relay queue. + + ACE_SYNCH_MUTEX transmission_lock_; + // Lock for thread-safe synchronization of transmission startup and + // termination. + + // = Transmission Statistics + + const char *status_msg (void); + // Returns string corresponding to current status. + + u_long transmission_number_; + // Number of transmissions sent. + + u_long packets_sent_; + // Count of packets sent in the most recent transmission. + + Transmission_Status status_; + // Status of the current or most recent transmission. + + ACE_Time_Value transmission_start_; + // Start time of the most recent transmission. + + ACE_Time_Value transmission_end_; + // Ending time of the most recent transmission. + +}; + +class Input_Device_Wrapper_Base : public ACE_Task_Base +{ + // = TITLE + // This class defines an abstract base class for an input device + // wrapper that hides the details of the specific device and + // provides a consistent message passing interface without + // knowing anything about the implementation of the input device + // or the message receiver. + // + // The abstract base class ctor takes a command template object + // that is instantiated with the correct receiver and action + // types. This command object is used to send newly created input + // messages to the receiver. + // + // The abstract base class is designed to operate in an active + // "push" mode, sending input data to the receiver whenever the + // data is ready. The underlying device may be active, notifying + // the wrapper when data is ready, or may be passive in which + // case the wrapper must rely on a reactive and/or polling + // mechanism. + // + // = DESCRIPTION + // Derived classes are responsible for filling in concrete + // definitions for the abstract message creation method and the + // svc method. +public: + // = Initialization and termination methods. + Input_Device_Wrapper_Base (ACE_Thread_Manager *input_task_mgr); + // Constructor. + + virtual ~Input_Device_Wrapper_Base (); + // Destructor. + + int set_send_input_msg_cmd (ACE_Command_Base *send_input_msg_cmd); + // Sets send input message command in the input device driver + // object. + + int set_input_period (u_long input_period); + // Sets period (in usecs) between when inputs are created. + + int set_send_count (long count); + // Sets count of messages to send. + + int request_stop (void); + // Requests that the input device stop sending messages and + // terminate its thread. Should return 1 if it will do so, 0 if it + // has already done so, or -1 if there is a problem doing so. + + virtual int svc (void); + // This method runs the input device loop in the new thread. + + virtual int modify_device_settings (void *) = 0; + // Provides an abstract interface to allow modifying device + // settings. + +protected: + virtual ACE_Message_Block *create_input_message (void) = 0; + // Creates a new message block, carrying data read from the + // underlying input device. + + virtual int send_input_message (ACE_Message_Block *); + // Sends a newly created message block, carrying data read from the + // underlying input device, by passing a pointer to the message + // block to its command execution. + + ACE_Command_Base *send_input_msg_cmd_; + // Send newly created input message. + + u_long input_period_; + // Period between when input values are produced (usecs). + + ACE_Reactor reactor_; + // Reactor used to multiplex input streams, timeouts. + + int is_active_; + // Flag to indicate whether or not input object is + // (and should remain) active. + + long send_count_; + // Count of messages to send before stopping (-1 indicates the + // device should not stop). + + long current_count_; + // Currently remaining count of messages to send before stopping + // (-1 indicates the device should not stop). + +}; + +class Output_Device_Wrapper_Base +{ + // = TITLE + // This class defines an abstract base class for an output device + // wrapper that hides the details of the specific device and + // provides a consistent write method interface without knowing + // anything about the implementation. + // + // = DESCRIPTION + // The abstract methods write_output_message () and + // modify_device_settings () are defined in derived classes to + // write the contents of the passed message out the underlying + // output device, and update device settings, respectively. +public: + + virtual ~Output_Device_Wrapper_Base (void); + + virtual int write_output_message (void *) = 0; + // Writes contents of the passed message block out to the underlying + // output device. + + virtual int modify_device_settings (void *) = 0; + // Provides an abstract interface to allow modifying device + // settings. +}; + +// include the templates +#include "BPR_Drivers_T.h" + +#endif /* _BPR_DRIVERS_H_ */ diff --git a/ACE/examples/Bounded_Packet_Relay/BPR_Drivers_T.cpp b/ACE/examples/Bounded_Packet_Relay/BPR_Drivers_T.cpp new file mode 100644 index 00000000000..6e597dfb9e5 --- /dev/null +++ b/ACE/examples/Bounded_Packet_Relay/BPR_Drivers_T.cpp @@ -0,0 +1,322 @@ +// $Id$ + +// ============================================================================ +// = LIBRARY +// examples +// +// = FILENAME +// BPR_Driver.cpp +// +// = DESCRIPTION +// This code builds an abstraction to factor out common code for +// the different implementations of the Timer_Queue. +// +// = AUTHORS +// Chris Gill <cdgill@cs.wustl.edu> and +// Douglas C. Schmidt <schmidt@cs.wustl.edu> +// +// Based on the Timer Queue Test example written by +// +// Carlos O'Ryan <coryan@cs.wustl.edu> and +// Douglas C. Schmidt <schmidt@cs.wustl.edu> and +// Sergio Flores-Gaitan <sergio@cs.wustl.edu> +// +// ============================================================================ + +#ifndef _BPR_DRIVER_T_CPP_ +#define _BPR_DRIVER_T_CPP_ + +// #include BPR_Drivers.h instead of BPR_Drivers_T.h +// to avoid problems with circular includes +#include "BPR_Drivers.h" +#include "ace/OS_NS_string.h" +#include "ace/OS_NS_unistd.h" + +ACE_RCSID(Bounded_Packet_Relay, BPR_Drivers_T, "$Id$") + +// Constructor. + +template <class TQ> +Bounded_Packet_Relay_Driver<TQ>::Bounded_Packet_Relay_Driver (void) + : packet_count_cmd_ (0), + arrival_period_cmd_ (0), + transmit_period_cmd_ (0), + duration_limit_cmd_ (0), + logging_level_cmd_ (0), + run_transmission_cmd_ (0), + cancel_transmission_cmd_ (0), + report_stats_cmd_ (0), + shutdown_cmd_ (0), + packet_count_ (1000), + arrival_period_ (10000), + send_period_ (10000), + duration_limit_ (20000000), + logging_level_ (0) +{ +} + +// Destructor. + +template <class TQ> +Bounded_Packet_Relay_Driver<TQ>::~Bounded_Packet_Relay_Driver (void) +{ + // delete all instantiated command objects + delete packet_count_cmd_; + delete arrival_period_cmd_; + delete transmit_period_cmd_; + delete duration_limit_cmd_; + delete logging_level_cmd_; + delete run_transmission_cmd_; + delete cancel_transmission_cmd_; + delete report_stats_cmd_; + delete shutdown_cmd_; +} + +// Parse the input and execute the corresponding command. + +template <class TQ> int +Bounded_Packet_Relay_Driver<TQ>::parse_commands (const char *buf) +{ + int option; + + if (::sscanf (buf, "%d", &option) <= 0) + // If there was an error reading the option simply try on the next + // line. + return 0; + + switch (option) + { + case 1: // set packet count + { + u_long count; + + // We just reread the option, this simplies parsing (since + // sscanf can do it for us). + if (::sscanf (buf, "%d %lu", &option, &count) < 2) + // If there was not enough information on the line, ignore + // option and try the next line. + return 0; + if (packet_count_cmd_->execute ((void *) &count) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%t %p\n", + "set packet count failed"), + -1); + break; + } + case 2: // Set the arrival period. + { + u_long usec; + + // We just reread the option, this simplies parsing (since + // sscanf can do it for us). + if (::sscanf (buf, "%d %lu", &option, &usec) < 2) + // If there was not enough information on the line, ignore + // option and try the next line. + return 0; + if (arrival_period_cmd_->execute ((void *) &usec) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%t %p\n", + "set arrival period failed"), + -1); + break; + } + case 3: // Set transmit period. + { + u_long usec; + + // We just reread the option, this simplies parsing (since + // sscanf can do it for us). + if (::sscanf (buf, "%d %lu", &option, &usec) < 2) + // If there was not enough information on the line, ignore + // option and try the next line. + return 0; + if (transmit_period_cmd_->execute ((void *) &usec) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%t %p\n", + "set transmit period failed"), + -1); + break; + } + case 4: // Set duration limit. + { + u_long usec; + + // We just reread the option, this simplies parsing (since + // sscanf can do it for us). + if (::sscanf (buf, "%d %lu", &option, &usec) < 2) + // If there was not enough information on the line, ignore + // option and try the next line. + return 0; + if (duration_limit_cmd_->execute ((void *) &usec) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%t %p\n", + "\nSet duration limit failed."), + -1); + break; + } + case 5: // Set logging level. + { + int level; + + // We just reread the option, this simplies parsing (since + // sscanf can do it for us). + if ((::sscanf (buf, "%d %d", &option, &level) < 2) || + (level < 0) || (level > 7)) + { + // If there was not enough information on the line, or the + // passed value was invalid, ignore and try again. + return 0; + } + + if (logging_level_cmd_->execute ((void *) &level) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%t %p\n", + "set logging level failed"), + -1); + break; + } + case 6: // Run one transmission. + return run_transmission_cmd_->execute (0); + /* NOTREACHED */ + case 7: // Cancel current transmission. + return cancel_transmission_cmd_->execute (0); + /* NOTREACHED */ + case 8: // Report statistics. + return report_stats_cmd_->execute (0); + /* NOTREACHED */ + case 9: // Shut down the driver. + return shutdown_cmd_->execute (0); + /* NOTREACHED */ + default: + // Display an error message. + ACE_ERROR_RETURN ((LM_ERROR, "invalid input %s\n", buf), 0); + ACE_NOTREACHED (break); + /* NOTREACHED */ + } /* ENDSWITCH */ + return 0; +} + +// Runs the test. + +template <class TQ> int +Bounded_Packet_Relay_Driver<TQ>::run (void) +{ + this->init (); + + // Process all the incoming events. + + for (;;) + if (this->get_next_request () == -1) + return -1; + + ACE_NOTREACHED (return 0); +} + +// Gets the next request from the user input. + +template <class TQ> int +Bounded_Packet_Relay_Driver<TQ>::get_next_request (void) +{ + char buf[BUFSIZ]; + + this->display_menu (); + + // Reads input from the user. + if (this->read_input (buf, sizeof buf) <= 0) + return -1; + + // Parse and run the command. + return this->parse_commands (buf); +} + +// Reads input from the user from ACE_STDIN into the buffer specified. + +template <class TQ> ssize_t +Bounded_Packet_Relay_Driver<TQ>::read_input (char *buf, size_t bufsiz) +{ + ACE_OS::memset (buf, 0, bufsiz); + + // Wait for user to type commands. This call is automatically + // restarted when SIGINT or SIGALRM signals occur. + return ACE_OS::read (ACE_STDIN, buf, bufsiz); +} + +// Get count of packets to send in a transmission. + +template <class TQ> u_long +Bounded_Packet_Relay_Driver<TQ>::packet_count (void) +{ + return packet_count_; +} + +// Set count of packets to send in a transmission. + +template <class TQ> void +Bounded_Packet_Relay_Driver<TQ>::packet_count (u_long pc) +{ + packet_count_ = pc; +} + +// Get rate at which input packets are to arrive. + +template <class TQ> u_long +Bounded_Packet_Relay_Driver<TQ>::arrival_period (void) +{ + return arrival_period_; +} + +// Set rate at which input packets are to arrive. + +template <class TQ> void +Bounded_Packet_Relay_Driver<TQ>::arrival_period (u_long ap) +{ + arrival_period_ = ap; +} + +// Get rate at which packets are to be relayed (usec). + +template <class TQ> u_long +Bounded_Packet_Relay_Driver<TQ>::send_period (void) +{ + return send_period_; +} + +// Set rate at which packets are to be relayed (usec). + +template <class TQ> void +Bounded_Packet_Relay_Driver<TQ>::send_period (u_long sp) +{ + send_period_ = sp; +} + +// Get limit on the duration of the transmission (usec). + +template <class TQ> u_long +Bounded_Packet_Relay_Driver<TQ>::duration_limit (void) +{ + return duration_limit_; +} + +// Set limit on the duration of the transmission (usec). + +template <class TQ> void +Bounded_Packet_Relay_Driver<TQ>::duration_limit (u_long dl) +{ + duration_limit_ = dl; +} +// Get logging level. + +template <class TQ> int +Bounded_Packet_Relay_Driver<TQ>::logging_level (void) +{ + return logging_level_; +} + +// Set logging level. + +template <class TQ> void +Bounded_Packet_Relay_Driver<TQ>::logging_level (int ll) +{ + logging_level_ = ll; +} +#endif /* _BPR_DRIVER_T_CPP_ */ diff --git a/ACE/examples/Bounded_Packet_Relay/BPR_Drivers_T.h b/ACE/examples/Bounded_Packet_Relay/BPR_Drivers_T.h new file mode 100644 index 00000000000..4d0ca6bdfb4 --- /dev/null +++ b/ACE/examples/Bounded_Packet_Relay/BPR_Drivers_T.h @@ -0,0 +1,178 @@ +/* -*- C++ -*- */ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// examples +// +// = FILENAME +// BPR_Drivers_T.h +// +// = DESCRIPTION +// This code factors out common class templates for use in +// the different possible implementations of the Timer_Queue +// based bounded packet relay example. +// +// = AUTHORS +// Chris Gill <cdgill@cs.wustl.edu> and +// Douglas C. Schmidt <schmidt@cs.wustl.edu> +// +// Based on the Timer Queue Test example written by +// +// Carlos O'Ryan <coryan@cs.wustl.edu> and +// Douglas C. Schmidt <schmidt@cs.wustl.edu> and +// Sergio Flores-Gaitan <sergio@cs.wustl.edu> +// +// ============================================================================ + +#ifndef _BPR_DRIVERS_T_H_ +#define _BPR_DRIVERS_T_H_ + +#include "ace/Functor.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +// Forward declarations. +class Input_Device_Wrapper_Base; +class Output_Device_Wrapper_Base; + +template <class TQ> +class Bounded_Packet_Relay_Driver +{ + // = TITLE + // This abstract base class provides a simple abstraction for a + // test driver for the bounded packet relay example. + // + // = DESCRIPTION + // This is the place where the common code to test the different + // implementations of the timer queue resides. This class has + // the logic for the parse_commands () method, the run (), + // read_input () and get_next_request () methods. Subclasses can + // override these methods if there is some logic that is specific + // to that implementation. +public: + Bounded_Packet_Relay_Driver (void); + // Constructor. + + virtual ~Bounded_Packet_Relay_Driver (void); + // Destructor. + + virtual int parse_commands (const char *buf); + // Breaks up the input string buffer into pieces and executes the + // appropriate method to handle that operation. + + virtual int run (void); + // This is the main entry point for the driver. The user of the + // class should normally invoke this method. Returns 0 when + // successful, or 0 otherwise. + + virtual int get_next_request (void); + // This internal method gets the next request from the user. + // Returns -1 when user wants to exit. Returns 0 otherwise. + + virtual ssize_t read_input (char *buf, size_t bufsiz); + // Reads input from the user into the buffer <buf> with a maximum of + // <bufsiz> bytes. Returns the amount of bytes actually read + // Otherwise, a -1 is returned and errno is set to indicate the + // error. + + virtual int display_menu (void)=0; + // Prints the user interface for the driver to STDERR. + + virtual int init (void)=0; + // Initializes values and operations for the driver. + + u_long packet_count (void); + // Get count of packets to send in a transmission. + + void packet_count (u_long pc); + // Set count of packets to send in a transmission. + + u_long arrival_period (void); + // Get rate at which input packets are to arrive. + + void arrival_period (u_long ap); + // Set rate at which input packets are to arrive. + + u_long send_period (void); + // Get rate at which packets are to be relayed (usec). + + void send_period (u_long sp); + // Set rate at which packets are to be relayed (usec). + + u_long duration_limit (void); + // Get limit on the duration of the transmission (usec). + + void duration_limit (u_long dl); + // Set limit on the duration of the transmission (usec). + + int logging_level (void); + // Get logging level. + + void logging_level (int ll); + // Set logging level. + +protected: + // = Major Driver Mechanisms + + TQ timer_queue_; + // Timer queue for transmission timeouts. + + // = Set of commands to be executed. + + ACE_Command_Base *packet_count_cmd_; + // Set packet count command. + + ACE_Command_Base *arrival_period_cmd_; + // Set arrival period command. + + ACE_Command_Base *transmit_period_cmd_; + // Set transmit period command. + + ACE_Command_Base *duration_limit_cmd_; + // Set duration limit command. + + ACE_Command_Base *logging_level_cmd_; + // Set logging level command. + + ACE_Command_Base *run_transmission_cmd_; + // Run transmission command. + + ACE_Command_Base *cancel_transmission_cmd_; + // Cancel transmission command. + + ACE_Command_Base *report_stats_cmd_; + // Report statistics command. + + ACE_Command_Base *shutdown_cmd_; + // Shut down the driver. + +private: + u_long packet_count_; + // Count of packets to send in a transmission. + + u_long arrival_period_; + // Rate at which input packets are to arrive. + + u_long send_period_; + // Rate at which packets are to be relayed (usec). + + u_long duration_limit_; + // Limit on the duration of the transmission (usec). + + int logging_level_; + // Logging level. +}; + +#if defined (ACE_TEMPLATES_REQUIRE_SOURCE) +#include "BPR_Drivers_T.cpp" +#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */ + +#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA) +#pragma implementation ("BPR_Drivers_T.cpp") +#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */ + +#endif /* _BPR_DRIVERS_T_H_ */ diff --git a/ACE/examples/Bounded_Packet_Relay/Bounded_Packet_Relay.mpc b/ACE/examples/Bounded_Packet_Relay/Bounded_Packet_Relay.mpc new file mode 100644 index 00000000000..087cc5ac3be --- /dev/null +++ b/ACE/examples/Bounded_Packet_Relay/Bounded_Packet_Relay.mpc @@ -0,0 +1,7 @@ +// -*- MPC -*- +// $Id$ + +project : aceexe { + exename = bpr_thread + macros += ACE_HAS_DEFERRED_TIMER_COMMANDS +} diff --git a/ACE/examples/Bounded_Packet_Relay/Makefile.am b/ACE/examples/Bounded_Packet_Relay/Makefile.am new file mode 100644 index 00000000000..5fb14ba2d05 --- /dev/null +++ b/ACE/examples/Bounded_Packet_Relay/Makefile.am @@ -0,0 +1,39 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +ACE_BUILDDIR = $(top_builddir) +ACE_ROOT = $(top_srcdir) + +## Makefile.Bounded_Packet_Relay.am +noinst_PROGRAMS = bpr_thread + +bpr_thread_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) \ + -DACE_HAS_DEFERRED_TIMER_COMMANDS + +bpr_thread_SOURCES = \ + BPR_Drivers.cpp \ + Thread_Bounded_Packet_Relay.cpp \ + bpr_thread.cpp \ + BPR_Drivers.h \ + BPR_Drivers_T.h \ + Thread_Bounded_Packet_Relay.h + +bpr_thread_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Clean up template repositories, etc. +clean-local: + -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.* + -rm -f gcctemp.c gcctemp so_locations *.ics + -rm -rf cxx_repository ptrepository ti_files + -rm -rf templateregistry ir.out + -rm -rf ptrepository SunWS_cache Templates.DB diff --git a/ACE/examples/Bounded_Packet_Relay/README b/ACE/examples/Bounded_Packet_Relay/README new file mode 100644 index 00000000000..5757224c510 --- /dev/null +++ b/ACE/examples/Bounded_Packet_Relay/README @@ -0,0 +1,194 @@ +1. INTRODUCTION + +This directory contains an example that illustrates how to use both +threaded and reactive concurrency mechanisms in ACE. The example +application schedules and processes heterogenerous user input and +timer-based events in the context of a bounded packet relay mechanism. + +In this example, a transmission begins, packets arrive from an input device +object, and are transferred to an output device object by a relay object at +a specified pace. The transfer continues until all packets have been +relayed, a duration limit expires, or the transmission is cancelled. + +User input is handled concurrently with a running transmission. You +can run a transmission, cancel a transmission, change transmission +parameters, view statistics from the most recent transmission, or exit +the program, using selections from an interactive text-based menu. +In addition, the example program can be run in batch mode, with the +appropriate commands piped to the program's standard input stream. + +Transmission parameters are intialized to default values. Transmission +parameter values persist until/unless they are subsequently modified by an +appropriate command. If an invalid value for a command is given, or a run +or report command is issued while a transmission is in progress, the +offending command has no effect, and an error message is generated. + +2. USER INTERFACE + +Commands that can be given to the program include the following: + +Settings commands: + + 1 <number of packets to relay in one transmission> + + Minimum value is 1 packet, defaults to 1000 packets. + + 2 <input packet arrival period (in usec)> + + Minimum value is 1 usec, defaults to 10000 usec (10 msec). + + 3 <output packet transmission period (in usec)> + + Minimum value is 1 usec, defaults to 10000 usec (10 msec). + + 4 <limit on duration of transmission (in usec)> + + Minimum value is 1 usec, defaults to 20000000 usec (20 sec). + A value of 0 is also a valid input, in which case no limit + will be placed on the duration of the transmission (it will + end when all packets have been relayed from the input device + to the output device). + + 5 <logging level> + + 0 - does no logging + 1 - logs packets created by the input device + 2 - logs packets consumed by the output device + 4 - prints contents of packets consumed by the output device + + To set several flags, pass their sum as the logging level value: + e.g., a logging level value of 7 turns on all possible logging. + +Action commands: + + 6 - runs a transmission using the current settings + + 7 - cancels a transmission if there is one running + + 8 - reports statistics from the most recent transmission + + 9 - quits the program + +3. APPLICATION DESIGN + +3.1. KEY COMPONENTS + +The design of this example application consists of four main +components: the driver object, the relay object, the input device +object, and the output device object. + +The driver object is responsible for receiving user input and overall handling +of user input commands. The driver object is active, with separate threads +for receiving user input and managing its transmission timer queue. This +allows the user to issue commands while a transmission is in progress. The +driver object uses an ACE_Thread_Timer_Queue_Adapter, which is derived from +ACE_Task_Base. The driver object starts another active object, called +User_Input_Task, which is also derived from ACE_Task_Base. This allows both +the timer queue and the user input object to be made active, running in their +own threads of control. + +The relay object is passive, managing a message queue and necessary +locks to allow safe access from multiple threads. It provides methods +to receive and enqueue a mesage from the input device, dequeue a +message and send it to the output device, and to start or end a +transmission. It uses ACE_Message_Queue (which contains ACE_Message_Block +objects) and ACE_Thread_Mutex objects to implement this functionality. + +The input object is active, managing timeouts and input events in its +own thread. The input object is also reactive, using an ACE_Reactor to +allow response to multiple input handles as well as to do polling at +specific timeouts. The input pseudo-device wrapper in this example +does not make use of input handles and only does timed polling, but +extending this only requires registering the appropriate input handles +and handlers with the reactor. The input object is derived from +ACE_Task_Base, and is activated by the relay object when a new +transmission starts. The input object packages each data packet in an +ACE_Message_Block before sending it to the relay object. + +The output object is passive. If logging is turned on, it will report +the arrival time, relative to the start of the transmission, of each +output message, and the contents of that message. The output object +will also "consume" each ACE_Message_Block passed to it, calling +delete on the passed pointer. + +3.2. RUN-TIME CHARACTERSITICS + +When the user initiates a transmission, the appropriate settings are passed +by the driver to the relay object's start transmission method. The relay +object tries to start a new transmission. If another transmission is in +progress, the method returns an error. Otherwise, the relay object's start +transmission method initializes itself and the input and output device +objects, activates the input device object, and stores the handle for +the new input device thread. + +The driver then constructs a timeout handler with a count of the +number of messages to relay and a send timeout value, and pushes a +timer with this handler onto the timer queue. If there is a limit on +the duration of the transmission, the driver constructs a different +handler for end-of-transmission, and pushes a timer for the end of +the transmission with this handler onto the timer queue as well. When +the user issues a cancel transmission command, the driver calls the +relay's end transmission method. + +When a send timeout expires, the handler (running in the timer queue +thread) calls the send method of the relay. If there are any enqueued +messages from the input device object in its queue, the relay object's +send method will dequeue a message, pass it to the output device +object, and return success. If there are no messages in the queue, +the relay object's send method will return failure. If the send was +successful, the handler will decrement its count of remaining +messages. If the count is greater than zero, the handler will +register a new send timer for itself and exit. If the count is zero, +then the handler will call the relay's end transmission method, clear +the timer queue, and mark itself inactive before exiting. + +Similarly, if the end-of-transmission timer expires before all packets +have been sent, that handler will call the relay's end transmission +method, clear the timer queue, release the semaphore, and then exit. + +When the relay's end transmission method is called, it marks the relay +itself inactive, and calls the input device's deactivate method, which +sets the input device's activity flag to inactive (see below). The +relay's end transmission method then waits until the input device thread +exits, before returning. + +While it is still active, the input device thread blocks on a reactor +timeout for the duration it was given by the relay. When the timeout +expires, the input device checks a flag to see if it is still active. +If the flag says the input device is inactive, the thread simply +exits. This allows cancellation of the input device when a +transmission has ended. If the flag says it is still active, the +thread builds a new character buffer, and wraps this with a new +ACE_Message_Block. The input device passes this message block to the +execution method of the send input message command object with which +it was constructed. This level of indirection allows the input device +to be used with arbitrary types, so that it could for example be +connected directly to an output device. The input device also +maintains a count of the number of messages it has sent. Once the +input device has sent all its messages, it marks itself inactive, and +its thread simply exits. + +4. ACCESSING THE SOURCE CODE + +The files for this example are located in +$ACE_ROOT/examples/Bounded_Packet_Relay in the latest release of ACE, +which is located at + +http://www.cs.wustl.edu/~schmidt/ACE_wrappers/ACE.tar.gz + +Source Files: Thread_Bounded_Packet_Relay.h + Thread_Bounded_Packet_Relay.cpp + BPR_Driver.h + BPR_Driver.cpp + BPR_Driver_T.h + BPR_Driver_T.cpp + bpr_thread.cpp + +Make file: Makefile + +Doc file: README (this file) + +Executable: bpr_thread + + + diff --git a/ACE/examples/Bounded_Packet_Relay/Thread_Bounded_Packet_Relay.cpp b/ACE/examples/Bounded_Packet_Relay/Thread_Bounded_Packet_Relay.cpp new file mode 100644 index 00000000000..a2f179a5348 --- /dev/null +++ b/ACE/examples/Bounded_Packet_Relay/Thread_Bounded_Packet_Relay.cpp @@ -0,0 +1,770 @@ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// examples +// +// = FILENAME +// Thread_Bounded_Packet_Relay.cpp +// +// = DESCRIPTION +// Method definitions for the threaded-bounded packet relay class. +// +// = AUTHORS +// Chris Gill <cdgill@cs.wustl.edu> and +// Douglas C. Schmidt <schmidt@cs.wustl.edu> +// +// Based on the Timer Queue Test example written by +// +// Carlos O'Ryan <coryan@cs.wustl.edu> and +// Douglas C. Schmidt <schmidt@cs.wustl.edu> and +// Sergio Flores-Gaitan <sergio@cs.wustl.edu> +// +// ============================================================================ + +#include "ace/OS_NS_string.h" +#include "ace/OS_NS_sys_time.h" +#include "ace/Condition_T.h" +#include "ace/Null_Mutex.h" + +#include "Thread_Bounded_Packet_Relay.h" + +typedef Thread_Bounded_Packet_Relay_Driver::MYCOMMAND DRIVER_CMD; +typedef ACE_Command_Callback<BPR_Handler_Base, BPR_Handler_Base::ACTION> HANDLER_CMD; +typedef ACE_Command_Callback<Send_Handler, Send_Handler::ACTION> SEND_HANDLER_CMD; + +ACE_RCSID(Bounded_Packet_Relay, Thread_Bounded_Packet_Relay, "$Id$") + +// Constructor. + +Text_Input_Device_Wrapper::Text_Input_Device_Wrapper (ACE_Thread_Manager *input_task_mgr, + size_t read_length, + const char* text, + int logging) + : Input_Device_Wrapper_Base (input_task_mgr), + read_length_ (read_length), + text_ (text), + index_ (0), + logging_ (logging), + packet_count_ (0) + +{ +} + +// Destructor. + +Text_Input_Device_Wrapper::~Text_Input_Device_Wrapper (void) +{ +} + +// Modifies device settings based on passed pointer to a u_long. + +int +Text_Input_Device_Wrapper::modify_device_settings (void *logging) +{ + packet_count_ = 0; + + if (logging) + logging_ = *static_cast<int *> (logging); + else + ACE_ERROR_RETURN ((LM_ERROR, + "Text_Input_Device_Wrapper::modify_device_settings: " + "null argument"), + -1); + return 0; +} + + +// Creates a new message block, carrying data +// read from the underlying input device. + +ACE_Message_Block * +Text_Input_Device_Wrapper::create_input_message (void) +{ + + // Construct a new message block to send. + ACE_Message_Block *mb; + ACE_NEW_RETURN (mb, + ACE_Message_Block (read_length_), + 0); + + // Zero out a "read" buffer to hold data. + char read_buf [BUFSIZ]; + ACE_OS::memset (read_buf, 0, BUFSIZ); + + // Loop through the text, filling in data to copy into the read + // buffer (leaving room for a terminating zero). + for (size_t i = 0; i < read_length_ - 1; ++i) + { + read_buf [i] = text_ [index_]; + index_ = (index_ + 1) % ACE_OS::strlen (text_); + } + + // Copy buf into the Message_Block and update the wr_ptr (). + if (mb->copy (read_buf, read_length_) < 0) + { + delete mb; + ACE_ERROR_RETURN ((LM_ERROR, + "read buffer copy failed"), + 0); + } + + // log packet creation if logging is turned on + if (logging_ & Text_Input_Device_Wrapper::LOG_MSGS_CREATED) + { + ++packet_count_; + ACE_DEBUG ((LM_DEBUG, "input message %d created\n", + packet_count_)); + } + + return mb; +} + +// Constructor. + +Text_Output_Device_Wrapper::Text_Output_Device_Wrapper (int logging) + : logging_ (logging) +{ +} + +// Consume and possibly print out the passed message. + +int +Text_Output_Device_Wrapper::write_output_message (void *message) +{ + if (message) + { + ++packet_count_; + + if (logging_ & Text_Output_Device_Wrapper::LOG_MSGS_RCVD) + ACE_DEBUG ((LM_DEBUG, "output message %d received\n", + packet_count_)); + + if (logging_ & Text_Output_Device_Wrapper::PRINT_MSGS_RCVD) + ACE_DEBUG ((LM_DEBUG, "output message %d:\n[%s]\n", + packet_count_, + static_cast<ACE_Message_Block *> (message)-> + rd_ptr ())); + + delete static_cast<ACE_Message_Block *> (message); + return 0; + } + ACE_ERROR_RETURN ((LM_ERROR, + "Text_Output_Device_Wrapper::" + "write_output_message: null argument"), -1); +} + +// Modifies device settings based on passed pointer to a u_long. + +int +Text_Output_Device_Wrapper::modify_device_settings (void *logging) +{ + packet_count_ = 0; + + if (logging) + logging_ = *static_cast<int *> (logging); + else + ACE_ERROR_RETURN ((LM_ERROR, + "Text_Output_Device_Wrapper::modify_device_settings: " + "null argument"), + -1); + return 0; +} + +// Constructor. + +User_Input_Task::User_Input_Task (Bounded_Packet_Relay *relay, + Thread_Timer_Queue *queue, + Thread_Bounded_Packet_Relay_Driver &tbprd) + : ACE_Task_Base (ACE_Thread_Manager::instance ()), + usecs_ (ACE_ONE_SECOND_IN_USECS), + relay_ (relay), + queue_ (queue), + driver_ (tbprd) +{ +} + +// Destructor. + +User_Input_Task::~User_Input_Task (void) +{ + this->clear_all_timers (); +} + +// Runs the main event loop. + +int +User_Input_Task::svc (void) +{ + for (;;) + // Call back to the driver's implementation of how to read and + // parse input. + if (this->driver_.get_next_request () == -1) + break; + + // We are done. + this->relay_->end_transmission (Bounded_Packet_Relay::CANCELLED); + this->queue_->deactivate (); + ACE_DEBUG ((LM_DEBUG, + "terminating user input thread\n")); + this->clear_all_timers (); + return 0; +} + +// Sets the number of packets for the next transmission. + +int +User_Input_Task::set_packet_count (void *argument) +{ + if (argument) + { + driver_.packet_count (*static_cast<int *> (argument)); + return 0; + } + ACE_ERROR_RETURN ((LM_ERROR, + "User_Input_Task::set_packet_count: null argument"), + -1); +} + +// Sets the input device packet arrival period (usecs) for the next +// transmission. + +int +User_Input_Task::set_arrival_period (void *argument) +{ + if (argument) + { + driver_.arrival_period (*static_cast<int *> (argument)); + return 0; + } + ACE_ERROR_RETURN ((LM_ERROR, + "User_Input_Task::set_arrival_period: null argument"), + -1); +} + +// Sets the period between output device sends (usecs) for the next +// transmission. + +int +User_Input_Task::set_send_period (void *argument) +{ + if (argument) + { + driver_.send_period (*static_cast<int *> (argument)); + return 0; + } + ACE_ERROR_RETURN ((LM_ERROR, + "User_Input_Task::set_send_period: null argument"), + -1); +} + +// Sets a limit on the transmission duration (usecs). + +int +User_Input_Task::set_duration_limit (void *argument) +{ + if (argument) + { + driver_.duration_limit (*static_cast<int *> (argument)); + return 0; + } + ACE_ERROR_RETURN ((LM_ERROR, + "User_Input_Task::set_duration_limit: null argument"), + -1); +} + +// Sets logging level (0 or 1) for output device for the next +// transmission. + +int +User_Input_Task::set_logging_level (void *argument) +{ + if (argument) + { + driver_.logging_level (*static_cast<int *> (argument)); + return 0; + } + ACE_ERROR_RETURN ((LM_ERROR, + "User_Input_Task::set_logging_level: null argument"), + -1); +} + +// Runs the next transmission (if one is not in progress). + +int +User_Input_Task::run_transmission (void *) +{ + if (relay_) + { + switch (relay_->start_transmission (driver_.packet_count (), + driver_.arrival_period (), + driver_.logging_level ())) + { + case 1: + ACE_DEBUG ((LM_DEBUG, + "\nRun transmission: " + " Transmission already in progress\n")); + return 0; + /* NOTREACHED */ + case 0: + { + ACE_Time_Value now = ACE_OS::gettimeofday (); + ACE_Time_Value send_every (0, driver_.send_period ()); + ACE_Time_Value send_at (send_every + now); + + Send_Handler *send_handler; + ACE_NEW_RETURN (send_handler, + Send_Handler (driver_.packet_count (), + send_every, + *relay_, + *queue_, + driver_), + -1); + if (queue_->schedule (send_handler, 0, send_at) < 0) + { + delete send_handler; + ACE_ERROR_RETURN ((LM_ERROR, + "User_Input_Task::run_transmission: " + "failed to schedule send handler"), + -1); + } + if (driver_.duration_limit ()) + { + ACE_Time_Value terminate_at (0, driver_.duration_limit ()); + terminate_at += now; + + Termination_Handler *termination_handler; + + termination_handler = + new Termination_Handler (*relay_, + *queue_, + driver_); + + if (! termination_handler) + { + this->clear_all_timers (); + ACE_ERROR_RETURN ((LM_ERROR, + "User_Input_Task::run_transmission: " + "failed to allocate termination " + "handler"), + -1); + } + if (queue_->schedule (termination_handler, + 0, terminate_at) < 0) + { + delete termination_handler; + this->clear_all_timers (); + ACE_ERROR_RETURN ((LM_ERROR, + "User_Input_Task::run_transmission: " + "failed to schedule termination " + "handler"), + -1); + } + } + return 0; + } + /* NOTREACHED */ + default: + return -1; + /* NOTREACHED */ + } + } + ACE_ERROR_RETURN ((LM_ERROR, + "User_Input_Task::run_transmission: " + "relay not instantiated"), + -1); +} + +// Ends the current transmission (if one is in progress). + +int +User_Input_Task::end_transmission (void *) +{ + if (relay_) + { + switch (relay_->end_transmission (Bounded_Packet_Relay::CANCELLED)) + { + case 1: + ACE_DEBUG ((LM_DEBUG, + "\nEnd transmission: " + "no transmission in progress\n")); + /* Fall through to next case */ + case 0: + // Cancel any remaining timers. + this->clear_all_timers (); + return 0; + /* NOTREACHED */ + default: + return -1; + /* NOTREACHED */ + } + } + ACE_ERROR_RETURN ((LM_ERROR, + "User_Input_Task::end_transmission: " + "relay not instantiated"), + -1); +} + +// Reports statistics for the previous transmission +// (if one is not in progress). + +int +User_Input_Task::report_stats (void *) +{ + if (relay_) + { + switch (relay_->report_statistics ()) + { + case 1: + ACE_DEBUG ((LM_DEBUG, + "\nRun transmission: " + "\ntransmission already in progress\n")); + return 0; + /* NOTREACHED */ + + case 0: + this->clear_all_timers (); + return 0; + /* NOTREACHED */ + + default: + return -1; + /* NOTREACHED */ + } + } + ACE_ERROR_RETURN ((LM_ERROR, + "User_Input_Task::report_stats: " + "relay not instantiated"), + -1); +} + +// Shut down the task. + +int +User_Input_Task::shutdown (void *) +{ + // Clear any outstanding timers. + this->clear_all_timers (); + +#if !defined (ACE_LACKS_PTHREAD_CANCEL) + // Cancel the thread timer queue task "preemptively." + ACE_Thread::cancel (this->queue_->thr_id ()); +#else + // Cancel the thread timer queue task "voluntarily." + this->queue_->deactivate (); +#endif /* ACE_LACKS_PTHREAD_CANCEL */ + + // -1 indicates we are shutting down the application. + return -1; +} + +// Helper method: clears all timers. + +int +User_Input_Task::clear_all_timers (void) +{ + // loop through the timers in the queue, cancelling each one + for (ACE_Timer_Node_T <ACE_Event_Handler *> *node; + (node = queue_->timer_queue ()->get_first ()) != 0; + ) + queue_->timer_queue ()->cancel (node->get_timer_id (), 0, 0); + + return 0; +} + +// Constructor. + +BPR_Handler_Base::BPR_Handler_Base (Bounded_Packet_Relay &relay, + Thread_Timer_Queue &queue) + : relay_ (relay), + queue_ (queue) +{ +} + +// Destructor. + +BPR_Handler_Base::~BPR_Handler_Base (void) +{ +} + +// Helper method: clears all timers. + +int +BPR_Handler_Base::clear_all_timers (void *) +{ + // Loop through the timers in the queue, cancelling each one. + + for (ACE_Timer_Node_T <ACE_Event_Handler *> *node; + (node = queue_.timer_queue ()->get_first ()) != 0; + ) + queue_.timer_queue ()->cancel (node->get_timer_id (), 0, 0); + // queue_.cancel (node->get_timer_id (), 0); + + // Invoke the handler's (virtual) destructor + delete this; + + return 0; +} + +// Constructor. + +Send_Handler::Send_Handler (u_long send_count, + const ACE_Time_Value &duration, + Bounded_Packet_Relay &relay, + Thread_Timer_Queue &queue, + Thread_Bounded_Packet_Relay_Driver &driver) + : BPR_Handler_Base (relay, queue), + send_count_ (send_count), + duration_ (duration), + driver_ (driver) +{ +} + +// Destructor. + +Send_Handler::~Send_Handler (void) +{ +} + +// Call back hook. + +int +Send_Handler::handle_timeout (const ACE_Time_Value &, + const void *) +{ + switch (relay_.send_input ()) + { + case 0: + // Decrement count of packets to relay. + --send_count_; + /* Fall through to next case. */ + case 1: + if (send_count_ > 0) + { + // Enqueue a deferred callback to the reregister command. + SEND_HANDLER_CMD *re_register_callback_; + ACE_NEW_RETURN (re_register_callback_, + SEND_HANDLER_CMD (*this, + &Send_Handler::reregister), + -1); + return queue_.enqueue_command (re_register_callback_); + } + else + { + // All packets are sent, time to end the transmission, redisplay + // the user menu, cancel any other timers, and go away. + relay_.end_transmission (Bounded_Packet_Relay::COMPLETED); + driver_.display_menu (); + + // Enqueue a deferred callback to the clear_all_timers command. + HANDLER_CMD *clear_timers_callback_; + ACE_NEW_RETURN (clear_timers_callback_, + HANDLER_CMD (*this, + &BPR_Handler_Base::clear_all_timers), + -1); + return queue_.enqueue_command (clear_timers_callback_); + } + /* NOTREACHED */ + default: + return -1; + } +} + +// Cancellation hook. + +int +Send_Handler::cancelled (void) +{ + delete this; + return 0; +} + +// Helper method: re-registers this timer + +int +Send_Handler::reregister (void *) +{ + // Re-register the handler for a new timeout. + if (queue_.schedule (this, + 0, + duration_ + ACE_OS::gettimeofday ()) < 0) + ACE_ERROR_RETURN ((LM_ERROR, + "Send_Handler::reregister: " + "failed to reschedule send handler"), + -1); + + return 0; +} + + +// Constructor. + +Termination_Handler::Termination_Handler (Bounded_Packet_Relay &relay, + Thread_Timer_Queue &queue, + Thread_Bounded_Packet_Relay_Driver &driver) + : BPR_Handler_Base (relay, queue), + driver_ (driver) +{ +} + +// Destructor. + +Termination_Handler::~Termination_Handler (void) +{ +} + +// Call back hook. + +int +Termination_Handler::handle_timeout (const ACE_Time_Value &, + const void *) +{ + // Transmission timed out, so end the transmission, display the user + // menu, and register a callback to clear the timer queue and then + // make this object go away. + relay_.end_transmission (Bounded_Packet_Relay::TIMED_OUT); + driver_.display_menu (); + + // Enqueue a deferred callback to the clear_all_timers command. + HANDLER_CMD *clear_timers_callback_; + ACE_NEW_RETURN (clear_timers_callback_, + HANDLER_CMD (*this, + &BPR_Handler_Base::clear_all_timers), + -1); + return queue_.enqueue_command (clear_timers_callback_); +} + +// Cancellation hook + +int +Termination_Handler::cancelled (void) +{ + delete this; + return 0; +} + +// Constructor. + +Thread_Bounded_Packet_Relay_Driver::Thread_Bounded_Packet_Relay_Driver (Bounded_Packet_Relay *relay) + : input_task_ (relay, &timer_queue_, *this) +{ +} + +// Destructor. + +Thread_Bounded_Packet_Relay_Driver::~Thread_Bounded_Packet_Relay_Driver (void) +{ +} + +// Display the user menu. + +int +Thread_Bounded_Packet_Relay_Driver::display_menu (void) +{ + static char menu[] = + "\n\n Options:\n" + " ----------------------------------------------------------------------\n" + " 1 <number of packets to relay in one transmission = %d>\n" + " min = 1 packet.\n" + " 2 <input packet arrival period (in usec) = %d>\n" + " min = 1.\n" + " 3 <output packet transmission period (in usec) = %d>\n" + " min = 1.\n" + " 4 <limit on duration of transmission (in usec) = %d>\n" + " min = 1, no limit = 0.\n" + " 5 <logging level flags = %d>\n" + " no logging = 0,\n" + " log packets created by input device = 1,\n" + " log packets consumed by output device = 2,\n" + " logging options 1,2 = 3,\n" + " print contents of packets consumed by output put device = 4,\n" + " logging options 1,4 = 5,\n" + " logging options 2,4 = 6,\n" + " logging options 1,2,4 = 7.\n" + " ----------------------------------------------------------------------\n" + " 6 - runs a transmission using the current settings\n" + " 7 - cancels a transmission (if there is one running)\n" + " 8 - reports statistics from the most recent transmission\n" + " 9 - quits the program\n" + " ----------------------------------------------------------------------\n" + " Please enter your choice: "; + + ACE_DEBUG ((LM_DEBUG, + menu, + this->packet_count (), + this->arrival_period (), + this->send_period (), + this->duration_limit (), + this->logging_level ())); + + return 0; +} + +// Initialize the driver. + +int +Thread_Bounded_Packet_Relay_Driver::init (void) +{ + // Initialize the <Command> objects with their corresponding + // methods from <User_Input_Task>. + ACE_NEW_RETURN (packet_count_cmd_, + DRIVER_CMD (input_task_, + &User_Input_Task::set_packet_count), + -1); + ACE_NEW_RETURN (arrival_period_cmd_, + DRIVER_CMD (input_task_, + &User_Input_Task::set_arrival_period), + -1); + ACE_NEW_RETURN (transmit_period_cmd_, + DRIVER_CMD (input_task_, + &User_Input_Task::set_send_period), + -1); + ACE_NEW_RETURN (duration_limit_cmd_, + DRIVER_CMD (input_task_, + &User_Input_Task::set_duration_limit), + -1); + ACE_NEW_RETURN (logging_level_cmd_, + DRIVER_CMD (input_task_, + &User_Input_Task::set_logging_level), + -1); + ACE_NEW_RETURN (run_transmission_cmd_, + DRIVER_CMD (input_task_, + &User_Input_Task::run_transmission), + -1); + ACE_NEW_RETURN (cancel_transmission_cmd_, + DRIVER_CMD (input_task_, + &User_Input_Task::end_transmission), + -1); + ACE_NEW_RETURN (report_stats_cmd_, + DRIVER_CMD (input_task_, + &User_Input_Task::report_stats), + -1); + ACE_NEW_RETURN (shutdown_cmd_, + DRIVER_CMD (input_task_, + &User_Input_Task::shutdown), + -1); + if (this->input_task_.activate () == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "cannot activate input task"), + -1); + else if (this->timer_queue_.activate () == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "cannot activate timer queue"), + -1); + else if (ACE_Thread_Manager::instance ()->wait () == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "wait on Thread_Manager failed"), + -1); + return 0; +} + +// Run the driver + +int +Thread_Bounded_Packet_Relay_Driver::run (void) +{ + this->init (); + return 0; +} + diff --git a/ACE/examples/Bounded_Packet_Relay/Thread_Bounded_Packet_Relay.h b/ACE/examples/Bounded_Packet_Relay/Thread_Bounded_Packet_Relay.h new file mode 100644 index 00000000000..ccd5782b487 --- /dev/null +++ b/ACE/examples/Bounded_Packet_Relay/Thread_Bounded_Packet_Relay.h @@ -0,0 +1,400 @@ +/* -*- C++ -*- */ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// examples +// +// = FILENAME +// Thread_Bounded_Packet_Relay.h +// +// = DESCRIPTION +// This code provides a thread based implementation +// of the bounded packet relay example. +// +// = AUTHORS +// Chris Gill <cdgill@cs.wustl.edu> and +// Douglas C. Schmidt <schmidt@cs.wustl.edu> +// +// Based on the Timer Queue Test example written by +// +// Carlos O'Ryan <coryan@cs.wustl.edu> and +// Douglas C. Schmidt <schmidt@cs.wustl.edu> and +// Sergio Flores-Gaitan <sergio@cs.wustl.edu> +// +// ============================================================================ + +#ifndef _THREAD_BOUNDED_PACKET_RELAY_H_ +#define _THREAD_BOUNDED_PACKET_RELAY_H_ + +#include "ace/Functor_T.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Task.h" +#include "ace/Timer_Heap_T.h" +#include "ace/Timer_Queue_Adapters.h" +#include "BPR_Drivers.h" + +// These typedefs ensure that we use the minimal amount of locking +// necessary. +typedef ACE_Event_Handler_Handle_Timeout_Upcall<ACE_Null_Mutex> + Upcall; +typedef ACE_Timer_Heap_T<ACE_Event_Handler *, + Upcall, + ACE_Null_Mutex> + Timer_Heap; +typedef ACE_Timer_Heap_Iterator_T<ACE_Event_Handler *, + Upcall, + ACE_Null_Mutex> + Timer_Heap_Iterator; +typedef ACE_Thread_Timer_Queue_Adapter<Timer_Heap> + Thread_Timer_Queue; + +// Forward declaration. +class Thread_Bounded_Packet_Relay_Driver; + +class Text_Input_Device_Wrapper : public Input_Device_Wrapper_Base +{ + // = TITLE + // Defines a wrapper for a simple active looping text input + // pseudo-device. + // + // = DESCRIPTION + // The wrapper is an active object, running in its own thread, + // and uses a reactor to generate timeouts. When a timeout + // occurs, the wrapper calls its concrete message creation + // method. The wrapper then calls its base class message send + // method to forward the message to the receiver. + // + // A more sophisticated version of this class would use the + // reactive capabilities as well as the timeout generating + // capabilities of the reactor, multiplexing several input + // streams. Comments to this effect appear in the definition of + // the event loop method. +public: + + // = Enumerated logging level flags + enum Logging_Flags {NO_LOGGING = 0, + LOG_MSGS_CREATED = 1}; + + // = Initialization and termination methods. + Text_Input_Device_Wrapper (ACE_Thread_Manager *input_task_mgr, + size_t read_length, + const char* text, + int logging = 0); + // Constructor. + + virtual ~Text_Input_Device_Wrapper (void); + // Destructor. + + virtual int modify_device_settings (void *logging); + // Modifies device settings based on passed pointer to a u_long. + // Turns logging on if u_long is non-zero, off if u_long is zero, + // and does nothing if the pointer is null. + +protected: + virtual ACE_Message_Block *create_input_message (void); + // Creates a new message block, carrying data read from the + // underlying input device. + +private: + size_t read_length_; + // Length of the buffer into which to "read". + + const char *text_; + // Text to "read" into the buffer. + + size_t index_; + // Index into the string. + + int logging_; + // This value is 0 if logging is turned off, non-zero otherwise + + u_long packet_count_; + // This value holds a count of packets created. + +}; + +class Text_Output_Device_Wrapper : public Output_Device_Wrapper_Base +{ + // = TITLE + // Implements a simple wrapper for a output pseudo-device. + // + // = DESCRIPTION + // Data from the passed output message is printed to the standard + // output stream, if logging is turned on. +public: + + // = Enumerated logging level flags + enum Logging_Flags {NO_LOGGING = 0, + LOG_MSGS_RCVD = 2, + PRINT_MSGS_RCVD = 4}; + + Text_Output_Device_Wrapper (int logging = 0); + // Default constructor. + + // = Command Accessible Entry Points + + virtual int write_output_message (void *message); + // Consumes and possibly prints out the passed message. + + virtual int modify_device_settings (void *logging); + // Modifies device settings based on passed pointer to a u_long. + // Turns logging on if u_long is non-zero, off if u_long is zero, + // and does nothing if the pointer is null. + +private: + + int logging_; + // This value holds the logging level. + + u_long packet_count_; + // This value holds a count of packets received. + +}; + +class User_Input_Task : public ACE_Task_Base +{ + // = TITLE + // Read user actions on the Timer_Queue from stdin. + // + // = DESCRIPTION + // This class reads user input from stdin. The commands allow + // the control of a Timer_Queue, which is dispatched by another + // thread. +public: + + // = Trait for command accessible entry points. + + typedef int (User_Input_Task::*ACTION) (void *); + + User_Input_Task (Bounded_Packet_Relay *relay, + Thread_Timer_Queue *queue, + Thread_Bounded_Packet_Relay_Driver &timer_queue_driver); + // Constructor. + + virtual ~User_Input_Task (void); + // Destructor. + + virtual int svc (void); + // This method runs the event loop in the new thread. + + // = Some helper methods. + + int set_packet_count (void *); + // Sets the number of packets for the next transmission. + + int set_arrival_period (void *); + // Sets the input device packet arrival period (usecs) for the next + // transmission. + + int set_send_period (void *); + // Sets the period between output device sends (usecs) for the next + // transmission. + + int set_duration_limit (void *); + // Sets a limit on the transmission duration (usecs). + + int set_logging_level (void *); + // Sets logging level (0 or 1) for output device for the next + // transmission. + + int run_transmission (void *); + // Runs the next transmission (if one is not in progress). + + int end_transmission (void *); + // Ends the current transmission (if one is in progress). + + int report_stats (void *); + // Reports statistics for the previous transmission (if one is not + // in progress). + + int shutdown (void *); + // Shuts down the task. + + int clear_all_timers (void); + // Helper method: clears all timers. + +private: + const int usecs_; + // How many microseconds are in a second. + + Bounded_Packet_Relay *relay_; + // The bounded packet relay. + + Thread_Timer_Queue *queue_; + // The timer queue implementation. + + Thread_Bounded_Packet_Relay_Driver &driver_; + // The thread timer queue test driver. +}; + +class BPR_Handler_Base : public ACE_Event_Handler +{ + // = TITLE + // Base event handler class for bounded packet relay example. + // + // = DESCRIPTION + // The base class provides a helper method that derived classes + // can register as a deferred execution callback that will cancel + // all timers in the underlying timer queue, and then delete "this". + // +public: + + // = Trait for command accessible entry points. + + typedef int (BPR_Handler_Base::*ACTION) (void *); + + + BPR_Handler_Base (Bounded_Packet_Relay &relay, + Thread_Timer_Queue &queue); + // Constructor. + + virtual ~BPR_Handler_Base (void); + // Destructor. + + // = Command accessible entry points. + + virtual int clear_all_timers (void *); + // Helper method: clears all timers. + +protected: + Bounded_Packet_Relay &relay_; + // Stores a reference to the relay object on which to invoke + // the appropritate calls when the timer expires. + + Thread_Timer_Queue &queue_; + // Store a reference to the timer queue, in which to re-register + // the send timer and handler if there are still sends to perform. +}; + +class Send_Handler; + +class Send_Handler : public BPR_Handler_Base +{ + // = TITLE + // Event handler for message send timeout events. + // + // = DESCRIPTION + // The <handle_timeout> hook method calls the relay's send + // method and decrements its count of messages to send. + // If there are still messages to send, it re-registers itself + // with the timer queue. Otherwise it calls the relay's end + // transmission method, and registers a deferred execution + // callback to clear the timer queue, and then delete "this". +public: + + // = Trait for command accessible entry points. + + typedef int (Send_Handler::*ACTION) (void *); + + Send_Handler (u_long send_count, + const ACE_Time_Value &duration, + Bounded_Packet_Relay &relay, + Thread_Timer_Queue &queue, + Thread_Bounded_Packet_Relay_Driver &driver); + // Constructor. + + virtual ~Send_Handler (void); + // Destructor. + + virtual int handle_timeout (const ACE_Time_Value ¤t_time, + const void *arg); + // Call back hook. + + virtual int cancelled (void); + // Cancellation hook. + + // = Command accessible entry points. + + virtual int reregister (void *timeout); + // Helper method: re-registers this handler. + +private: + + u_long send_count_; + // Count of the number of messages to send from the + // relay object to the output device object. + + ACE_Time_Value duration_; + // Stores the expected duration until expiration, and is used to + // re-register the handler if there are still sends to perform. + + Thread_Bounded_Packet_Relay_Driver &driver_; + // Reference to the driver that will redisplay the user input menu. +}; + +class Termination_Handler : public BPR_Handler_Base +{ + // = TITLE + // Event handler for end transmission timeout events. + // + // = DESCRIPTION + // The <handle_timeout> hook method calls the relay's end + // transmission method, then registers a deferred execution + // callback to clear all timers and then delete "this". +public: + Termination_Handler (Bounded_Packet_Relay &relay, + Thread_Timer_Queue &queue, + Thread_Bounded_Packet_Relay_Driver &driver); + // Constructor. + + virtual ~Termination_Handler (void); + // Destructor. + + virtual int handle_timeout (const ACE_Time_Value ¤t_time, + const void *arg); + // Call back hook. + + virtual int cancelled (void); + // Cancellation hook. + +private: + Thread_Bounded_Packet_Relay_Driver &driver_; + // Reference to the driver that will redisplay the user input menu. +}; + +class Thread_Bounded_Packet_Relay_Driver : public Bounded_Packet_Relay_Driver <Thread_Timer_Queue> +{ + // = TITLE + // Implements an example application that exercises + // <Thread_Timer_Queue> timer queue. + // + // = DESCRIPTION + // This class implements a simple test driver for the + // <Thread_Timer_Queue>. The <display_menu> hook method is + // called from the base class to print a menu specific to the + // thread implementation of the timer queue. +public: + + // = Trait for commands issued from this driver + + typedef ACE_Command_Callback<User_Input_Task, User_Input_Task::ACTION> MYCOMMAND; + + // = Initialization and termination methods. + + Thread_Bounded_Packet_Relay_Driver (Bounded_Packet_Relay *relay); + // Constructor. + + virtual ~Thread_Bounded_Packet_Relay_Driver (void); + // Destructor. + + virtual int display_menu (void); + // Displays the user menu. + + virtual int init (void); + // Initializes the driver. + + virtual int run (void); + // Run the driver. + +private: + User_Input_Task input_task_; + // User input task, subclassed from ACE_Task. +}; + +#endif /* _THREAD_BOUNDED_PACKET_RELAY_H_ */ diff --git a/ACE/examples/Bounded_Packet_Relay/bpr_thread.cpp b/ACE/examples/Bounded_Packet_Relay/bpr_thread.cpp new file mode 100644 index 00000000000..0a564ecd2a5 --- /dev/null +++ b/ACE/examples/Bounded_Packet_Relay/bpr_thread.cpp @@ -0,0 +1,122 @@ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// examples +// +// = FILENAME +// bpr_thread.cpp +// +// = DESCRIPTION +// Exercises drivers for a bounded packet relay, based on threaded timer queues. +// +// = AUTHORS +// Chris Gill <cdgill@cs.wustl.edu> and +// Douglas C. Schmidt <schmidt@cs.wustl.edu> +// +// Based on the Timer Queue Test example written by +// +// Carlos O'Ryan <coryan@cs.wustl.edu> and +// Douglas C. Schmidt <schmidt@cs.wustl.edu> and +// Sergio Flores-Gaitan <sergio@cs.wustl.edu> +// +// ============================================================================ + +// The following #pragma is needed to disable a warning that occurs +// in MSVC 6 due to the overly long debugging symbols generated for +// the std::auto_ptr<Timer_Queue_Test_Driver<...> > template +// instance used by some of the methods in this file. +#ifdef _MSC_VER +# pragma warning(disable: 4786) /* identifier was truncated to '255' + characters in the browser + information */ +#endif /* _MSC_VER */ + +#include "ace/Auto_Ptr.h" +#include "Thread_Bounded_Packet_Relay.h" + +ACE_RCSID (Bounded_Packet_Relay, + bpr_thread, + "$Id$") + +typedef Bounded_Packet_Relay_Driver<Thread_Timer_Queue> + THREAD_BOUNDED_PACKET_RELAY_DRIVER; + +typedef ACE_Command_Callback<Bounded_Packet_Relay,Bounded_Packet_Relay::ACTION> + INPUT_CALLBACK; + +// A snippet from Andrew Marvell (Oliver Cromwell's poet laureate) +static const char input_text [] = +"But ever at my back I hear\n" +" Time's winged chariot hurrying near."; + +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + // Construct a new thread manager for the input device task. Auto + // ptr ensures memory is freed when we exit this scope. + ACE_Thread_Manager *input_task_mgr; + ACE_NEW_RETURN (input_task_mgr, + ACE_Thread_Manager, + -1); + auto_ptr <ACE_Thread_Manager> mgr (input_task_mgr); + + // Construct a new input device wrapper. Auto ptr ensures memory is + // freed when we exit this scope. + Text_Input_Device_Wrapper *input_device; + ACE_NEW_RETURN (input_device, + Text_Input_Device_Wrapper (input_task_mgr, + sizeof (input_text), + input_text), + -1); + auto_ptr <Text_Input_Device_Wrapper> input (input_device); + + // Construct a new output device wrapper. Auto ptr ensures memory + // is freed when we exit this scope. + Text_Output_Device_Wrapper *output_device; + ACE_NEW_RETURN (output_device, + Text_Output_Device_Wrapper, + -1); + auto_ptr <Text_Output_Device_Wrapper> output (output_device); + + // Construct a new bounded packet relay. Auto ptr ensures memory is + // freed when we exit this scope. + Bounded_Packet_Relay *packet_relay; + ACE_NEW_RETURN (packet_relay, + Bounded_Packet_Relay (input_task_mgr, + input_device, + output_device), + -1); + auto_ptr <Bounded_Packet_Relay> relay (packet_relay); + + // Construct a receive input callback command for the relay, and register + // it with the input device. Auto ptr ensures memory is freed when we exit + // this scope. + INPUT_CALLBACK *input_callback; + ACE_NEW_RETURN (input_callback, + INPUT_CALLBACK (*packet_relay, + &Bounded_Packet_Relay::receive_input), + -1); + auto_ptr <INPUT_CALLBACK> callback (input_callback); + if (input_device->set_send_input_msg_cmd (input_callback) < 0) + { + ACE_ERROR_RETURN ((LM_ERROR, + "failed to register input callback"), + -1); + } + + // Construct a new bounded packet relay driver. Auto ptr ensures + // memory is freed when we exit this scope. + THREAD_BOUNDED_PACKET_RELAY_DRIVER *tbprd; + + ACE_NEW_RETURN (tbprd, + Thread_Bounded_Packet_Relay_Driver (packet_relay), + -1); + + auto_ptr <THREAD_BOUNDED_PACKET_RELAY_DRIVER> driver (tbprd); + + return driver->run (); + // All dynamically allocated memory is released when main() returns. +} + diff --git a/ACE/examples/C++NPv1/.cvsignore b/ACE/examples/C++NPv1/.cvsignore new file mode 100644 index 00000000000..7735c154a0c --- /dev/null +++ b/ACE/examples/C++NPv1/.cvsignore @@ -0,0 +1,14 @@ +RTTPC_logging_server +RTTPC_logging_server +iterative_logging_server +iterative_logging_server +logging_client +logging_client +ppc_logging_server +ppc_logging_server +reactive_logging_server +reactive_logging_server +reactive_logging_server_ex +reactive_logging_server_ex +tpc_logging_server +tpc_logging_server diff --git a/ACE/examples/C++NPv1/C++NPv1.mpc b/ACE/examples/C++NPv1/C++NPv1.mpc new file mode 100644 index 00000000000..2cc6967e831 --- /dev/null +++ b/ACE/examples/C++NPv1/C++NPv1.mpc @@ -0,0 +1,70 @@ +// -*- MPC -*- +// $Id$ + +project(*Iterative_Logging_Server) : aceexe { + avoids += uses_wchar ace_for_tao + exename = iterative_logging_server + Source_Files { + Iterative_Logging_Server.cpp + Logging_Server.cpp + Logging_Handler.cpp + } +} + +project(*Logging_Client) : aceexe { + avoids += uses_wchar + exename = logging_client + Source_Files { + Logging_Client.cpp + } +} + +project(*PPC_Logging_Server) : aceexe { + avoids += uses_wchar ace_for_tao + exename = ppc_logging_server + Source_Files { + Process_Per_Connection_Logging_Server.cpp + Logging_Server.cpp + Logging_Handler.cpp + } +} + +project(*Reactive_Logging_Server) : aceexe { + avoids += uses_wchar ace_for_tao + exename = reactive_logging_server + Source_Files { + Reactive_Logging_Server.cpp + Logging_Server.cpp + Logging_Handler.cpp + } +} + +project(*Reactive_Logging_Server_Ex) : aceexe { + avoids += uses_wchar ace_for_tao + exename = reactive_logging_server_ex + Source_Files { + Reactive_Logging_Server_Ex.cpp + Logging_Server.cpp + Logging_Handler.cpp + } +} + +project(*RTTPC_Logging_Server) : aceexe { + avoids += uses_wchar ace_for_tao + exename = RTTPC_logging_server + Source_Files { + RT_Thread_Per_Connection_Logging_Server.cpp + Logging_Server.cpp + Logging_Handler.cpp + } +} + +project(*TPC_Logging_Server) : aceexe { + avoids += uses_wchar ace_for_tao + exename = tpc_logging_server + Source_Files { + Thread_Per_Connection_Logging_Server.cpp + Logging_Server.cpp + Logging_Handler.cpp + } +} diff --git a/ACE/examples/C++NPv1/Iterative_Logging_Server.cpp b/ACE/examples/C++NPv1/Iterative_Logging_Server.cpp new file mode 100644 index 00000000000..f4c28f08da7 --- /dev/null +++ b/ACE/examples/C++NPv1/Iterative_Logging_Server.cpp @@ -0,0 +1,17 @@ +/* +** $Id$ +** +** Copyright 2001 Addison Wesley. All Rights Reserved. +*/ + +#include "ace/Log_Msg.h" +#include "Iterative_Logging_Server.h" + +int main (int argc, char *argv[]) +{ + Iterative_Logging_Server server; + + if (server.run (argc, argv) == -1) + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "server.run()"), 1); + return 0; +} diff --git a/ACE/examples/C++NPv1/Iterative_Logging_Server.h b/ACE/examples/C++NPv1/Iterative_Logging_Server.h new file mode 100644 index 00000000000..f811f98c7ce --- /dev/null +++ b/ACE/examples/C++NPv1/Iterative_Logging_Server.h @@ -0,0 +1,64 @@ +/* +** $Id$ +** +** Copyright 2001 Addison Wesley. All Rights Reserved. +*/ + +#ifndef _ITERATIVE_LOGGING_SERVER_H +#define _ITERATIVE_LOGGING_SERVER_H + +#include "ace/FILE_IO.h" +#include "ace/INET_Addr.h" +#include "ace/Log_Msg.h" + +#include "Logging_Handler.h" +#include "Logging_Server.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL +class ACE_SOCK_Stream; +ACE_END_VERSIONED_NAMESPACE_DECL + +class Iterative_Logging_Server : public Logging_Server +{ +protected: + ACE_FILE_IO log_file_; + Logging_Handler logging_handler_; + +public: + Iterative_Logging_Server () : logging_handler_ (log_file_) {} + + virtual ~Iterative_Logging_Server () { log_file_.close (); } + + Logging_Handler &logging_handler () { return logging_handler_; } + +protected: + // Override inherited open() from Logging_Server + virtual int open (u_short port) { + if (make_log_file (log_file_) == -1) + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "make_log_file()"), -1); + return Logging_Server::open (port); + } + + virtual int handle_connections () { + ACE_INET_Addr logging_peer_addr; + + if (acceptor ().accept (logging_handler_.peer (), + &logging_peer_addr) == -1) + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "acceptor.accept()"), -1); + + ACE_DEBUG ((LM_DEBUG, "Accepted connection from %s\n", + logging_peer_addr.get_host_name ())); + return 0; + } + + virtual int handle_data (ACE_SOCK_Stream *) { + while (logging_handler_.log_record () != -1) + continue; + + logging_handler_.close (); // Close the socket handle. + return 0; + } + +}; + +#endif /* _ITERATIVE_LOGGING_SERVER_H */ diff --git a/ACE/examples/C++NPv1/Logging_Client.cpp b/ACE/examples/C++NPv1/Logging_Client.cpp new file mode 100644 index 00000000000..40f2609f30a --- /dev/null +++ b/ACE/examples/C++NPv1/Logging_Client.cpp @@ -0,0 +1,141 @@ +/* +** $Id$ +** +** Copyright 2001 Addison Wesley. All Rights Reserved. +*/ + +#include "ace/OS_NS_sys_time.h" +#include "ace/CDR_Stream.h" +#include "ace/INET_Addr.h" +#include "ace/SOCK_Connector.h" +#include "ace/SOCK_Stream.h" +#include "ace/Log_Msg.h" +#include "ace/Log_Record.h" +#include "ace/OS_NS_unistd.h" + +// FUZZ: disable check_for_streams_include +#include "ace/streams.h" + +#if defined (ACE_WIN32) && (!defined (ACE_HAS_STANDARD_CPP_LIBRARY) || \ + (ACE_HAS_STANDARD_CPP_LIBRARY == 0) || \ + defined (ACE_USES_OLD_IOSTREAMS)) +# include <stdio.h> +#else +# include <string> +#endif + +class Logging_Client { +private: + ACE_SOCK_Stream logging_peer_; + +public: + ACE_SOCK_Stream &peer () { return logging_peer_; } + + int send (const ACE_Log_Record &log_record) { + // Serialize the log record using a CDR stream, allocate + // enough space for the complete <ACE_Log_Record>. + const size_t max_payload_size = + 4 // type() + + 8 // timestamp + + 4 // process id + + 4 // data length + + ACE_Log_Record::MAXLOGMSGLEN // data + + ACE_CDR::MAX_ALIGNMENT; // padding; + + // Insert contents of <log_record> into payload stream. + ACE_OutputCDR payload (max_payload_size); + payload << log_record; + + // Get the number of bytes used by the CDR stream. + ACE_CDR::ULong length = payload.total_length (); + + // Send a header so the receiver can determine the byte + // order and size of the incoming CDR stream. + ACE_OutputCDR header (ACE_CDR::MAX_ALIGNMENT + 8); + header << ACE_OutputCDR::from_boolean (ACE_CDR_BYTE_ORDER); + + // Store the size of the payload that follows + header << ACE_CDR::ULong (length); + // Use an iovec to send both buffer and payload simultaneously. + iovec iov[2]; + iov[0].iov_base = header.begin ()->rd_ptr (); + iov[0].iov_len = 8; + iov[1].iov_base = payload.begin ()->rd_ptr (); + iov[1].iov_len = length; + + // Send header and payload efficiently using "gather-write". + return logging_peer_.sendv_n (iov, 2); + } + + ~Logging_Client () { logging_peer_.close (); } +}; + + +int main (int argc, char *argv[]) +{ + u_short logger_port = argc > 1 ? atoi (argv[1]) : 0; + const char *logger_host = + argc > 2 ? argv[2] : ACE_DEFAULT_SERVER_HOST; + int result; + + ACE_INET_Addr server_addr; + + if (logger_port != 0) + result = server_addr.set (logger_port, logger_host); + else + result = server_addr.set ("ace_logger", logger_host); + if (result == -1) + ACE_ERROR_RETURN ((LM_ERROR, "lookup %s, %p\n", + logger_port == 0 ? "ace_logger" : argv[1], + logger_host), 1); + + ACE_SOCK_Connector connector; + Logging_Client logging_client; + + if (connector.connect (logging_client.peer (), server_addr) < 0) + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "connect()"), 1); + +#if defined (ACE_WIN32) && (!defined (ACE_HAS_STANDARD_CPP_LIBRARY) || \ + (ACE_HAS_STANDARD_CPP_LIBRARY == 0) || \ + defined (ACE_USES_OLD_IOSTREAMS)) + for (;;) { + char user_input[ACE_Log_Record::MAXLOGMSGLEN]; + if (!gets (user_input)) + break; + + ACE_Time_Value now (ACE_OS::gettimeofday ()); + ACE_Log_Record log_record (LM_INFO, now, ACE_OS::getpid ()); + log_record.msg_data (user_input); + if (logging_client.send (log_record) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", "logging_client.send()"), 1); + } +#else + + // Limit the number of characters read on each record + cin.width (ACE_Log_Record::MAXLOGMSGLEN); + + for (;;) { + +#if defined (ACE_USES_STD_NAMESPACE_FOR_STDCPP_LIB) && (ACE_USES_STD_NAMESPACE_FOR_STDCPP_LIB == 0) + string user_input; + getline (cin, user_input, '\n'); +#else + std::string user_input; + std::getline (cin, user_input, '\n'); + +#endif + + if (!cin || cin.eof ()) break; + + ACE_Time_Value now (ACE_OS::gettimeofday ()); + ACE_Log_Record log_record (LM_INFO, now, ACE_OS::getpid ()); + log_record.msg_data (user_input.c_str ()); + if (logging_client.send (log_record) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", "logging_client.send()"), 1); + } +#endif + + return 0; // Logging_Client destructor closes TCP connection. +} diff --git a/ACE/examples/C++NPv1/Logging_Handler.cpp b/ACE/examples/C++NPv1/Logging_Handler.cpp new file mode 100644 index 00000000000..b24066fc208 --- /dev/null +++ b/ACE/examples/C++NPv1/Logging_Handler.cpp @@ -0,0 +1,110 @@ +/* +** $Id$ +** +** Copyright 2001 Addison Wesley. All Rights Reserved. +*/ + +#include "ace/ACE.h" +#include "ace/CDR_Stream.h" +#include "ace/INET_Addr.h" +#include "ace/Log_Record.h" +#include "ace/Message_Block.h" + +#include "Logging_Handler.h" + +// FUZZ: disable check_for_streams_include +#include "ace/streams.h" + +#include "ace/os_include/os_netdb.h" + +int Logging_Handler::recv_log_record (ACE_Message_Block *&mblk) +{ + // Put <logging_peer>'s hostname in new message block. + ACE_INET_Addr peer_addr; + logging_peer_.get_remote_addr (peer_addr); + mblk = new ACE_Message_Block (MAXHOSTNAMELEN + 1); + peer_addr.get_host_name (mblk->wr_ptr (), MAXHOSTNAMELEN); + mblk->wr_ptr (strlen (mblk->wr_ptr ()) + 1); // Go past name + + // Allocate a message block for the payload; initially at least + // large enough to hold the header, but needs some room for + // alignment. + ACE_Message_Block *payload = + new ACE_Message_Block (ACE_DEFAULT_CDR_BUFSIZE); + // Align the Message Block for a CDR stream + ACE_CDR::mb_align (payload); + if (logging_peer_.recv_n (payload->wr_ptr (), 8) == 8) { + payload->wr_ptr (8); // Reflect addition of 8 bytes + + // Create a CDR stream to parse the 8-byte header. + ACE_InputCDR cdr (payload); + + // Extract the byte-order and use helper methods to + // disambiguate octet, booleans, and chars. + ACE_CDR::Boolean byte_order; + cdr >> ACE_InputCDR::to_boolean (byte_order); + + // Set the byte-order on the stream... + cdr.reset_byte_order (byte_order); + + // Extract the length + ACE_CDR::ULong length; + cdr >> length; + + // Ensure there's sufficient room for log record payload. + ACE_CDR::grow (payload, 8 + ACE_CDR::MAX_ALIGNMENT + length); + + // Use <recv_n> to obtain the contents. + if (logging_peer_.recv_n (payload->wr_ptr (), length) > 0) { + payload->wr_ptr (length); // Reflect additional bytes + // Chain the payload to mblk via the contination field. + mblk->cont (payload); + return length; + } + } + // Error cases end up here, so we need to release the memory to + // prevent a leak. + payload->release (); + payload = 0; + mblk->release (); + mblk = 0; + return -1; +} + +int +Logging_Handler::write_log_record (ACE_Message_Block *mblk) +{ + // Peer hostname is in the <mblk> and the log record data + // is in its continuation. + if (log_file_.send_n (mblk) == -1) + return -1; + if (ACE::debug ()) { + // Build a CDR stream from the log record data. + ACE_InputCDR cdr (mblk->cont ()); + ACE_CDR::Boolean byte_order; + ACE_CDR::ULong length; + // Extract the byte-order and length, ending up at the start + // of the log record itself. Use the byte order to properly + // set the CDR stream for extracting the contents. + cdr >> ACE_InputCDR::to_boolean (byte_order); + cdr.reset_byte_order (byte_order); + cdr >> length; + ACE_Log_Record log_record; + cdr >> log_record; // Finally extract the <ACE_log_record>. + log_record.print (mblk->rd_ptr (), 1, cerr); + } + return mblk->total_length (); +} + + +int Logging_Handler::log_record () +{ + ACE_Message_Block *mblk = 0; + if (recv_log_record (mblk) == -1) + return -1; + else { + int result = write_log_record (mblk); + mblk->release (); // Free up the contents. + return result == -1 ? -1 : 0; + } +} diff --git a/ACE/examples/C++NPv1/Logging_Handler.h b/ACE/examples/C++NPv1/Logging_Handler.h new file mode 100644 index 00000000000..6e0004212b3 --- /dev/null +++ b/ACE/examples/C++NPv1/Logging_Handler.h @@ -0,0 +1,55 @@ +/* +** $Id$ +** +** Copyright 2001 Addison Wesley. All Rights Reserved. +*/ + +#ifndef _LOGGING_HANDLER_H +#define _LOGGING_HANDLER_H + +#include "ace/FILE_IO.h" +#include "ace/SOCK_Stream.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL +class ACE_Message_Block; +ACE_END_VERSIONED_NAMESPACE_DECL + +class Logging_Handler +{ +protected: + ACE_FILE_IO &log_file_; // Reference to a log file. + + ACE_SOCK_Stream logging_peer_; // Connected to the client. + +public: + // Initialization and termination methods. + Logging_Handler (ACE_FILE_IO &log_file): log_file_ (log_file) {} + Logging_Handler (ACE_FILE_IO &log_file, + ACE_HANDLE handle): log_file_ (log_file) + { logging_peer_.set_handle (handle); } + Logging_Handler (ACE_FILE_IO &log_file, + const ACE_SOCK_Stream &logging_peer) + : log_file_ (log_file), logging_peer_ (logging_peer) {} + int close () { return logging_peer_.close (); } + + // Receive one log record from a connected client. Returns + // length of record on success and <mblk> contains the + // hostname, <mblk->cont()> contains the log record header + // (the byte order and the length) and the data. Returns -1 on + // failure or connection close. + int recv_log_record (ACE_Message_Block *&log_record); + + // Write one record to the log file. The <mblk> contains the + // hostname and the <mblk->cont> contains the log record. + // Returns length of record written on success, or -1 on failure. + int write_log_record (ACE_Message_Block *log_record); + + // Log one record by calling <recv_log_record> and + // <write_log_record>. Returns 0 on success and -1 on failure. + int log_record (); + + // Accessor method. + ACE_SOCK_Stream &peer () { return logging_peer_; } +}; + +#endif /* _LOGGING_HANDLER_H */ diff --git a/ACE/examples/C++NPv1/Logging_Server.cpp b/ACE/examples/C++NPv1/Logging_Server.cpp new file mode 100644 index 00000000000..c685412c769 --- /dev/null +++ b/ACE/examples/C++NPv1/Logging_Server.cpp @@ -0,0 +1,74 @@ +/* +** $Id$ +** +** Copyright 2001 Addison Wesley. All Rights Reserved. +*/ + +#include "ace/FILE_Addr.h" +#include "ace/FILE_Connector.h" +#include "ace/FILE_IO.h" +#include "ace/INET_Addr.h" +#include "ace/SOCK_Stream.h" +#include "Logging_Server.h" +#include "ace/OS_NS_string.h" +#include "ace/os_include/os_netdb.h" + +int Logging_Server::run (int argc, char *argv[]) +{ + if (open (argc > 1 ? atoi (argv[1]) : 0) == -1) + return -1; + + for (;;) { + if (wait_for_multiple_events () == -1) + return -1; + if (handle_connections () == -1) + return -1; + if (handle_data () == -1) + return -1; + } + + return 0; +} + + +int Logging_Server::open (u_short logger_port) +{ + ACE_INET_Addr server_addr; + int result; + + if (logger_port != 0) + result = server_addr.set (logger_port, + (ACE_UINT32) INADDR_ANY); + else + result = server_addr.set ("ace_logger", + (ACE_UINT32) INADDR_ANY); + if (result == -1) return -1; + + // Start listening, enable reuse of listen address for quick restarts. + return acceptor_.open (server_addr, 1); +} + + +int Logging_Server::make_log_file (ACE_FILE_IO &logging_file, + ACE_SOCK_Stream *logging_peer) +{ + char filename[MAXHOSTNAMELEN + sizeof (".log")]; + + if (logging_peer != 0) { // Use client's hostname as log file name. + ACE_INET_Addr logging_peer_addr; + logging_peer->get_remote_addr (logging_peer_addr); + logging_peer_addr.get_host_name (filename, MAXHOSTNAMELEN); + ACE_OS::strcat (filename, ".log"); + } + else + ACE_OS::strcpy (filename, "logging_server.log"); + + ACE_FILE_Connector connector; + return connector.connect (logging_file, + ACE_FILE_Addr (filename), + 0, // No timeout. + ACE_Addr::sap_any, // Ignored. + 0, // Don't try to reuse the addr. + O_RDWR|O_CREAT|O_APPEND, + ACE_DEFAULT_FILE_PERMS); +} diff --git a/ACE/examples/C++NPv1/Logging_Server.h b/ACE/examples/C++NPv1/Logging_Server.h new file mode 100644 index 00000000000..2c8624a11cb --- /dev/null +++ b/ACE/examples/C++NPv1/Logging_Server.h @@ -0,0 +1,44 @@ +/* +** $Id$ +** +** Copyright 2001 Addison Wesley. All Rights Reserved. +*/ + +#ifndef _LOGGING_SERVER_H +#define _LOGGING_SERVER_H + +#include "ace/FILE_IO.h" +#include "ace/SOCK_Acceptor.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL +class ACE_SOCK_Stream; +ACE_END_VERSIONED_NAMESPACE_DECL + +class Logging_Server +{ +public: + // Template Method that runs logging server's event loop. + virtual int run (int argc, char *argv[]); + +protected: + // The following four methods are ``hooks'' that can be + // overridden by subclasses. + virtual int open (u_short port = 0); + virtual int wait_for_multiple_events () { return 0; } + virtual int handle_connections () = 0; + virtual int handle_data (ACE_SOCK_Stream * = 0) = 0; + + // The following helper method can be used by the hook methods. + int make_log_file (ACE_FILE_IO &, ACE_SOCK_Stream * = 0); + + // Close the socket endpoint. + virtual ~Logging_Server () { acceptor_.close (); } + + // Accessor. + ACE_SOCK_Acceptor &acceptor () { return acceptor_; } + +private: + ACE_SOCK_Acceptor acceptor_; // Socket acceptor endpoint. +}; + +#endif /* _LOGGING_SERVER_H */ diff --git a/ACE/examples/C++NPv1/Makefile.am b/ACE/examples/C++NPv1/Makefile.am new file mode 100644 index 00000000000..5c46ae7f00d --- /dev/null +++ b/ACE/examples/C++NPv1/Makefile.am @@ -0,0 +1,191 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +ACE_BUILDDIR = $(top_builddir) +ACE_ROOT = $(top_srcdir) + +noinst_PROGRAMS = + +## Makefile.C++NPv1_Iterative_Logging_Server.am + +if !BUILD_ACE_FOR_TAO +if !BUILD_USES_WCHAR +noinst_PROGRAMS += iterative_logging_server + +iterative_logging_server_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +iterative_logging_server_SOURCES = \ + Iterative_Logging_Server.cpp \ + Logging_Handler.cpp \ + Logging_Server.cpp \ + Iterative_Logging_Server.h \ + Logging_Handler.h \ + Logging_Server.h + +iterative_logging_server_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_USES_WCHAR +endif !BUILD_ACE_FOR_TAO + +## Makefile.C++NPv1_Logging_Client.am + +if !BUILD_USES_WCHAR +noinst_PROGRAMS += logging_client + +logging_client_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +logging_client_SOURCES = \ + Logging_Client.cpp \ + Iterative_Logging_Server.h \ + Logging_Handler.h \ + Logging_Server.h \ + Process_Per_Connection_Logging_Server.h \ + RT_Thread_Per_Connection_Logging_Server.h \ + Reactive_Logging_Server.h \ + Reactive_Logging_Server_Ex.h \ + Thread_Per_Connection_Logging_Server.h + +logging_client_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_USES_WCHAR + +## Makefile.C++NPv1_PPC_Logging_Server.am + +if !BUILD_ACE_FOR_TAO +if !BUILD_USES_WCHAR +noinst_PROGRAMS += ppc_logging_server + +ppc_logging_server_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +ppc_logging_server_SOURCES = \ + Logging_Handler.cpp \ + Logging_Server.cpp \ + Process_Per_Connection_Logging_Server.cpp \ + Logging_Handler.h \ + Logging_Server.h \ + Process_Per_Connection_Logging_Server.h + +ppc_logging_server_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_USES_WCHAR +endif !BUILD_ACE_FOR_TAO + +## Makefile.C++NPv1_RTTPC_Logging_Server.am + +if !BUILD_ACE_FOR_TAO +if !BUILD_USES_WCHAR +noinst_PROGRAMS += RTTPC_logging_server + +RTTPC_logging_server_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +RTTPC_logging_server_SOURCES = \ + Logging_Handler.cpp \ + Logging_Server.cpp \ + RT_Thread_Per_Connection_Logging_Server.cpp \ + Logging_Handler.h \ + Logging_Server.h \ + RT_Thread_Per_Connection_Logging_Server.h + +RTTPC_logging_server_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_USES_WCHAR +endif !BUILD_ACE_FOR_TAO + +## Makefile.C++NPv1_Reactive_Logging_Server.am + +if !BUILD_ACE_FOR_TAO +if !BUILD_USES_WCHAR +noinst_PROGRAMS += reactive_logging_server + +reactive_logging_server_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +reactive_logging_server_SOURCES = \ + Logging_Handler.cpp \ + Logging_Server.cpp \ + Reactive_Logging_Server.cpp \ + Logging_Handler.h \ + Logging_Server.h \ + Reactive_Logging_Server.h + +reactive_logging_server_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_USES_WCHAR +endif !BUILD_ACE_FOR_TAO + +## Makefile.C++NPv1_Reactive_Logging_Server_Ex.am + +if !BUILD_ACE_FOR_TAO +if !BUILD_USES_WCHAR +noinst_PROGRAMS += reactive_logging_server_ex + +reactive_logging_server_ex_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +reactive_logging_server_ex_SOURCES = \ + Logging_Handler.cpp \ + Logging_Server.cpp \ + Reactive_Logging_Server_Ex.cpp \ + Logging_Handler.h \ + Logging_Server.h \ + Reactive_Logging_Server_Ex.h + +reactive_logging_server_ex_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_USES_WCHAR +endif !BUILD_ACE_FOR_TAO + +## Makefile.C++NPv1_TPC_Logging_Server.am + +if !BUILD_ACE_FOR_TAO +if !BUILD_USES_WCHAR +noinst_PROGRAMS += tpc_logging_server + +tpc_logging_server_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +tpc_logging_server_SOURCES = \ + Logging_Handler.cpp \ + Logging_Server.cpp \ + Thread_Per_Connection_Logging_Server.cpp \ + Logging_Handler.h \ + Logging_Server.h \ + Thread_Per_Connection_Logging_Server.h + +tpc_logging_server_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_USES_WCHAR +endif !BUILD_ACE_FOR_TAO + +## Clean up template repositories, etc. +clean-local: + -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.* + -rm -f gcctemp.c gcctemp so_locations *.ics + -rm -rf cxx_repository ptrepository ti_files + -rm -rf templateregistry ir.out + -rm -rf ptrepository SunWS_cache Templates.DB diff --git a/ACE/examples/C++NPv1/Process_Per_Connection_Logging_Server.cpp b/ACE/examples/C++NPv1/Process_Per_Connection_Logging_Server.cpp new file mode 100644 index 00000000000..54d936962aa --- /dev/null +++ b/ACE/examples/C++NPv1/Process_Per_Connection_Logging_Server.cpp @@ -0,0 +1,180 @@ +/* +** $Id$ +** +** Copyright 2001 Addison Wesley. All Rights Reserved. +*/ + +#include "ace/Log_Msg.h" +#include "ace/Process_Manager.h" +#include "ace/Signal.h" +#include "ace/OS_NS_string.h" +#include "ace/os_include/os_fcntl.h" + +#include "Process_Per_Connection_Logging_Server.h" +#include "Logging_Handler.h" + +#include <errno.h> + +namespace { + extern "C" void sigterm_handler (int /* signum */) { /* No-op. */ } +} + + +Logging_Process::Logging_Process (const char *prog_name, + const ACE_SOCK_Stream &logging_peer) + : logging_peer_ (logging_peer.get_handle ()) +{ + ACE_OS::strcpy (prog_name_, prog_name); +} + +// Set up the process options here. If the decision to do a fork +// a no exec on POSIX needs to be changed, this is the only place +// that needs to change (omit the creation_flags() call). +// We request that the logging client's socket handle be passed +// to the child process. The internals of ACE_Process insure that +// it gets put on the command line if starting a new program image, +// and that if it needed to be duplicated to accomplish that (such +// as on Win32) it will get properly closed. +// The process_name () call sets the program to run and is also used +// for the fork() call on POSIX. +// avoid_zombies has a real affect only on POSIX; it's harmless on Win32. +// Setting the NO_EXEC creation flag is what prevents the exec() on +// POSIX. It has no affect on Win32. +int +Logging_Process::prepare (ACE_Process_Options &options) +{ + if (options.pass_handle (logging_peer_.get_handle ()) == -1) + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "pass_handle"), -1); + options.command_line ("%s", prog_name_); + options.avoid_zombies (1); + options.creation_flags (ACE_Process_Options::NO_EXEC); + return 0; +} + +// Just delete the process object. If any handles needed to be +// duplicated to be passed to the child, they'll get closed now +// by the ACE_Process destructor. +void +Logging_Process::unmanage () +{ + delete this; +} + + +int +Process_Per_Connection_Logging_Server::handle_connections () +{ + ACE_SOCK_Stream logging_peer; + + // Block until a client connects. + if (acceptor ().accept (logging_peer) == -1) + return -1; + + Logging_Process *logger = + new Logging_Process (prog_name_, logging_peer); + ACE_Process_Options options; + pid_t pid; + pid = ACE_Process_Manager::instance ()->spawn (logger, + options); + // If we came back with pid 0 from the spawn(), this is a + // POSIX fork system - we are in the child process. Handle the + // logging records, then exit. + if (pid == 0) { + acceptor().close (); + handle_data (&logging_peer); + delete logger; + ACE_OS::exit (0); + } + logging_peer.close (); + if (pid == -1) + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "spawn()"), -1); + + // See if there are any child processes that have + // exited - reap their status and clean up handles held + // open while the child executed. + ACE_Process_Manager::instance ()->wait (0, + ACE_Time_Value::zero); + return 0; +} + +int +Process_Per_Connection_Logging_Server::handle_data (ACE_SOCK_Stream *client) +{ + // Disable non-blocking mode. + client->disable (ACE_NONBLOCK); + ACE_FILE_IO log_file; + make_log_file (log_file, client); + Logging_Handler logging_handler (log_file, *client); + + while (logging_handler.log_record () != -1) + continue; + + log_file.close (); + return 0; +} + + +int +Process_Per_Connection_Logging_Server::run (int argc, char *argv[]) +{ + ACE_OS::strncpy (prog_name_, argv[0], MAXPATHLEN); + prog_name_[MAXPATHLEN] = '\0'; // Ensure NUL-termination. + // If there are 2 command line arguments after prog_name_, this + // is a spawned worker process. Else run as the master. + if (argc == 3) + return run_worker (argc, argv); // Only on Win32. + else + return run_master (argc, argv); +} + +int +Process_Per_Connection_Logging_Server::run_master (int argc, char *argv[]) +{ + u_short logger_port = 0; + if (argc == 2) + logger_port = atoi (argv[1]); + if (open (logger_port) == -1) + return -1; + + for (;;) + if (handle_connections () == -1) + return -1; + + return 0; +} + +int +Process_Per_Connection_Logging_Server::run_worker (int, char *argv[]) +{ + int client_handle_i = atoi (argv[2]); + // Some compilers don't like reinterpret_casting an int to an int, so + // only do reinterpret_cast on Windows. +#if defined (ACE_WIN32) + ACE_HANDLE client_handle = + reinterpret_cast<ACE_HANDLE> (client_handle_i); +#else + ACE_HANDLE client_handle = + static_cast<ACE_HANDLE> (client_handle_i); +#endif /* ACE_WIN32 */ + ACE_SOCK_Stream client (client_handle); + + handle_data (&client); + client.close (); + return 0; +} + + +int main (int argc, char *argv[]) +{ + // Register to receive the <SIGTERM> signal. + ACE_Sig_Action sa ((ACE_SignalHandler)sigterm_handler, + SIGTERM); + + Process_Per_Connection_Logging_Server server; + + if (server.run (argc, argv) == -1 && errno != EINTR) + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "server.run()"), 1); + + // Barrier synchronization. + return ACE_Process_Manager::instance ()->wait (); +} diff --git a/ACE/examples/C++NPv1/Process_Per_Connection_Logging_Server.h b/ACE/examples/C++NPv1/Process_Per_Connection_Logging_Server.h new file mode 100644 index 00000000000..4d64d764bfd --- /dev/null +++ b/ACE/examples/C++NPv1/Process_Per_Connection_Logging_Server.h @@ -0,0 +1,53 @@ +/* +** $Id$ +** +** Copyright 2001 Addison Wesley. All Rights Reserved. +*/ + +#ifndef _PROCESS_PER_CONNECTION_LOGGING_SERVER_H +#define _PROCESS_PER_CONNECTION_LOGGING_SERVER_H + +#include "ace/INET_Addr.h" +#include "ace/Log_Record.h" +#include "ace/Process.h" +#include "ace/Process_Manager.h" +#include "ace/SOCK_Acceptor.h" +#include "ace/SOCK_Stream.h" +#include "ace/Signal.h" +#include "Logging_Server.h" + +class Logging_Process : public ACE_Process +{ +public: + Logging_Process (const char *prog_name, + const ACE_SOCK_Stream &logging_peer); + + virtual int prepare (ACE_Process_Options &options); + virtual void unmanage (); + +private: + Logging_Process (); // Force desired constructor to be used. + + char prog_name_[MAXPATHLEN + 1]; + ACE_SOCK_Stream logging_peer_; +}; + + +class Process_Per_Connection_Logging_Server : public Logging_Server +{ +protected: + char prog_name_[MAXPATHLEN + 1]; + +protected: + virtual int handle_connections (); + virtual int handle_data (ACE_SOCK_Stream *client = 0); + + int run_master (int argc, char *argv[]); + int run_worker (int argc, char *argv[]); + +public: + virtual int run (int argc, char *argv[]); + +}; + +#endif /* _PROCESS_PER_CONNECTION_LOGGING_SERVER_H */ diff --git a/ACE/examples/C++NPv1/README b/ACE/examples/C++NPv1/README new file mode 100644 index 00000000000..747fa24ecfc --- /dev/null +++ b/ACE/examples/C++NPv1/README @@ -0,0 +1,73 @@ +(This is file $Id$) + +The files in this directory contain the source code from the book +``C++ Network Programming: Mastering Complexity Using ACE and +Patterns'' (C++NPv1) by Douglas C. Schmidt and Stephen D. Huston +(Addison-Wesley 2001, ISBN 0-201-60464-7). + +We have compiled and run these files on the following platforms: + + Sun Solaris 8 on SPARC using Sun Forte 6. + Redhat Linux 7.1 using g++ 2.96. + Microsoft Windows 2000 using Microsoft Visual C++ 6. + +You must have the ACE_ROOT environment variable set correctly to build +these examples. ACE_ROOT must refer to the top-level ACE_wrappers +directory. Please see $ACE_ROOT/ACE-INSTALL.html for instructions on +how to build the ACE toolkit. + +Mapping Source Files to Book Chapters +------------------------------------- + +The files in this directory map to the chapters in C++NPv1 as follows: + +Chapter 4 Logging_Client.h + Logging_Client.cpp + Logging_Handler.h + Logging_Handler.cpp + Iterative_Logging_Server.h + Iterative_Logging_Server.cpp + +Chapter 7 Reactive_Logging_Server.h + Reactive_Logging_Server.cpp + Reactive_Logging_Server_Ex.h + Reactive_Logging_Server_Ex.cpp + +Chapter 8 Process_Per_Connection_Logging_Server.h + Process_Per_Connection_Logging_Server.cpp + +Chapter 9 Thread_Per_Connection_Logging_Server.h + Thread_Per_Connection_Logging_Server.cpp + RT_Thread_Per_Connection_Logging_Server.h + RT_Thread_Per_Connection_Logging_Server.cpp + +Microsoft Visual C++ users: +--------------------------- + +The examples.dsw file is a Microsoft Visual C++ workspace file that +contains projects for the individual programs. You can either build +them separately, or use the Batch Build command to build multiple +projects at once. + +All other users: +---------------- + +Assuming that your system is configured correctly, you should be able +to type + +% make + +to compile all of the programs, and + +% make clean + +to remove all the files that were generated during compilation. + +There are also individual Makefiles for each separate example program. +These makefiles have a ".mak" suffix. For example, Logging_Client.mak +is the makefile for the Logging_Client program. + +All of the files in these directories are copyright Addison Wesley, +and they come with absolutely no warranty whatsoever. Permission is +hereby granted to use these programs for educational or commercial +purposes. diff --git a/ACE/examples/C++NPv1/RT_Thread_Per_Connection_Logging_Server.cpp b/ACE/examples/C++NPv1/RT_Thread_Per_Connection_Logging_Server.cpp new file mode 100644 index 00000000000..febbf1964d5 --- /dev/null +++ b/ACE/examples/C++NPv1/RT_Thread_Per_Connection_Logging_Server.cpp @@ -0,0 +1,132 @@ +/* +** $Id$ +** +** Copyright 2001 Addison Wesley. All Rights Reserved. +*/ + +#include "ace/Auto_Ptr.h" +#include "ace/FILE_IO.h" +#include "ace/Log_Msg.h" +#include "ace/Sched_Params.h" +#include "ace/Signal.h" +#include "ace/Thread_Manager.h" + +#include "RT_Thread_Per_Connection_Logging_Server.h" +#include "Logging_Handler.h" + +#include <errno.h> + +namespace { + extern "C" void sigterm_handler (int /* signum */) { /* No-op. */ } +} + + +int +RT_Thread_Per_Connection_Logging_Server::open (u_short port) +{ + ACE_Sched_Params fifo_sched_params + (ACE_SCHED_FIFO, + ACE_Sched_Params::priority_min (ACE_SCHED_FIFO), + ACE_SCOPE_PROCESS); + + if (ACE_OS::sched_params (fifo_sched_params) != 0) { + if (errno == EPERM || errno == ENOTSUP) + ACE_DEBUG ((LM_DEBUG, + "Warning: user's not superuser, so " + "we're running in time-shared class\n")); + else + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", "ACE_OS::sched_params()"), -1); + } + // Initialize the parent classes. + return Thread_Per_Connection_Logging_Server::open (port); +} + + +int +RT_Thread_Per_Connection_Logging_Server::handle_data (ACE_SOCK_Stream *client) +{ + int prio = + ACE_Sched_Params::next_priority + (ACE_SCHED_FIFO, + ACE_Sched_Params::priority_min (ACE_SCHED_FIFO), + ACE_SCOPE_THREAD); + ACE_OS::thr_setprio (prio); + return Thread_Per_Connection_Logging_Server::handle_data (client); +} + + +// For simplicity, the Thread_Per_Connection_Logging_Server methods +// are duplicated here. + +ACE_THR_FUNC_RETURN Thread_Per_Connection_Logging_Server::run_svc (void *arg) +{ + auto_ptr<Thread_Args> thread_args (static_cast<Thread_Args *> (arg)); + + thread_args->this_->handle_data (&thread_args->logging_peer_); + thread_args->logging_peer_.close (); + return 0; // Return value is ignored +} + + +int +Thread_Per_Connection_Logging_Server::handle_connections () +{ + auto_ptr<Thread_Args> thread_args (new Thread_Args (this)); + + if (acceptor ().accept (thread_args->logging_peer_) == -1) + return -1; + if (ACE_Thread_Manager::instance ()->spawn ( + // Pointer to function entry point. + Thread_Per_Connection_Logging_Server::run_svc, + // <run_svc> parameter. + static_cast<void *> (thread_args.get ()), + THR_DETACHED | THR_SCOPE_SYSTEM) == -1) + return -1; + thread_args.release (); // Spawned thread now owns memory + return 0; +} + + +int +Thread_Per_Connection_Logging_Server::handle_data (ACE_SOCK_Stream *client) +{ + ACE_FILE_IO log_file; + // Client's hostname is logfile name. + make_log_file (log_file, client); + + // Place the connection into blocking mode since this + // thread isn't doing anything except handling this client. + client->disable (ACE_NONBLOCK); + + Logging_Handler logging_handler (log_file, *client); + + // Keep handling log records until client closes connection + // or this thread is asked to cancel itself. + ACE_Thread_Manager *mgr = ACE_Thread_Manager::instance (); + ACE_thread_t me = ACE_Thread::self (); + while (!mgr->testcancel (me) && + logging_handler.log_record () != -1) + continue; + + log_file.close (); + return 0; +} + + +int main (int argc, char *argv[]) +{ + // Register to receive the <SIGTERM> signal. + ACE_Sig_Action sa ((ACE_SignalHandler) sigterm_handler, + SIGTERM); + + RT_Thread_Per_Connection_Logging_Server server; + + if (server.run (argc, argv) == -1) + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "server.run()"), 1); + + // Cooperative thread cancellation and barrier synchronization. + ACE_Thread_Manager::instance ()->cancel_all (); + return ACE_Thread_Manager::instance ()->wait (); +} + diff --git a/ACE/examples/C++NPv1/RT_Thread_Per_Connection_Logging_Server.h b/ACE/examples/C++NPv1/RT_Thread_Per_Connection_Logging_Server.h new file mode 100644 index 00000000000..828a0e61a03 --- /dev/null +++ b/ACE/examples/C++NPv1/RT_Thread_Per_Connection_Logging_Server.h @@ -0,0 +1,22 @@ +/* +** $Id$ +** +** Copyright 2001 Addison Wesley. All Rights Reserved. +*/ + +#ifndef _RT_THREAD_PER_CONNECTION_LOGGING_SERVER_H +#define _RT_THREAD_PER_CONNECTION_LOGGING_SERVER_H + +#include "ace/SOCK_Stream.h" +#include "Logging_Server.h" +#include "Thread_Per_Connection_Logging_Server.h" + +class RT_Thread_Per_Connection_Logging_Server : + public Thread_Per_Connection_Logging_Server +{ +protected: + virtual int open (u_short port); + virtual int handle_data (ACE_SOCK_Stream * = 0); +}; + +#endif /* _RT_THREAD_PER_CONNECTION_LOGGING_SERVER_H */ diff --git a/ACE/examples/C++NPv1/Reactive_Logging_Server.cpp b/ACE/examples/C++NPv1/Reactive_Logging_Server.cpp new file mode 100644 index 00000000000..39d2c6b51be --- /dev/null +++ b/ACE/examples/C++NPv1/Reactive_Logging_Server.cpp @@ -0,0 +1,17 @@ +/* +** $Id$ +** +** Copyright 2001 Addison Wesley. All Rights Reserved. +*/ + +#include "ace/Log_Msg.h" +#include "Reactive_Logging_Server.h" + +int main (int argc, char *argv[]) +{ + Reactive_Logging_Server server; + + if (server.run (argc, argv) == -1) + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "server.run()"), 1); + return 0; +} diff --git a/ACE/examples/C++NPv1/Reactive_Logging_Server.h b/ACE/examples/C++NPv1/Reactive_Logging_Server.h new file mode 100644 index 00000000000..482bcb32107 --- /dev/null +++ b/ACE/examples/C++NPv1/Reactive_Logging_Server.h @@ -0,0 +1,79 @@ +/* +** $Id$ +** +** Copyright 2001 Addison Wesley. All Rights Reserved. +*/ + +#ifndef _REACTIVE_LOGGING_SERVER_H +#define _REACTIVE_LOGGING_SERVER_H + +#include "ace/INET_Addr.h" +#include "ace/SOCK_Acceptor.h" +#include "ace/SOCK_Stream.h" +#include "ace/Log_Record.h" +#include "ace/Handle_Set.h" +#include "ace/os_include/os_fcntl.h" +#include "Iterative_Logging_Server.h" + +class Reactive_Logging_Server : public Iterative_Logging_Server +{ +protected: + // Keep track of the acceptor socket handle and all the + // connected stream socket handles. + ACE_Handle_Set master_handle_set_; + + // Keep track of handles marked as active by <select>. + ACE_Handle_Set active_handles_; + + virtual int open (u_short logger_port) { + Iterative_Logging_Server::open (logger_port); + master_handle_set_.set_bit (acceptor ().get_handle ()); + acceptor ().enable (ACE_NONBLOCK); + return 0; + } + + virtual int wait_for_multiple_events () { + active_handles_ = master_handle_set_; + int width = (int)active_handles_.max_set () + 1; + if (select (width, + active_handles_.fdset (), + 0, // no write_fds + 0, // no except_fds + 0) == -1) // no timeout + return -1; + active_handles_.sync + ((ACE_HANDLE) ((int) active_handles_.max_set () + 1)); + return 0; + } + + virtual int handle_connections () { + if (active_handles_.is_set (acceptor ().get_handle ())) { + while (acceptor ().accept (logging_handler ().peer ()) == 0) + master_handle_set_.set_bit + (logging_handler ().peer ().get_handle ()); + + // Remove acceptor handle from further consideration. + active_handles_.clr_bit (acceptor ().get_handle ()); + } + return 0; + } + + virtual int handle_data (ACE_SOCK_Stream *) { + ACE_Handle_Set_Iterator peer_iterator (active_handles_); + + for (ACE_HANDLE handle; + (handle = peer_iterator ()) != ACE_INVALID_HANDLE; + ) { + logging_handler ().peer ().set_handle (handle); + if (logging_handler ().log_record () == -1) { + // Handle connection shutdown or comm failure. + master_handle_set_.clr_bit (handle); + logging_handler ().close (); + } + } + return 0; + } + +}; + +#endif /* _REACTIVE_LOGGING_SERVER_H */ diff --git a/ACE/examples/C++NPv1/Reactive_Logging_Server_Ex.cpp b/ACE/examples/C++NPv1/Reactive_Logging_Server_Ex.cpp new file mode 100644 index 00000000000..b8bc363180a --- /dev/null +++ b/ACE/examples/C++NPv1/Reactive_Logging_Server_Ex.cpp @@ -0,0 +1,20 @@ +/* +** $Id$ +** +** Copyright 2001 Addison Wesley. All Rights Reserved. +*/ + +#include "ace/Functor.h" +#include "ace/Log_Msg.h" + +#include "Reactive_Logging_Server_Ex.h" + +int main (int argc, char *argv[]) +{ + Reactive_Logging_Server_Ex server; + + if (server.run (argc, argv) == -1) + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "server.run()"), 1); + return 0; +} + diff --git a/ACE/examples/C++NPv1/Reactive_Logging_Server_Ex.h b/ACE/examples/C++NPv1/Reactive_Logging_Server_Ex.h new file mode 100644 index 00000000000..c839b2453fc --- /dev/null +++ b/ACE/examples/C++NPv1/Reactive_Logging_Server_Ex.h @@ -0,0 +1,95 @@ +/* +** $Id$ +** +** Copyright 2001 Addison Wesley. All Rights Reserved. +*/ + +#ifndef _REACTIVE_LOGGING_SERVER_EX_H +#define _REACTIVE_LOGGING_SERVER_EX_H + +#include "ace/ACE.h" +#include "ace/FILE_IO.h" +#include "ace/Handle_Set.h" +#include "ace/Hash_Map_Manager.h" +#include "ace/INET_Addr.h" +#include "ace/Log_Record.h" +#include "ace/SOCK_Acceptor.h" +#include "ace/SOCK_Stream.h" +#include "Logging_Server.h" +#include "Logging_Handler.h" +#include "ace/Null_Mutex.h" +#include "ace/os_include/os_fcntl.h" + +typedef ACE_Hash_Map_Manager<ACE_HANDLE, + ACE_FILE_IO *, + ACE_Null_Mutex> LOG_MAP; + +class Reactive_Logging_Server_Ex : public Logging_Server +{ +protected: + // Associate an active handle to an <ACE_FILE_IO> pointer. + LOG_MAP log_map_; + + // Keep track of acceptor socket and all the connected + // stream socket handles. + ACE_Handle_Set master_handle_set_; + + // Keep track of read handles marked as active by <select>. + ACE_Handle_Set active_read_handles_; + + virtual int open (u_short port) { + Logging_Server::open (port); + master_handle_set_.set_bit (acceptor ().get_handle ()); + acceptor ().enable (ACE_NONBLOCK); + return 0; + } + + virtual int wait_for_multiple_events () { + active_read_handles_ = master_handle_set_; + int width = (int) active_read_handles_.max_set () + 1; + + return ACE::select (width, active_read_handles_); + } + + virtual int handle_connections () { + ACE_SOCK_Stream logging_peer; + + while (acceptor ().accept (logging_peer) != -1) { + ACE_FILE_IO *log_file = new ACE_FILE_IO; + + // Use the client's hostname as the logfile name. + make_log_file (*log_file, &logging_peer); + + // Add the new <logging_peer>'s handle to the map and + // to the set of handles we <select> for input. + log_map_.bind (logging_peer.get_handle (), log_file); + master_handle_set_.set_bit (logging_peer.get_handle ()); + } + active_read_handles_.clr_bit (acceptor ().get_handle ()); + return 0; + } + + virtual int handle_data (ACE_SOCK_Stream *) { + ACE_Handle_Set_Iterator peer_iterator (active_read_handles_); + + for (ACE_HANDLE handle; + (handle = peer_iterator ()) != ACE_INVALID_HANDLE; + ) { + ACE_FILE_IO *log_file = 0; + log_map_.find (handle, log_file); + Logging_Handler logging_handler (*log_file, handle); + + if (logging_handler.log_record () == -1) { + logging_handler.close (); + master_handle_set_.clr_bit (handle); + log_map_.unbind (handle); + log_file->close (); + delete log_file; + } + } + return 0; + } + +}; + +#endif /* _REACTIVE_LOGGING_SERVER_EX_H */ diff --git a/ACE/examples/C++NPv1/Thread_Per_Connection_Logging_Server.cpp b/ACE/examples/C++NPv1/Thread_Per_Connection_Logging_Server.cpp new file mode 100644 index 00000000000..3737957ff70 --- /dev/null +++ b/ACE/examples/C++NPv1/Thread_Per_Connection_Logging_Server.cpp @@ -0,0 +1,93 @@ +/* +** $Id$ +** +** Copyright 2001 Addison Wesley. All Rights Reserved. +*/ + +#include "ace/Auto_Ptr.h" +#include "ace/FILE_IO.h" +#include "ace/Log_Msg.h" +#include "ace/Signal.h" +#include "ace/Thread_Manager.h" + +#include "Thread_Per_Connection_Logging_Server.h" +#include "Logging_Handler.h" + +#include <errno.h> + +namespace { + extern "C" void sigterm_handler (int /* signum */) { /* No-op. */ } +} + + +ACE_THR_FUNC_RETURN Thread_Per_Connection_Logging_Server::run_svc (void *arg) +{ + auto_ptr<Thread_Args> thread_args (static_cast<Thread_Args *> (arg)); + + thread_args->this_->handle_data (&thread_args->logging_peer_); + thread_args->logging_peer_.close (); + return 0; // Return value is ignored +} + + +int +Thread_Per_Connection_Logging_Server::handle_connections () +{ + auto_ptr<Thread_Args> thread_args (new Thread_Args (this)); + + if (acceptor ().accept (thread_args->logging_peer_) == -1) + return -1; + if (ACE_Thread_Manager::instance ()->spawn ( + // Pointer to function entry point. + Thread_Per_Connection_Logging_Server::run_svc, + // <run_svc> parameter. + static_cast<void *> (thread_args.get ()), + THR_DETACHED | THR_SCOPE_SYSTEM) == -1) + return -1; + thread_args.release (); // Spawned thread now owns memory + return 0; +} + + +int +Thread_Per_Connection_Logging_Server::handle_data (ACE_SOCK_Stream *client) +{ + ACE_FILE_IO log_file; + // Client's hostname is logfile name. + make_log_file (log_file, client); + + // Place the connection into blocking mode since this + // thread isn't doing anything except handling this client. + client->disable (ACE_NONBLOCK); + + Logging_Handler logging_handler (log_file, *client); + + // Keep handling log records until client closes connection + // or this thread is asked to cancel itself. + ACE_Thread_Manager *mgr = ACE_Thread_Manager::instance (); + ACE_thread_t me = ACE_Thread::self (); + while (!mgr->testcancel (me) && + logging_handler.log_record () != -1) + continue; + + log_file.close (); + return 0; +} + + +int main (int argc, char *argv[]) +{ + // Register to receive the <SIGTERM> signal. + ACE_Sig_Action sa ((ACE_SignalHandler) sigterm_handler, + SIGTERM); + + Thread_Per_Connection_Logging_Server server; + + if (server.run (argc, argv) == -1) + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "server.run()"), 1); + + // Cooperative thread cancellation and barrier synchronization. + ACE_Thread_Manager::instance ()->cancel_all (); + return ACE_Thread_Manager::instance ()->wait (); +} + diff --git a/ACE/examples/C++NPv1/Thread_Per_Connection_Logging_Server.h b/ACE/examples/C++NPv1/Thread_Per_Connection_Logging_Server.h new file mode 100644 index 00000000000..edf3651cf46 --- /dev/null +++ b/ACE/examples/C++NPv1/Thread_Per_Connection_Logging_Server.h @@ -0,0 +1,49 @@ +/* +** $Id$ +** +** Copyright 2001 Addison Wesley. All Rights Reserved. +*/ + +#ifndef _THREAD_PER_CONNECTION_LOGGING_SERVER_H +#define _THREAD_PER_CONNECTION_LOGGING_SERVER_H + +#include "ace/SOCK_Stream.h" +#include "Logging_Server.h" + +class Thread_Per_Connection_Logging_Server : public Logging_Server +{ +private: + struct Thread_Args { + Thread_Args (Thread_Per_Connection_Logging_Server *lsp) : this_ (lsp) {} + + Thread_Per_Connection_Logging_Server *this_; + ACE_SOCK_Stream logging_peer_; + }; + + // Passed as a parameter to <ACE_Thread_Manager::spawn>. + static ACE_THR_FUNC_RETURN run_svc (void *arg); + +protected: + virtual int handle_connections (); + virtual int handle_data (ACE_SOCK_Stream * = 0); + +public: + // Template Method that runs logging server's event loop. Need to + // reimplement this here because the threads spawned from handle_connections + // call handle_data; therefore, this method must not. + virtual int run (int argc, char *argv[]) { + if (open (argc > 1 ? atoi (argv[1]) : 0) == -1) + return -1; + + for (;;) { + if (wait_for_multiple_events () == -1) + return -1; + if (handle_connections () == -1) + return -1; + } + + return 0; + } +}; + +#endif /* _THREAD_PER_CONNECTION_LOGGING_SERVER_H */ diff --git a/ACE/examples/C++NPv2/.cvsignore b/ACE/examples/C++NPv2/.cvsignore new file mode 100644 index 00000000000..560cd9f1c78 --- /dev/null +++ b/ACE/examples/C++NPv2/.cvsignore @@ -0,0 +1,14 @@ +configurable_logging_server +configurable_logging_server +display_logfile +display_logfile +reactor_logging_server +reactor_logging_server +select_reactor_loggin_server +select_reactor_loggin_server +sr_configurable_logging_server +sr_configurable_logging_server +tp_reactor_logging_server +tp_reactor_logging_server +x +x diff --git a/ACE/examples/C++NPv2/AC_CLD_export.h b/ACE/examples/C++NPv2/AC_CLD_export.h new file mode 100644 index 00000000000..0f2b35ca4c4 --- /dev/null +++ b/ACE/examples/C++NPv2/AC_CLD_export.h @@ -0,0 +1,54 @@ + +// -*- C++ -*- +// $Id$ +// Definition for Win32 Export directives. +// This file is generated automatically by generate_export_file.pl AC_CLD +// ------------------------------ +#ifndef AC_CLD_EXPORT_H +#define AC_CLD_EXPORT_H + +#include "ace/config-all.h" + +#if defined (ACE_AS_STATIC_LIBS) && !defined (AC_CLD_HAS_DLL) +# define AC_CLD_HAS_DLL 0 +#endif /* ACE_AS_STATIC_LIBS && ! AC_CLD_HAS_DLL */ + +#if !defined (AC_CLD_HAS_DLL) +# define AC_CLD_HAS_DLL 1 +#endif /* ! AC_CLD_HAS_DLL */ + +#if defined (AC_CLD_HAS_DLL) && (AC_CLD_HAS_DLL == 1) +# if defined (AC_CLD_BUILD_DLL) +# define AC_CLD_Export ACE_Proper_Export_Flag +# define AC_CLD_SINGLETON_DECLARATION(T) ACE_EXPORT_SINGLETON_DECLARATION (T) +# define AC_CLD_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) ACE_EXPORT_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) +# else /* AC_CLD_BUILD_DLL */ +# define AC_CLD_Export ACE_Proper_Import_Flag +# define AC_CLD_SINGLETON_DECLARATION(T) ACE_IMPORT_SINGLETON_DECLARATION (T) +# define AC_CLD_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) ACE_IMPORT_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) +# endif /* AC_CLD_BUILD_DLL */ +#else /* AC_CLD_HAS_DLL == 1 */ +# define AC_CLD_Export +# define AC_CLD_SINGLETON_DECLARATION(T) +# define AC_CLD_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) +#endif /* AC_CLD_HAS_DLL == 1 */ + +// Set AC_CLD_NTRACE = 0 to turn on library specific tracing even if +// tracing is turned off for ACE. +#if !defined (AC_CLD_NTRACE) +# if (ACE_NTRACE == 1) +# define AC_CLD_NTRACE 1 +# else /* (ACE_NTRACE == 1) */ +# define AC_CLD_NTRACE 0 +# endif /* (ACE_NTRACE == 1) */ +#endif /* !AC_CLD_NTRACE */ + +#if (AC_CLD_NTRACE == 1) +# define AC_CLD_TRACE(X) +#else /* (AC_CLD_NTRACE == 1) */ +# define AC_CLD_TRACE(X) ACE_TRACE_IMPL(X) +#endif /* (AC_CLD_NTRACE == 1) */ + +#endif /* AC_CLD_EXPORT_H */ + +// End of auto generated file. diff --git a/ACE/examples/C++NPv2/AC_Client_Logging_Daemon.cpp b/ACE/examples/C++NPv2/AC_Client_Logging_Daemon.cpp new file mode 100644 index 00000000000..759dcb44861 --- /dev/null +++ b/ACE/examples/C++NPv2/AC_Client_Logging_Daemon.cpp @@ -0,0 +1,426 @@ +/* +** $Id$ +** +** Copyright 2002 Addison Wesley. All Rights Reserved. +*/ + +#include "ace/OS_NS_string.h" +#include "ace/OS_NS_unistd.h" +#include "ace/OS_NS_sys_socket.h" +#include "ace/OS_NS_sys_time.h" +#include "ace/INET_Addr.h" +#include "ace/SOCK_Acceptor.h" +#include "ace/SOCK_Connector.h" +#include "ace/SOCK_Stream.h" +#include "ace/Acceptor.h" +#include "ace/Connector.h" +#include "ace/Get_Opt.h" +#include "ace/Handle_Set.h" +#include "ace/Log_Record.h" +#include "ace/Message_Block.h" +#include "ace/Reactor.h" +#include "ace/Service_Object.h" +#include "ace/Signal.h" +#include "ace/Svc_Handler.h" +#include "ace/Thread_Manager.h" +#include "ace/os_include/os_netdb.h" +#include "Logging_Handler.h" +#include "AC_CLD_export.h" + +#include "AC_Client_Logging_Daemon.h" + +#include <openssl/ssl.h> + + +class AC_CLD_Acceptor + : public ACE_Acceptor<AC_Input_Handler, ACE_SOCK_ACCEPTOR> { +public: + // Constructor. + AC_CLD_Acceptor (AC_Output_Handler *handler = 0) + : output_handler_ (handler), input_handler_ (handler) {} + +protected: + typedef ACE_Acceptor<AC_Input_Handler, ACE_SOCK_ACCEPTOR> + PARENT; + + // <ACE_Acceptor> factory method. + virtual int make_svc_handler (AC_Input_Handler *&sh); + + // <ACE_Reactor> close hook method. + virtual int handle_close (ACE_HANDLE = ACE_INVALID_HANDLE, + ACE_Reactor_Mask = 0); + + // Pointer to the output handler. + AC_Output_Handler *output_handler_; + + // Single input handler. + AC_Input_Handler input_handler_; +}; + +class AC_CLD_Connector + : public ACE_Connector<AC_Output_Handler, ACE_SOCK_CONNECTOR> { +public: + typedef ACE_Connector<AC_Output_Handler, ACE_SOCK_CONNECTOR> + PARENT; + + // Constructor. + AC_CLD_Connector (AC_Output_Handler *handler = 0) + : handler_ (handler), ssl_ctx_ (0), ssl_ (0) {} + + // Destructor frees the SSL resources. + virtual ~AC_CLD_Connector (void) { + SSL_free (ssl_); + SSL_CTX_free (ssl_ctx_); + } + + // Initialize the Connector. + virtual int open (ACE_Reactor *r = ACE_Reactor::instance (), + int flags = 0); + + // Re-establish a connection to the logging server. + int reconnect (); + +protected: + // Connection establishment and authentication hook method. + virtual int connect_svc_handler + (AC_Output_Handler *&svc_handler, + const ACE_SOCK_Connector::PEER_ADDR &remote_addr, + ACE_Time_Value *timeout, + const ACE_SOCK_Connector::PEER_ADDR &local_addr, + int reuse_addr, int flags, int perms); + + virtual int connect_svc_handler + (AC_Output_Handler *&svc_handler, + AC_Output_Handler *&sh_copy, + const ACE_SOCK_Connector::PEER_ADDR &remote_addr, + ACE_Time_Value *timeout, + const ACE_SOCK_Connector::PEER_ADDR &local_addr, + int reuse_addr, int flags, int perms); + + // Pointer to <AC_Output_Handler> we're connecting. + AC_Output_Handler *handler_; + + // Address at which logging server listens for connections. + ACE_INET_Addr remote_addr_; + + // The SSL "context" data structure. + SSL_CTX *ssl_ctx_; + + // The SSL data structure corresponding to authenticated SSL + // connections. + SSL *ssl_; +}; + +class AC_Client_Logging_Daemon : public ACE_Service_Object { +protected: + // Factory that passively connects the <AC_Input_Handler>. + AC_CLD_Acceptor acceptor_; + + // Factory that actively connects the <AC_Output_Handler>. + AC_CLD_Connector connector_; + + // The <AC_Output_Handler> connected by <AC_CLD_Connector>. + AC_Output_Handler output_handler_; + +public: + // Constructor. + AC_Client_Logging_Daemon () + : acceptor_ (&output_handler_), + connector_ (&output_handler_) {} + + // Service Configurator hook methods. + virtual int init (int argc, ACE_TCHAR *argv[]); + virtual int fini (); + //virtual int info (ACE_TCHAR **bufferp, size_t length = 0) const; + //virtual int suspend (); + //virtual int resume (); +}; + +/******************************************************/ + +#if !defined (FLUSH_TIMEOUT) +#define FLUSH_TIMEOUT 120 /* 120 seconds == 2 minutes. */ +#endif /* FLUSH_TIMEOUT */ + +int AC_Output_Handler::open (void *connector) { + connector_ = + static_cast<AC_CLD_Connector *> (connector); + int bufsiz = ACE_DEFAULT_MAX_SOCKET_BUFSIZ; + peer ().set_option (SOL_SOCKET, SO_SNDBUF, + &bufsiz, sizeof bufsiz); + if (reactor ()->register_handler + (this, ACE_Event_Handler::READ_MASK) == -1) + return -1; + if (msg_queue ()->activate () + == ACE_Message_Queue_Base::ACTIVATED) { + msg_queue ()->high_water_mark (QUEUE_MAX); + return activate (THR_SCOPE_SYSTEM); + } else return 0; +} + +int AC_Output_Handler::put (ACE_Message_Block *mb, + ACE_Time_Value *timeout) { + int retval; + while ((retval = putq (mb, timeout)) == -1) { + if (msg_queue ()->state () != ACE_Message_Queue_Base::PULSED) + break; + } + return retval; +} + +int AC_Output_Handler::handle_input (ACE_HANDLE h) { + peer ().close (); + reactor ()->remove_handler + (h, ACE_Event_Handler::READ_MASK + | ACE_Event_Handler::DONT_CALL); + msg_queue ()->pulse (); + return 0; +} + +int AC_Output_Handler::svc () { + ACE_Message_Block *chunk[ACE_IOV_MAX]; + size_t message_index = 0; + ACE_Time_Value time_of_last_send (ACE_OS::gettimeofday ()); + ACE_Time_Value timeout; + ACE_Sig_Action no_sigpipe ((ACE_SignalHandler) SIG_IGN); + ACE_Sig_Action original_action; + no_sigpipe.register_action (SIGPIPE, &original_action); + + for (;;) { + if (message_index == 0) { + timeout = ACE_OS::gettimeofday (); + timeout += FLUSH_TIMEOUT; + } + ACE_Message_Block *mblk = 0; + if (getq (mblk, &timeout) == -1) { + if (errno == ESHUTDOWN) { + if (connector_->reconnect () == -1) break; + continue; + } else if (errno != EWOULDBLOCK) break; + else if (message_index == 0) continue; + } else { + if (mblk->size () == 0 + && mblk->msg_type () == ACE_Message_Block::MB_STOP) + { mblk->release (); break; } + chunk[message_index] = mblk; + ++message_index; + } + if (message_index >= ACE_IOV_MAX || + (ACE_OS::gettimeofday () - time_of_last_send + >= ACE_Time_Value(FLUSH_TIMEOUT))) { + if (send (chunk, message_index) == -1) break; + time_of_last_send = ACE_OS::gettimeofday (); + } + } + + if (message_index > 0) send (chunk, message_index); + no_sigpipe.restore_action (SIGPIPE, original_action); + return 0; +} + +int AC_Output_Handler::send (ACE_Message_Block *chunk[], size_t &count) { + iovec iov[ACE_IOV_MAX]; + size_t iov_size; + int result = 0; + + for (iov_size = 0; iov_size < count; ++iov_size) { + iov[iov_size].iov_base = chunk[iov_size]->rd_ptr (); + iov[iov_size].iov_len = chunk[iov_size]->length (); + } + while (peer ().sendv_n (iov, iov_size) == -1) + if (connector_->reconnect () == -1) { + result = -1; + break; + } + + while (iov_size > 0) { + chunk[--iov_size]->release (); chunk[iov_size] = 0; + } + count = iov_size; + return result; +} + +/******************************************************/ + +int AC_Input_Handler::open (void *) { + ACE_HANDLE handle = peer ().get_handle (); + if (reactor ()->register_handler + (handle, this, ACE_Event_Handler::READ_MASK) == -1) + return -1; + connected_clients_.set_bit (handle); + return 0; +} + +int AC_Input_Handler::close (u_long) { + ACE_Message_Block *shutdown_message = 0; + ACE_NEW_RETURN + (shutdown_message, + ACE_Message_Block (0, ACE_Message_Block::MB_STOP), -1); + output_handler_->put (shutdown_message); + + reactor ()->remove_handler + (connected_clients_, ACE_Event_Handler::READ_MASK); + return output_handler_->wait (); +} + +int AC_Input_Handler::handle_input (ACE_HANDLE handle) { + ACE_Message_Block *mblk = 0; + Logging_Handler logging_handler (handle); + + if (logging_handler.recv_log_record (mblk) != -1) + if (output_handler_->put (mblk->cont ()) != -1) { + mblk->cont (0); + mblk->release (); + return 0; // Success return. + } else mblk->release (); + return -1; // Error return. +} + +int AC_Input_Handler::handle_close (ACE_HANDLE handle, + ACE_Reactor_Mask) { + connected_clients_.clr_bit (handle); + return ACE_OS::closesocket (handle); +} + +/********************************************************/ + +int AC_CLD_Acceptor::make_svc_handler (AC_Input_Handler *&sh) +{ sh = &input_handler_; return 0; } + + +int AC_CLD_Acceptor::handle_close (ACE_HANDLE, + ACE_Reactor_Mask) { + PARENT::handle_close (); + input_handler_.close (); + return 0; +} + +/*******************************************************/ + +#if !defined (CLD_CERTIFICATE_FILENAME) +# define CLD_CERTIFICATE_FILENAME "cld-cert.pem" +#endif /* !CLD_CERTIFICATE_FILENAME */ +#if !defined (CLD_KEY_FILENAME) +# define CLD_KEY_FILENAME "cld-key.pem" +#endif /* !CLD_KEY_FILENAME */ + +int AC_CLD_Connector::open (ACE_Reactor *r, int flags) { + if (PARENT::open (r, flags) != 0) return -1; + OpenSSL_add_ssl_algorithms (); + ssl_ctx_ = SSL_CTX_new (SSLv3_client_method ()); + if (ssl_ctx_ == 0) return -1; + + if (SSL_CTX_use_certificate_file (ssl_ctx_, + CLD_CERTIFICATE_FILENAME, + SSL_FILETYPE_PEM) <= 0 + || SSL_CTX_use_PrivateKey_file (ssl_ctx_, + CLD_KEY_FILENAME, + SSL_FILETYPE_PEM) <= 0 + || !SSL_CTX_check_private_key (ssl_ctx_)) + return -1; + + ssl_ = SSL_new (ssl_ctx_); + if (ssl_ == 0) return -1; + return 0; +} + +int AC_CLD_Connector::connect_svc_handler + (AC_Output_Handler *&svc_handler, + const ACE_SOCK_Connector::PEER_ADDR &remote_addr, + ACE_Time_Value *timeout, + const ACE_SOCK_Connector::PEER_ADDR &local_addr, + int reuse_addr, int flags, int perms) { + if (PARENT::connect_svc_handler + (svc_handler, remote_addr, timeout, + local_addr, reuse_addr, flags, perms) == -1) return -1; + SSL_clear (ssl_); +#if defined (ACE_WIN32) + // ACE_WIN32 is the only platform where ACE_HANDLE is not an int. + // See ace/config-lite.h for the typedefs. + SSL_set_fd (ssl_, + reinterpret_cast<int> (svc_handler->get_handle ())); +#else + SSL_set_fd (ssl_, svc_handler->get_handle ()); +#endif /* ACE_WIN32 */ + + SSL_set_verify (ssl_, SSL_VERIFY_PEER, 0); + + if (SSL_connect (ssl_) == -1 + || SSL_shutdown (ssl_) == -1) return -1; + remote_addr_ = remote_addr; + return 0; +} + +int AC_CLD_Connector::connect_svc_handler + (AC_Output_Handler *&svc_handler, + AC_Output_Handler *&sh_copy, + const ACE_SOCK_Connector::PEER_ADDR &remote_addr, + ACE_Time_Value *timeout, + const ACE_SOCK_Connector::PEER_ADDR &local_addr, + int reuse_addr, int flags, int perms) { + sh_copy = svc_handler; + return this->connect_svc_handler (svc_handler, remote_addr, timeout, + local_addr, reuse_addr, flags, perms); +} + +int AC_CLD_Connector::reconnect () { + // Maximum number of times to retry connect. + const size_t MAX_RETRIES = 5; + ACE_Time_Value timeout (1); + size_t i; + for (i = 0; i < MAX_RETRIES; ++i) { + ACE_Synch_Options options (ACE_Synch_Options::USE_TIMEOUT, + timeout); + if (i > 0) ACE_OS::sleep (timeout); + if (connect (handler_, remote_addr_, options) == 0) + break; + timeout *= 2; // Exponential backoff. + } + return i == MAX_RETRIES ? -1 : 0; +} + +/******************************************************/ + +int AC_Client_Logging_Daemon::init + (int argc, ACE_TCHAR *argv[]) { + u_short cld_port = ACE_DEFAULT_SERVICE_PORT; + u_short sld_port = ACE_DEFAULT_LOGGING_SERVER_PORT; + ACE_TCHAR sld_host[MAXHOSTNAMELEN]; + ACE_OS::strcpy (sld_host, ACE_LOCALHOST); + + ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("p:r:s:"), 0); + get_opt.long_option (ACE_TEXT ("client_port"), 'p', + ACE_Get_Opt::ARG_REQUIRED); + get_opt.long_option (ACE_TEXT ("server_port"), 'r', + ACE_Get_Opt::ARG_REQUIRED); + get_opt.long_option (ACE_TEXT ("server_name"), 's', + ACE_Get_Opt::ARG_REQUIRED); + + for (int c; (c = get_opt ()) != -1;) + switch (c) { + case 'p': // Client logging daemon acceptor port number. + cld_port = static_cast<u_short> (ACE_OS::atoi (get_opt.opt_arg ())); + break; + case 'r': // Server logging daemon acceptor port number. + sld_port = static_cast<u_short> (ACE_OS::atoi (get_opt.opt_arg ())); + break; + case 's': // Server logging daemon hostname. + ACE_OS::strsncpy + (sld_host, get_opt.opt_arg (), MAXHOSTNAMELEN); + break; + } + + ACE_INET_Addr cld_addr (cld_port); + ACE_INET_Addr sld_addr (sld_port, sld_host); + + if (acceptor_.open (cld_addr) == -1) return -1; + AC_Output_Handler *oh = &output_handler_; + if (connector_.connect (oh, sld_addr) == -1) + { acceptor_.close (); return -1; } + return 0; +} + +int AC_Client_Logging_Daemon::fini () +{ return acceptor_.close (); } + +ACE_FACTORY_DEFINE (AC_CLD, AC_Client_Logging_Daemon) diff --git a/ACE/examples/C++NPv2/AC_Client_Logging_Daemon.h b/ACE/examples/C++NPv2/AC_Client_Logging_Daemon.h new file mode 100644 index 00000000000..20f3581f623 --- /dev/null +++ b/ACE/examples/C++NPv2/AC_Client_Logging_Daemon.h @@ -0,0 +1,62 @@ +/* +** $Id$ +** +** Copyright 2002 Addison Wesley. All Rights Reserved. +*/ + +#ifndef _AC_CLIENT_LOGGING_DAEMON_H +#define _AC_CLIENT_LOGGING_DAEMON_H + +#include "ace/Handle_Set.h" +#include "ace/Log_Record.h" +#include "ace/SOCK_Stream.h" +#include "ace/Svc_Handler.h" +#include "ace/Synch_Traits.h" + +class AC_CLD_Connector; + +class AC_Output_Handler + : public ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_MT_SYNCH> { +public: + enum { QUEUE_MAX = sizeof (ACE_Log_Record) * ACE_IOV_MAX }; + + virtual int open (void *); // Initialization hook method. + + // Entry point into the <AC_Output_Handler>. + virtual int put (ACE_Message_Block *, ACE_Time_Value * = 0); + +protected: + AC_CLD_Connector *connector_; + + // Handle disconnects from the logging server. + virtual int handle_input (ACE_HANDLE handle); + + // Hook method forwards log records to server logging daemon. + virtual int svc (); + + // Send the buffered log records using a gather-write operation. + virtual int send (ACE_Message_Block *chunk[], size_t &count); +}; + +class AC_Input_Handler + : public ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH> { +public: + AC_Input_Handler (AC_Output_Handler *handler = 0) + : output_handler_ (handler) {} + virtual int open (void *); // Initialization hook method. + virtual int close (u_long = 0); // Shutdown hook method. + +protected: + // Reactor hook methods. + virtual int handle_input (ACE_HANDLE handle); + virtual int handle_close (ACE_HANDLE = ACE_INVALID_HANDLE, + ACE_Reactor_Mask = 0); + + // Pointer to the output handler. + AC_Output_Handler *output_handler_; + + // Keep track of connected client handles. + ACE_Handle_Set connected_clients_; +}; + +#endif /* _AC_CLIENT_LOGGING_DAEMON_H */ diff --git a/ACE/examples/C++NPv2/AIO_CLD_export.h b/ACE/examples/C++NPv2/AIO_CLD_export.h new file mode 100644 index 00000000000..315bc287cf3 --- /dev/null +++ b/ACE/examples/C++NPv2/AIO_CLD_export.h @@ -0,0 +1,54 @@ + +// -*- C++ -*- +// $Id$ +// Definition for Win32 Export directives. +// This file is generated automatically by generate_export_file.pl AIO_CLD +// ------------------------------ +#ifndef AIO_CLD_EXPORT_H +#define AIO_CLD_EXPORT_H + +#include "ace/config-all.h" + +#if defined (ACE_AS_STATIC_LIBS) && !defined (AIO_CLD_HAS_DLL) +# define AIO_CLD_HAS_DLL 0 +#endif /* ACE_AS_STATIC_LIBS && ! AIO_CLD_HAS_DLL */ + +#if !defined (AIO_CLD_HAS_DLL) +# define AIO_CLD_HAS_DLL 1 +#endif /* ! AIO_CLD_HAS_DLL */ + +#if defined (AIO_CLD_HAS_DLL) && (AIO_CLD_HAS_DLL == 1) +# if defined (AIO_CLD_BUILD_DLL) +# define AIO_CLD_Export ACE_Proper_Export_Flag +# define AIO_CLD_SINGLETON_DECLARATION(T) ACE_EXPORT_SINGLETON_DECLARATION (T) +# define AIO_CLD_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) ACE_EXPORT_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) +# else /* AIO_CLD_BUILD_DLL */ +# define AIO_CLD_Export ACE_Proper_Import_Flag +# define AIO_CLD_SINGLETON_DECLARATION(T) ACE_IMPORT_SINGLETON_DECLARATION (T) +# define AIO_CLD_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) ACE_IMPORT_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) +# endif /* AIO_CLD_BUILD_DLL */ +#else /* AIO_CLD_HAS_DLL == 1 */ +# define AIO_CLD_Export +# define AIO_CLD_SINGLETON_DECLARATION(T) +# define AIO_CLD_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) +#endif /* AIO_CLD_HAS_DLL == 1 */ + +// Set AIO_CLD_NTRACE = 0 to turn on library specific tracing even if +// tracing is turned off for ACE. +#if !defined (AIO_CLD_NTRACE) +# if (ACE_NTRACE == 1) +# define AIO_CLD_NTRACE 1 +# else /* (ACE_NTRACE == 1) */ +# define AIO_CLD_NTRACE 0 +# endif /* (ACE_NTRACE == 1) */ +#endif /* !AIO_CLD_NTRACE */ + +#if (AIO_CLD_NTRACE == 1) +# define AIO_CLD_TRACE(X) +#else /* (AIO_CLD_NTRACE == 1) */ +# define AIO_CLD_TRACE(X) ACE_TRACE_IMPL(X) +#endif /* (AIO_CLD_NTRACE == 1) */ + +#endif /* AIO_CLD_EXPORT_H */ + +// End of auto generated file. diff --git a/ACE/examples/C++NPv2/AIO_Client_Logging_Daemon.cpp b/ACE/examples/C++NPv2/AIO_Client_Logging_Daemon.cpp new file mode 100644 index 00000000000..56983e8f89a --- /dev/null +++ b/ACE/examples/C++NPv2/AIO_Client_Logging_Daemon.cpp @@ -0,0 +1,360 @@ +/* +** $Id$ +** +** Copyright 2002 Addison Wesley. All Rights Reserved. +*/ + +#include "ace/config-all.h" + +#if (defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)) || (defined (ACE_HAS_AIO_CALLS)) + +#include "ace/OS_NS_string.h" +#include "ace/OS_NS_sys_socket.h" +#include "ace/Asynch_Acceptor.h" +#include "ace/Asynch_Connector.h" +#include "ace/Asynch_IO.h" +#include "ace/CDR_Stream.h" +#include "ace/Get_Opt.h" +#include "ace/INET_Addr.h" +#include "ace/Message_Block.h" +#include "ace/Null_Condition.h" +#include "ace/Null_Mutex.h" +#include "ace/Proactor.h" +#include "ace/SOCK_Stream.h" +#include "ace/Service_Object.h" +#include "ace/Signal.h" +#include "ace/Singleton.h" +#include "ace/Task.h" +#include "ace/Thread_Manager.h" +#include "ace/Unbounded_Set.h" +#include "ace/os_include/os_netdb.h" +#include "AIO_CLD_export.h" +#include "AIO_Client_Logging_Daemon.h" +#include <openssl/ssl.h> + + + +class AIO_CLD_Acceptor + : public ACE_Asynch_Acceptor<AIO_Input_Handler> { +public: + // Cancel accept and close all clients. + void close (void); + + // Remove handler from client set. + void remove (AIO_Input_Handler *ih) + { clients_.remove (ih); } + +protected: + // Service handler factory method. + virtual AIO_Input_Handler *make_handler (void); + + // Set of all connected clients + ACE_Unbounded_Set<AIO_Input_Handler *> clients_; +}; + + +class AIO_Client_Logging_Daemon : public ACE_Task<ACE_NULL_SYNCH> { +protected: + ACE_INET_Addr cld_addr_; + ACE_INET_Addr sld_addr_; + + // Factory that passively connects the <AIO_Input_Handler>. + AIO_CLD_Acceptor acceptor_; + +public: + // Service Configurator hook methods. + virtual int init (int argc, ACE_TCHAR *argv[]); + virtual int fini (); + virtual int svc (void); +}; + +/******************************************************/ + +AIO_Output_Handler::~AIO_Output_Handler () { + reader_.cancel (); + writer_.cancel (); + ACE_OS::closesocket (handle ()); +} + +int AIO_Output_Handler::put (ACE_Message_Block *mb, + ACE_Time_Value *timeout) { + if (can_write_) { start_write (mb); return 0; } + return putq (mb, timeout); +} + +void AIO_Output_Handler::open + (ACE_HANDLE new_handle, ACE_Message_Block &) { + ACE_SOCK_Stream peer (new_handle); + int bufsiz = ACE_DEFAULT_MAX_SOCKET_BUFSIZ; + peer.set_option (SOL_SOCKET, SO_SNDBUF, + &bufsiz, sizeof bufsiz); + + reader_.open (*this, new_handle, 0, proactor ()); + writer_.open (*this, new_handle, 0, proactor ()); + + ACE_Message_Block *mb; + ACE_NEW (mb, ACE_Message_Block (1)); + reader_.read (*mb, 1); + ACE_Sig_Action no_sigpipe ((ACE_SignalHandler) SIG_IGN); + no_sigpipe.register_action (SIGPIPE, 0); + can_write_ = 1; + start_write (0); +} + +void AIO_Output_Handler::start_write (ACE_Message_Block *mblk) { + if (mblk == 0) { + ACE_Time_Value nonblock (0); + getq (mblk, &nonblock); + } + if (mblk != 0) { + can_write_ = 0; + if (writer_.write (*mblk, mblk->length ()) == -1) + ungetq (mblk); + } +} + +void AIO_Output_Handler::handle_read_stream + (const ACE_Asynch_Read_Stream::Result &result) { + result.message_block ().release (); + writer_.cancel (); + ACE_OS::closesocket (result.handle ()); + handle (ACE_INVALID_HANDLE); + can_write_ = 0; + CLD_CONNECTOR::instance ()->reconnect (); +} + +void AIO_Output_Handler::handle_write_stream + (const ACE_Asynch_Write_Stream::Result &result) { + ACE_Message_Block &mblk = result.message_block (); + if (!result.success ()) { + mblk.rd_ptr (mblk.base ()); + ungetq (&mblk); + } + else { + can_write_ = handle () == result.handle (); + if (mblk.length () == 0) { + mblk.release (); + if (can_write_) start_write (); + } + else if (can_write_) start_write (&mblk); + else { mblk.rd_ptr (mblk.base ()); ungetq (&mblk); } + } +} + +/******************************************************/ + +AIO_Input_Handler::~AIO_Input_Handler () { + reader_.cancel (); + ACE_OS::closesocket (handle ()); + if (mblk_ != 0) mblk_->release (); + mblk_ = 0; + acceptor_->remove (this); +} + +void AIO_Input_Handler::open + (ACE_HANDLE new_handle, ACE_Message_Block &) { + reader_.open (*this, new_handle, 0, proactor ()); + ACE_NEW_NORETURN + (mblk_, ACE_Message_Block (ACE_DEFAULT_CDR_BUFSIZE)); + // Align the Message Block for a CDR stream + ACE_CDR::mb_align (mblk_); + reader_.read (*mblk_, LOG_HEADER_SIZE); +} + +void AIO_Input_Handler::handle_read_stream + (const ACE_Asynch_Read_Stream::Result &result) { + if (!result.success () || result.bytes_transferred () == 0) + delete this; + else if (result.bytes_transferred () < result.bytes_to_read ()) + reader_.read (*mblk_, result.bytes_to_read () - + result.bytes_transferred ()); + else if (mblk_->length () == LOG_HEADER_SIZE) { + ACE_InputCDR cdr (mblk_); + + ACE_CDR::Boolean byte_order; + cdr >> ACE_InputCDR::to_boolean (byte_order); + cdr.reset_byte_order (byte_order); + + ACE_CDR::ULong length; + cdr >> length; + + mblk_->size (length + LOG_HEADER_SIZE); + reader_.read (*mblk_, length); + } + else { + if (OUTPUT_HANDLER::instance ()->put (mblk_) == -1) + mblk_->release (); + + ACE_NEW_NORETURN + (mblk_, ACE_Message_Block (ACE_DEFAULT_CDR_BUFSIZE)); + ACE_CDR::mb_align (mblk_); + reader_.read (*mblk_, LOG_HEADER_SIZE); + } +} + +/********************************************************/ + +void AIO_CLD_Acceptor::close (void) { + ACE_Unbounded_Set_Iterator<AIO_Input_Handler *> + iter (clients_.begin ()); + AIO_Input_Handler **ih; + while (iter.next (ih)) + delete *ih; +} + +AIO_Input_Handler * AIO_CLD_Acceptor::make_handler (void) { + AIO_Input_Handler *ih; + ACE_NEW_RETURN (ih, AIO_Input_Handler (this), 0); + if (clients_.insert (ih) == -1) + { delete ih; return 0; } + return ih; +} + +/*******************************************************/ + +#if !defined (CLD_CERTIFICATE_FILENAME) +# define CLD_CERTIFICATE_FILENAME "cld-cert.pem" +#endif /* !CLD_CERTIFICATE_FILENAME */ +#if !defined (CLD_KEY_FILENAME) +# define CLD_KEY_FILENAME "cld-key.pem" +#endif /* !CLD_KEY_FILENAME */ + + +int AIO_CLD_Connector::validate_connection + (const ACE_Asynch_Connect::Result& result, + const ACE_INET_Addr &remote, const ACE_INET_Addr&) { + + remote_addr_ = remote; + if (!result.success ()) { + ACE_Time_Value delay (retry_delay_); + retry_delay_ *= 2; + if (retry_delay_ > MAX_RETRY_DELAY) + retry_delay_ = MAX_RETRY_DELAY; + proactor ()->schedule_timer (*this, 0, delay); + return -1; + } + retry_delay_ = INITIAL_RETRY_DELAY; + + if (ssl_ctx_ == 0) { + OpenSSL_add_ssl_algorithms (); + ssl_ctx_ = SSL_CTX_new (SSLv3_client_method ()); + if (ssl_ctx_ == 0) return -1; + + if (SSL_CTX_use_certificate_file (ssl_ctx_, + CLD_CERTIFICATE_FILENAME, + SSL_FILETYPE_PEM) <= 0 + || SSL_CTX_use_PrivateKey_file (ssl_ctx_, + CLD_KEY_FILENAME, + SSL_FILETYPE_PEM) <= 0 + || !SSL_CTX_check_private_key (ssl_ctx_)) { + SSL_CTX_free (ssl_ctx_); + ssl_ctx_ = 0; + return -1; + } + ssl_ = SSL_new (ssl_ctx_); + if (ssl_ == 0) { + SSL_CTX_free (ssl_ctx_); ssl_ctx_ = 0; + return -1; + } + } + + SSL_clear (ssl_); +#if defined (ACE_WIN32) + // ACE_WIN32 is the only platform where ACE_HANDLE is not an int. + // See ace/config-lite.h for the typedefs. + SSL_set_fd (ssl_, reinterpret_cast<int> (result.connect_handle ())); +#else + SSL_set_fd (ssl_, result.connect_handle ()); +#endif /* ACE_WIN32 */ + SSL_set_verify (ssl_, SSL_VERIFY_PEER, 0); + + if (SSL_connect (ssl_) == -1 + || SSL_shutdown (ssl_) == -1) return -1; + return 0; +} + +void AIO_CLD_Connector::handle_time_out +(const ACE_Time_Value&, const void *) { + connect (remote_addr_); +} + +/******************************************************/ + +int AIO_Client_Logging_Daemon::init + (int argc, ACE_TCHAR *argv[]) { + u_short cld_port = ACE_DEFAULT_SERVICE_PORT; + u_short sld_port = ACE_DEFAULT_LOGGING_SERVER_PORT; + ACE_TCHAR sld_host[MAXHOSTNAMELEN]; + ACE_OS::strcpy (sld_host, ACE_LOCALHOST); + + ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("p:r:s:"), 0); + get_opt.long_option (ACE_TEXT ("client_port"), 'p', + ACE_Get_Opt::ARG_REQUIRED); + get_opt.long_option (ACE_TEXT ("server_port"), 'r', + ACE_Get_Opt::ARG_REQUIRED); + get_opt.long_option (ACE_TEXT ("server_name"), 's', + ACE_Get_Opt::ARG_REQUIRED); + + for (int c; (c = get_opt ()) != -1;) + switch (c) { + case 'p': // Client logging daemon acceptor port number. + cld_port = static_cast<u_short> (ACE_OS::atoi (get_opt.opt_arg ())); + break; + case 'r': // Server logging daemon acceptor port number. + sld_port = static_cast<u_short> (ACE_OS::atoi (get_opt.opt_arg ())); + break; + case 's': // Server logging daemon hostname. + ACE_OS::strsncpy + (sld_host, get_opt.opt_arg (), MAXHOSTNAMELEN); + break; + } + + if (cld_addr_.set (cld_port) == -1 || + sld_addr_.set (sld_port, sld_host) == -1) + return -1; + return activate (); +} + +int AIO_Client_Logging_Daemon::fini () { + ACE_Proactor::instance ()->proactor_end_event_loop (); + wait (); + return 0; +} + +int AIO_Client_Logging_Daemon::svc (void) { + if (acceptor_.open (cld_addr_) == -1) return -1; + if (CLD_CONNECTOR::instance ()->connect (sld_addr_) == 0) + ACE_Proactor::instance ()->proactor_run_event_loop (); + acceptor_.close (); + CLD_CONNECTOR::close (); + OUTPUT_HANDLER::close (); + return 0; +} + +#else /* There's no AIO support on this platform */ + +#include "ace/Task.h" +#include "ace/Service_Object.h" +#include "ace/Synch_Traits.h" +#include "AIO_CLD_export.h" + +class AIO_Client_Logging_Daemon : public ACE_Task<ACE_NULL_SYNCH> { +public: + // Service Configurator hook methods. + virtual int init (int, ACE_TCHAR *[]); + virtual int fini (); +}; + +int AIO_Client_Logging_Daemon::init (int, ACE_TCHAR *[]) { + + ACE_ERROR_RETURN + ((LM_ERROR, ACE_TEXT ("This service requires AIO support\n")), -1); +} + +int AIO_Client_Logging_Daemon::fini () { + return 0; +} + +ACE_FACTORY_DEFINE (AIO_CLD, AIO_Client_Logging_Daemon) + +#endif /* (ACE_WIN32 && !ACE_HAS_WINCE) || ACE_HAS_AIO_CALLS */ diff --git a/ACE/examples/C++NPv2/AIO_Client_Logging_Daemon.h b/ACE/examples/C++NPv2/AIO_Client_Logging_Daemon.h new file mode 100644 index 00000000000..7c0d81da606 --- /dev/null +++ b/ACE/examples/C++NPv2/AIO_Client_Logging_Daemon.h @@ -0,0 +1,135 @@ +/* +** $Id$ +** +** Copyright 2002 Addison Wesley. All Rights Reserved. +*/ + +#ifndef _AIO_CLIENT_LOGGING_DAEMON_H +#define _AIO_CLIENT_LOGGING_DAEMON_H + +#include "ace/Asynch_Connector.h" +#include "ace/Asynch_IO.h" +#include "ace/Message_Block.h" +#include "ace/Null_Mutex.h" +#include "ace/Proactor.h" +#include "ace/Singleton.h" +#include "ace/Synch_Traits.h" +#include "ace/Task.h" + +#include <openssl/ssl.h> + +class AIO_CLD_Acceptor; + +class AIO_Input_Handler : public ACE_Service_Handler { +public: + AIO_Input_Handler (AIO_CLD_Acceptor *acc = 0) + : acceptor_ (acc), mblk_ (0) {} + + virtual ~AIO_Input_Handler (); + + // Called by ACE_Asynch_Acceptor when a client connects. + virtual void open (ACE_HANDLE new_handle, + ACE_Message_Block &message_block); + +protected: + enum { LOG_HEADER_SIZE = 8 }; // Length of CDR header + AIO_CLD_Acceptor *acceptor_; // Our creator + ACE_Message_Block *mblk_; // Block to receive log record + ACE_Asynch_Read_Stream reader_; // Async read factory + + // Handle input from logging clients. + virtual void handle_read_stream + (const ACE_Asynch_Read_Stream::Result &result); +}; + + +class AIO_Output_Handler + : public ACE_Task<ACE_NULL_SYNCH>, + public ACE_Service_Handler { +public: + AIO_Output_Handler () : can_write_ (0) {} + + virtual ~AIO_Output_Handler (); + + // Entry point into the <AIO_Output_Handler>. + virtual int put (ACE_Message_Block *, ACE_Time_Value * = 0); + + // Hook method called when server connection is established. + using ACE_Service_Handler::open; + virtual void open (ACE_HANDLE new_handle, + ACE_Message_Block &message_block); + +protected: + ACE_Asynch_Read_Stream reader_; // Detects connection loss + ACE_Asynch_Write_Stream writer_; // Sends to server + int can_write_; // Safe to begin send a log record? + + // Initiate the send of a log record + void start_write (ACE_Message_Block *mblk = 0); + + // Handle disconnects from the logging server. + virtual void handle_read_stream + (const ACE_Asynch_Read_Stream::Result &result); + + // Handle completed write to logging server. + virtual void handle_write_stream + (const ACE_Asynch_Write_Stream::Result &result); +}; + +typedef ACE_Unmanaged_Singleton<AIO_Output_Handler, ACE_Null_Mutex> + OUTPUT_HANDLER; + + +class AIO_CLD_Connector + : public ACE_Asynch_Connector<AIO_Output_Handler> { +public: + enum { INITIAL_RETRY_DELAY = 3, MAX_RETRY_DELAY = 60 }; + + // Constructor. + AIO_CLD_Connector () + : retry_delay_ (INITIAL_RETRY_DELAY), ssl_ctx_ (0), ssl_ (0) + { open (); } + + // Destructor frees the SSL resources. + virtual ~AIO_CLD_Connector (void) { + SSL_free (ssl_); + SSL_CTX_free (ssl_ctx_); + proactor ()->cancel_timer (*this); + } + + // Hook method to detect failure and validate peer before + // opening handler. + virtual int validate_connection + (const ACE_Asynch_Connect::Result& result, + const ACE_INET_Addr &remote, const ACE_INET_Addr& local); + + // Re-establish a connection to the logging server. + int reconnect (void) { return connect (remote_addr_); } + +protected: + // Hook method called on timer expiration - retry connect + virtual void handle_time_out + (const ACE_Time_Value&, const void *); + + // Template method to create a new handler + virtual AIO_Output_Handler *make_handler (void) + { return OUTPUT_HANDLER::instance (); } + + // Address at which logging server listens for connections. + ACE_INET_Addr remote_addr_; + + // Seconds to wait before trying the next connect + int retry_delay_; + + // The SSL "context" data structure. + SSL_CTX *ssl_ctx_; + + // The SSL data structure corresponding to authenticated SSL + // connections. + SSL *ssl_; +}; + +typedef ACE_Unmanaged_Singleton<AIO_CLD_Connector, ACE_Null_Mutex> + CLD_CONNECTOR; + +#endif /* _AIO_CLIENT_LOGGING_DAEMON_H */ diff --git a/ACE/examples/C++NPv2/C++NPv2.mpc b/ACE/examples/C++NPv2/C++NPv2.mpc new file mode 100644 index 00000000000..675db6f9929 --- /dev/null +++ b/ACE/examples/C++NPv2/C++NPv2.mpc @@ -0,0 +1,183 @@ +// -*- MPC -*- +// $Id$ + +// The specific section for gnuace is here to avoid problems +// with parallel builds. Since the libraries in question share source +// files, we need to ensure that one of them is built before all others. +// Also, a specific section was used because you can't set build order +// without setting a build dependency within vc6 and the like. + +project(*AC_CLD) : acelib, ssl { + avoids += uses_wchar + sharedname = AC_CLD + dynamicflags = AC_CLD_BUILD_DLL + specific(gnuace) { + after += *CLD + } + Source_Files { + AC_Client_Logging_Daemon.cpp + Logging_Handler.cpp + } +} + +project(*AIO_CLD) : acelib, ssl { + sharedname = AIO_CLD + dynamicflags = AIO_CLD_BUILD_DLL + Source_Files { + AIO_Client_Logging_Daemon.cpp + } +} + +project(*CLD) : acelib { + avoids += uses_wchar ace_for_tao + sharedname = CLD + dynamicflags = CLD_BUILD_DLL + Source_Files { + Client_Logging_Daemon.cpp + Logging_Acceptor.cpp + Logging_Event_Handler.cpp + Logging_Handler.cpp + } +} + +project(*Configurable_Log_Server) : aceexe { + avoids += uses_wchar + exename = configurable_logging_server + Source_Files { + Configurable_Logging_Server.cpp + Service_Reporter.cpp + } +} + +project(*Display_Logfile) : aceexe { + avoids += ace_for_tao + exename = display_logfile + Source_Files { + display_logfile.cpp + } +} + +project(*Reactor_Log_Server) : aceexe { + avoids += uses_wchar ace_for_tao + exename = reactor_logging_server + Source_Files { + Logging_Acceptor.cpp + Logging_Event_Handler.cpp + Logging_Event_Handler_Ex.cpp + Logging_Handler.cpp + Reactor_Logging_Server.cpp + } +} + +project(*Select_Reactor_Log_Server) : aceexe { + avoids += uses_wchar ace_for_tao + exename = select_reactor_logging_server + specific(gnuace) { + after += *Reactor_Log_Server + } + Source_Files { + Logging_Acceptor.cpp + Logging_Event_Handler.cpp + Logging_Event_Handler_Ex.cpp + Logging_Handler.cpp + Select_Reactor_Logging_Server.cpp + } +} + +project(*SLD) : acelib { + avoids += uses_wchar ace_for_tao + sharedname = SLD + dynamicflags = SLD_BUILD_DLL + specific(gnuace) { + after += *CLD + } + Source_Files { + SLD.cpp + Logging_Acceptor.cpp + Logging_Event_Handler.cpp + Logging_Handler.cpp + } +} + +project(*SLDex) : acelib { + avoids += uses_wchar ace_for_tao + sharedname = SLDex + dynamicflags = SLDEX_BUILD_DLL + specific(gnuace) { + after += *CLD + } + Source_Files { + Logging_Acceptor.cpp + Logging_Event_Handler.cpp + Logging_Event_Handler_Ex.cpp + Logging_Handler.cpp + Reactor_Logging_Server_Adapter.cpp + Server_Shutdown.cpp + SLDex.cpp + } +} + +project(*SR_Configurable_Log_Server) : aceexe { + exename = sr_configurable_logging_server + Source_Files { + SR_Configurable_Logging_Server.cpp + } +} + +project(*TP_Reactor_Log_Server) : aceexe { + avoids += uses_wchar ace_for_tao + exename = tp_reactor_logging_server + specific(gnuace) { + after += *Reactor_Log_Server + } + Source_Files { + Logging_Acceptor.cpp + Logging_Event_Handler.cpp + Logging_Event_Handler_Ex.cpp + Logging_Handler.cpp + TP_Reactor_Logging_Server.cpp + } +} + +project(*TPCLS) : acelib, ssl { + avoids += uses_wchar + sharedname = TPCLS + dynamicflags = TPCLS_BUILD_DLL + specific(gnuace) { + after += *CLD + } + Source_Files { + TPC_Logging_Server.cpp + Logging_Handler.cpp + } +} + +project(*TPLS) : acelib { + avoids += uses_wchar ace_for_tao + sharedname = TPLS + dynamicflags = TPLS_BUILD_DLL + specific(gnuace) { + after += *CLD + } + Source_Files { + Logging_Acceptor.cpp + Logging_Event_Handler.cpp + Logging_Handler.cpp + TP_Logging_Server.cpp + } +} + +project(*WFMO_Reactor_Log_Server) : aceexe, wfmo { + avoids += uses_wchar ace_for_tao + exename = wfmo_reactor_logging_server + specific(gnuace) { + after += *Reactor_Log_Server + } + Source_Files { + Logging_Acceptor.cpp + Logging_Event_Handler.cpp + Logging_Event_Handler_Ex.cpp + Logging_Handler.cpp + WFMO_Reactor_Logging_Server.cpp + } +} diff --git a/ACE/examples/C++NPv2/CLD_export.h b/ACE/examples/C++NPv2/CLD_export.h new file mode 100644 index 00000000000..3920094e133 --- /dev/null +++ b/ACE/examples/C++NPv2/CLD_export.h @@ -0,0 +1,38 @@ + +// -*- C++ -*- +// $Id$ +// Definition for Win32 Export directives. +// This file is generated automatically by generate_export_file.pl CLD +// ------------------------------ +#ifndef CLD_EXPORT_H +#define CLD_EXPORT_H + +#include "ace/config-all.h" + +#if defined (ACE_AS_STATIC_LIBS) && !defined (CLD_HAS_DLL) +# define CLD_HAS_DLL 0 +#endif /* ACE_AS_STATIC_LIBS && ! CLD_HAS_DLL */ + +#if !defined (CLD_HAS_DLL) +# define CLD_HAS_DLL 1 +#endif /* ! CLD_HAS_DLL */ + +#if defined (CLD_HAS_DLL) && (CLD_HAS_DLL == 1) +# if defined (CLD_BUILD_DLL) +# define CLD_Export ACE_Proper_Export_Flag +# define CLD_SINGLETON_DECLARATION(T) ACE_EXPORT_SINGLETON_DECLARATION (T) +# define CLD_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) ACE_EXPORT_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) +# else /* CLD_BUILD_DLL */ +# define CLD_Export ACE_Proper_Import_Flag +# define CLD_SINGLETON_DECLARATION(T) ACE_IMPORT_SINGLETON_DECLARATION (T) +# define CLD_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) ACE_IMPORT_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) +# endif /* CLD_BUILD_DLL */ +#else /* CLD_HAS_DLL == 1 */ +# define CLD_Export +# define CLD_SINGLETON_DECLARATION(T) +# define CLD_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) +#endif /* CLD_HAS_DLL == 1 */ + +#endif /* CLD_EXPORT_H */ + +// End of auto generated file. diff --git a/ACE/examples/C++NPv2/Client_Logging_Daemon.cpp b/ACE/examples/C++NPv2/Client_Logging_Daemon.cpp new file mode 100644 index 00000000000..5fc0d554cbd --- /dev/null +++ b/ACE/examples/C++NPv2/Client_Logging_Daemon.cpp @@ -0,0 +1,379 @@ +/* +** $Id$ +** +** Copyright 2002 Addison Wesley. All Rights Reserved. +*/ + +#include "ace/os_include/os_netdb.h" +#include "ace/OS_NS_sys_time.h" +#include "ace/OS_NS_sys_socket.h" +#include "ace/OS_NS_unistd.h" +#include "ace/OS_NS_string.h" +#include "ace/Event_Handler.h" +#include "ace/INET_Addr.h" +#include "ace/Get_Opt.h" +#include "ace/Log_Record.h" +#include "ace/Message_Block.h" +#include "ace/Message_Queue.h" +#include "ace/Reactor.h" +#include "ace/Service_Object.h" +#include "ace/Signal.h" +#include "ace/SOCK_Acceptor.h" +#include "ace/SOCK_Connector.h" +#include "ace/SOCK_Stream.h" +#include "ace/Thread_Manager.h" +#include "Logging_Acceptor.h" +#include "CLD_export.h" + +#if !defined (FLUSH_TIMEOUT) +#define FLUSH_TIMEOUT 120 /* 120 seconds == 2 minutes. */ +#endif /* FLUSH_TIMEOUT */ + + +class CLD_Connector; + +class CLD_Handler : public ACE_Event_Handler { +public: + enum { QUEUE_MAX = sizeof (ACE_Log_Record) * ACE_IOV_MAX }; + + // Initialization hook method. + virtual int open (CLD_Connector *); + virtual int close (); // Shut down hook method. + + // Accessor to the connection to the logging server. + virtual ACE_SOCK_Stream &peer () { return peer_; } + + // Reactor hook methods. + virtual int handle_input (ACE_HANDLE handle); + virtual int handle_close (ACE_HANDLE = ACE_INVALID_HANDLE, + ACE_Reactor_Mask = 0); + +protected: + // Forward log records to the server logging daemon. + virtual ACE_THR_FUNC_RETURN forward (); + + // Send the buffered log records using a gather-write operation. + virtual int send (ACE_Message_Block *chunk[], size_t &count); + + // Entry point into forwarder thread of control. + static ACE_THR_FUNC_RETURN run_svc (void *arg); + + // A synchronized <ACE_Message_Queue> that queues messages. + ACE_Message_Queue<ACE_SYNCH> msg_queue_; + + // Manage the forwarder thread. + ACE_Thread_Manager thr_mgr_; + + // Pointer to our <CLD_Connector>. + CLD_Connector *connector_; + + // Connection to the logging server. + ACE_SOCK_Stream peer_; +}; + + +class CLD_Connector { +public: + // Establish a connection to the logging server + // at the <remote_addr>. + int connect (CLD_Handler *handler, + const ACE_INET_Addr &remote_addr); + + // Re-establish a connection to the logging server. + int reconnect (); + +private: + // Pointer to the <CLD_Handler> that we're connecting. + CLD_Handler *handler_; + + // Address at which the logging server is listening + // for connections. + ACE_INET_Addr remote_addr_; +}; + + +class CLD_Acceptor : public ACE_Event_Handler { +public: + // Initialization hook method. + virtual int open (CLD_Handler *, const ACE_INET_Addr &, + ACE_Reactor * = ACE_Reactor::instance ()); + + // Reactor hook methods. + virtual int handle_input (ACE_HANDLE handle); + virtual int handle_close (ACE_HANDLE = ACE_INVALID_HANDLE, + ACE_Reactor_Mask = 0); + virtual ACE_HANDLE get_handle () const; + +protected: + // Factory that passively connects <ACE_SOCK_Stream>s. + ACE_SOCK_Acceptor acceptor_; + + // Pointer to the handler of log records. + CLD_Handler *handler_; +}; + +/****************************************************/ + +int CLD_Handler::handle_input (ACE_HANDLE handle) { + ACE_Message_Block *mblk = 0; + Logging_Handler logging_handler (handle); + + if (logging_handler.recv_log_record (mblk) != -1) + if (msg_queue_.enqueue_tail (mblk->cont ()) != -1) { + mblk->cont (0); + mblk->release (); + return 0; // Success return. + } else mblk->release (); + return -1; // Error return. +} + + +int CLD_Handler::handle_close (ACE_HANDLE handle, + ACE_Reactor_Mask) +{ return ACE_OS::closesocket (handle); } + + +int CLD_Handler::open (CLD_Connector *connector) { + connector_ = connector; + int bufsiz = ACE_DEFAULT_MAX_SOCKET_BUFSIZ; + peer ().set_option (SOL_SOCKET, SO_SNDBUF, + &bufsiz, sizeof bufsiz); + msg_queue_.high_water_mark (CLD_Handler::QUEUE_MAX); + return thr_mgr_.spawn (&CLD_Handler::run_svc, + this, THR_SCOPE_SYSTEM); +} + + +ACE_THR_FUNC_RETURN CLD_Handler::run_svc (void *arg) { + CLD_Handler *handler = static_cast<CLD_Handler *> (arg); + return handler->forward (); +} + + +ACE_THR_FUNC_RETURN CLD_Handler::forward () { + ACE_Message_Block *chunk[ACE_IOV_MAX]; + size_t message_index = 0; + ACE_Time_Value time_of_last_send (ACE_OS::gettimeofday ()); + ACE_Time_Value timeout; + ACE_Sig_Action no_sigpipe ((ACE_SignalHandler) SIG_IGN); + ACE_Sig_Action original_action; + no_sigpipe.register_action (SIGPIPE, &original_action); + + for (;;) { + if (message_index == 0) { + timeout = ACE_OS::gettimeofday (); + timeout += FLUSH_TIMEOUT; + } + ACE_Message_Block *mblk = 0; + if (msg_queue_.dequeue_head (mblk, &timeout) == -1) { + if (errno != EWOULDBLOCK) break; + else if (message_index == 0) continue; + } else { + if (mblk->size () == 0 + && mblk->msg_type () == ACE_Message_Block::MB_STOP) + { mblk->release (); break; } + chunk[message_index] = mblk; + ++message_index; + } + if (message_index >= ACE_IOV_MAX || + (ACE_OS::gettimeofday () - time_of_last_send + >= ACE_Time_Value(FLUSH_TIMEOUT))) { + if (send (chunk, message_index) == -1) break; + time_of_last_send = ACE_OS::gettimeofday (); + } + } + + if (message_index > 0) send (chunk, message_index); + msg_queue_.close (); + no_sigpipe.restore_action (SIGPIPE, original_action); + return 0; +} + + +int CLD_Handler::send (ACE_Message_Block *chunk[], size_t &count) { + iovec iov[ACE_IOV_MAX]; + size_t iov_size; + int result = 0; + + for (iov_size = 0; iov_size < count; ++iov_size) { + iov[iov_size].iov_base = chunk[iov_size]->rd_ptr (); + iov[iov_size].iov_len = chunk[iov_size]->length (); + } + while (peer ().sendv_n (iov, iov_size) == -1) + if (connector_->reconnect () == -1) { + result = -1; + break; + } + + while (iov_size > 0) { + chunk[--iov_size]->release (); chunk[iov_size] = 0; + } + count = iov_size; + return result; +} + + +int CLD_Handler::close () { + ACE_Message_Block *shutdown_message = 0; + ACE_NEW_RETURN + (shutdown_message, + ACE_Message_Block (0, ACE_Message_Block::MB_STOP), -1); + msg_queue_.enqueue_tail (shutdown_message); + return thr_mgr_.wait (); +} + +/**************************************************************/ + + +int CLD_Acceptor::open (CLD_Handler *handler, + const ACE_INET_Addr &local_addr, + ACE_Reactor *r) { + reactor (r); // Store the reactor pointer. + handler_ = handler; + if (acceptor_.open (local_addr) == -1 + || reactor ()->register_handler + (this, ACE_Event_Handler::ACCEPT_MASK) == -1) + return -1; + return 0; +} + + +ACE_HANDLE CLD_Acceptor::get_handle () const +{ return acceptor_.get_handle (); } + + +int CLD_Acceptor::handle_input (ACE_HANDLE) { + ACE_SOCK_Stream peer_stream; + if (acceptor_.accept (peer_stream) == -1) return -1; + else if (reactor ()->register_handler + (peer_stream.get_handle (), + handler_, + ACE_Event_Handler::READ_MASK) == -1) + return -1; + else return 0; +} + + +int CLD_Acceptor::handle_close (ACE_HANDLE, ACE_Reactor_Mask) { + acceptor_.close (); + handler_->close (); + return 0; +} + + +/***************************************************/ + + +int CLD_Connector::connect + (CLD_Handler *handler, + const ACE_INET_Addr &remote_addr) { + ACE_SOCK_Connector connector; + + if (connector.connect (handler->peer (), remote_addr) == -1) + return -1; + else if (handler->open (this) == -1) + { handler->handle_close (); return -1; } + handler_ = handler; + remote_addr_ = remote_addr; + return 0; +} + + +int CLD_Connector::reconnect () { + // Maximum number of times to retry connect. + const size_t MAX_RETRIES = 5; + + ACE_SOCK_Connector connector; + ACE_Time_Value timeout (1); // Start with 1 second timeout. + size_t i; + for (i = 0; i < MAX_RETRIES; ++i) { + if (i > 0) ACE_OS::sleep (timeout); + if (connector.connect (handler_->peer (), remote_addr_, + &timeout) == -1) + timeout *= 2; // Exponential backoff. + else { + int bufsiz = ACE_DEFAULT_MAX_SOCKET_BUFSIZ; + handler_->peer ().set_option (SOL_SOCKET, SO_SNDBUF, + &bufsiz, sizeof bufsiz); + break; + } + } + return i == MAX_RETRIES ? -1 : 0; +} + + +/*******************************************************/ + +class Client_Logging_Daemon : public ACE_Service_Object { +public: + virtual ~Client_Logging_Daemon () {} // Turn off g++ warnings. + + // Service Configurator hook methods. + virtual int init (int argc, ACE_TCHAR *argv[]); + virtual int fini (); +#if 0 + // Implementing these methods is left as an exercise for the reader. + virtual int info (ACE_TCHAR **bufferp, size_t length = 0) const; + virtual int suspend (); + virtual int resume (); +#endif + +protected: + // Receives, processes, and forwards log records. + CLD_Handler handler_; + + // Factory that passively connects the <CLD_Handler>. + CLD_Acceptor acceptor_; + + // Factory that actively connects the <CLD_Handler>. + CLD_Connector connector_; +}; + + +int Client_Logging_Daemon::init (int argc, ACE_TCHAR *argv[]) { + u_short cld_port = ACE_DEFAULT_SERVICE_PORT; + u_short sld_port = ACE_DEFAULT_LOGGING_SERVER_PORT; + ACE_TCHAR sld_host[MAXHOSTNAMELEN]; + ACE_OS::strcpy (sld_host, ACE_LOCALHOST); + + ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("p:r:s:"), 0); + get_opt.long_option (ACE_TEXT ("client_port"), 'p', + ACE_Get_Opt::ARG_REQUIRED); + get_opt.long_option (ACE_TEXT ("server_port"), 'r', + ACE_Get_Opt::ARG_REQUIRED); + get_opt.long_option (ACE_TEXT ("server_name"), 's', + ACE_Get_Opt::ARG_REQUIRED); + + for (int c; (c = get_opt ()) != -1;) + switch (c) { + case 'p': // Client logging daemon acceptor port number. + cld_port = static_cast<u_short> (ACE_OS::atoi (get_opt.opt_arg ())); + break; + case 'r': // Server logging daemon acceptor port number. + sld_port = static_cast<u_short> (ACE_OS::atoi (get_opt.opt_arg ())); + break; + case 's': // Server logging daemon hostname. + ACE_OS::strsncpy + (sld_host, get_opt.opt_arg (), MAXHOSTNAMELEN); + break; + } + + ACE_INET_Addr cld_addr (cld_port); + ACE_INET_Addr sld_addr (sld_port, sld_host); + + if (acceptor_.open (&handler_, cld_addr) == -1) + return -1; + else if (connector_.connect (&handler_, sld_addr) == -1) + { acceptor_.handle_close (); return -1; } + return 0; +} + + +int Client_Logging_Daemon::fini () { + acceptor_.handle_close (); + handler_.close (); + return 0; +} + + +ACE_FACTORY_DEFINE (CLD, Client_Logging_Daemon) diff --git a/ACE/examples/C++NPv2/Configurable_Logging_Server.cpp b/ACE/examples/C++NPv2/Configurable_Logging_Server.cpp new file mode 100644 index 00000000000..bcd6d42b884 --- /dev/null +++ b/ACE/examples/C++NPv2/Configurable_Logging_Server.cpp @@ -0,0 +1,20 @@ +/* +** $Id$ +** +** Copyright 2002 Addison Wesley. All Rights Reserved. +*/ + +#include "ace/OS_main.h" +#include "ace/Service_Config.h" +#include "ace/Reactor.h" + +int ACE_TMAIN (int argc, ACE_TCHAR *argv[]) { + + ACE_STATIC_SVC_REGISTER (Reporter_Descriptor); + + ACE_Service_Config::open + (argc, argv, ACE_DEFAULT_LOGGER_KEY, 0); + + ACE_Reactor::instance ()->run_reactor_event_loop (); + return 0; +} diff --git a/ACE/examples/C++NPv2/Logging_Acceptor.cpp b/ACE/examples/C++NPv2/Logging_Acceptor.cpp new file mode 100644 index 00000000000..2e7b7479603 --- /dev/null +++ b/ACE/examples/C++NPv2/Logging_Acceptor.cpp @@ -0,0 +1,38 @@ +/* +** $Id$ +** +** Copyright 2002 Addison Wesley. All Rights Reserved. +*/ + +#include "Logging_Acceptor.h" +#include "Logging_Event_Handler.h" + + +int Logging_Acceptor::open (const ACE_INET_Addr &local_addr) { + if (acceptor_.open (local_addr) == -1) return -1; + return reactor ()->register_handler + (this, ACE_Event_Handler::ACCEPT_MASK); +} + +int Logging_Acceptor::handle_input (ACE_HANDLE) { + Logging_Event_Handler *peer_handler = 0; + ACE_NEW_RETURN (peer_handler, + Logging_Event_Handler (reactor ()), + -1); + + if (acceptor_.accept (peer_handler->peer ()) == -1) { + delete peer_handler; + return -1; + } else if (peer_handler->open () == -1) { + peer_handler->handle_close (); + return -1; + } + return 0; +} + +int Logging_Acceptor::handle_close (ACE_HANDLE, + ACE_Reactor_Mask) { + acceptor_.close (); + delete this; + return 0; +} diff --git a/ACE/examples/C++NPv2/Logging_Acceptor.h b/ACE/examples/C++NPv2/Logging_Acceptor.h new file mode 100644 index 00000000000..7d38439e3eb --- /dev/null +++ b/ACE/examples/C++NPv2/Logging_Acceptor.h @@ -0,0 +1,53 @@ +/* +** $Id$ +** +** Copyright 2002 Addison Wesley. All Rights Reserved. +*/ + +#ifndef _LOGGING_ACCEPTOR_H +#define _LOGGING_ACCEPTOR_H + +#include "ace/Event_Handler.h" +#include "ace/INET_Addr.h" +#include "ace/Log_Record.h" +#include "ace/Reactor.h" +#include "ace/SOCK_Acceptor.h" +#include "ace/SOCK_Stream.h" +#include "Logging_Handler.h" + +class Logging_Acceptor : public ACE_Event_Handler +{ +protected: + // Factory that connects <ACE_SOCK_Stream>s passively. + ACE_SOCK_Acceptor acceptor_; + +protected: + virtual ~Logging_Acceptor () {}; // No-op destructor. + +public: + typedef ACE_INET_Addr PEER_ADDR; + + // Simple constructor. + Logging_Acceptor (ACE_Reactor *r = ACE_Reactor::instance ()) + : ACE_Event_Handler (r) {}; + + // Initialization method. + virtual int open (const ACE_INET_Addr &local_addr); + + // Called by a reactor when there's a new connection to accept. + virtual int handle_input (ACE_HANDLE = ACE_INVALID_HANDLE); + + // Called when this object is destroyed, e.g., when it's + // removed from a reactor. + virtual int handle_close (ACE_HANDLE = ACE_INVALID_HANDLE, + ACE_Reactor_Mask = 0); + + // Return the passive-mode socket's I/O handle. + virtual ACE_HANDLE get_handle () const + { return acceptor_.get_handle (); }; + + // Returns a reference to the underlying <acceptor_>. + ACE_SOCK_Acceptor &acceptor () { return acceptor_; }; +}; + +#endif /* _LOGGING_ACCEPTOR_H */ diff --git a/ACE/examples/C++NPv2/Logging_Acceptor_Ex.h b/ACE/examples/C++NPv2/Logging_Acceptor_Ex.h new file mode 100644 index 00000000000..913ae385db6 --- /dev/null +++ b/ACE/examples/C++NPv2/Logging_Acceptor_Ex.h @@ -0,0 +1,41 @@ +/* +** $Id$ +** +** Copyright 2002 Addison Wesley. All Rights Reserved. +*/ + +#ifndef _LOGGING_ACCEPTOR_EX_H +#define _LOGGING_ACCEPTOR_EX_H + +#include "ace/INET_Addr.h" +#include "ace/Reactor.h" + +#include "Logging_Acceptor.h" +#include "Logging_Event_Handler_Ex.h" + +class Logging_Acceptor_Ex : public Logging_Acceptor +{ +public: + typedef ACE_INET_Addr PEER_ADDR; + + // Simple constructor to pass ACE_Reactor to base class. + Logging_Acceptor_Ex (ACE_Reactor *r = ACE_Reactor::instance ()) + : Logging_Acceptor (r) {} + + int handle_input (ACE_HANDLE) { + Logging_Event_Handler_Ex *peer_handler = 0; + ACE_NEW_RETURN (peer_handler, + Logging_Event_Handler_Ex (reactor ()), + -1); + if (acceptor_.accept (peer_handler->peer ()) == -1) { + delete peer_handler; + return -1; + } else if (peer_handler->open () == -1) { + peer_handler->handle_close (); + return -1; + } + return 0; + } +}; + +#endif /* _LOGGING_ACCEPTOR_EX_H */ diff --git a/ACE/examples/C++NPv2/Logging_Event_Handler.cpp b/ACE/examples/C++NPv2/Logging_Event_Handler.cpp new file mode 100644 index 00000000000..d805e776390 --- /dev/null +++ b/ACE/examples/C++NPv2/Logging_Event_Handler.cpp @@ -0,0 +1,45 @@ +/* +** $Id$ +** +** Copyright 2002 Addison Wesley. All Rights Reserved. +*/ + +#include "ace/FILE_Connector.h" + +#include "Logging_Event_Handler.h" +#include "ace/OS_NS_string.h" +#include "ace/os_include/os_netdb.h" + +int Logging_Event_Handler::open () { + + static const char LOGFILE_SUFFIX[] = ".log"; + char filename[MAXHOSTNAMELEN + sizeof (LOGFILE_SUFFIX)]; + ACE_INET_Addr logging_peer_addr; + + logging_handler_.peer ().get_remote_addr (logging_peer_addr); + logging_peer_addr.get_host_name (filename, MAXHOSTNAMELEN); + ACE_OS::strcat (filename, LOGFILE_SUFFIX); + + ACE_FILE_Connector connector; + connector.connect (log_file_, + ACE_FILE_Addr (filename), + 0, // No timeout. + ACE_Addr::sap_any, // Ignored. + 0, // Don't try to reuse the addr. + O_RDWR|O_CREAT|O_APPEND, + ACE_DEFAULT_FILE_PERMS); + + return reactor ()->register_handler + (this, ACE_Event_Handler::READ_MASK); +} + +int Logging_Event_Handler::handle_input (ACE_HANDLE) +{ return logging_handler_.log_record (); } + +int Logging_Event_Handler::handle_close (ACE_HANDLE, + ACE_Reactor_Mask) { + logging_handler_.close (); + log_file_.close (); + delete this; + return 0; +} diff --git a/ACE/examples/C++NPv2/Logging_Event_Handler.h b/ACE/examples/C++NPv2/Logging_Event_Handler.h new file mode 100644 index 00000000000..f1a71364be5 --- /dev/null +++ b/ACE/examples/C++NPv2/Logging_Event_Handler.h @@ -0,0 +1,61 @@ +/* +** $Id$ +** +** Copyright 2002 Addison Wesley. All Rights Reserved. +*/ + +#ifndef _LOGGING_EVENT_HANDLER_H +#define _LOGGING_EVENT_HANDLER_H + +#include "ace/Event_Handler.h" +#include "ace/FILE_IO.h" +#include "ace/Reactor.h" +#include "ace/SOCK_Stream.h" + +#include "Logging_Handler.h" + +class Logging_Event_Handler : public ACE_Event_Handler +{ +protected: + // File where log records are written. + ACE_FILE_IO log_file_; + + // Connection to remote peer. + Logging_Handler logging_handler_; + +public: + // Initialize the base class and logging handler. + Logging_Event_Handler (ACE_Reactor *reactor) + : ACE_Event_Handler (reactor), + logging_handler_ (log_file_) {}; + + virtual ~Logging_Event_Handler () {}; // No-op destructor. + + // Activate the object. + virtual int open (); + + // Called by a reactor when logging events arrive. + virtual int handle_input (ACE_HANDLE = ACE_INVALID_HANDLE); + + // Called when this object is destroyed, e.g., when it's + // removed from a reactor. + virtual int handle_close (ACE_HANDLE = ACE_INVALID_HANDLE, + ACE_Reactor_Mask = 0); + + // Return socket handle of the contained <Logging_Handler>. + virtual ACE_HANDLE get_handle (void) const { + // Need a non-const reference to call peer(), but that's + // safe since we call a const method using it. + Logging_Handler& h = + const_cast<Logging_Handler&> (logging_handler_); + return h.peer ().get_handle (); + }; + + // Get a reference to the contained <ACE_SOCK_Stream>. + ACE_SOCK_Stream &peer () { return logging_handler_.peer (); }; + + // Return a reference to the <log_file_>. + ACE_FILE_IO &log_file () { return log_file_; }; +}; + +#endif /* _LOGGING_EVENT_HANDLER_H */ diff --git a/ACE/examples/C++NPv2/Logging_Event_Handler_Ex.cpp b/ACE/examples/C++NPv2/Logging_Event_Handler_Ex.cpp new file mode 100644 index 00000000000..858e615e9d9 --- /dev/null +++ b/ACE/examples/C++NPv2/Logging_Event_Handler_Ex.cpp @@ -0,0 +1,41 @@ +/* +** $Id$ +** +** Copyright 2002 Addison Wesley. All Rights Reserved. +*/ + +#include "Logging_Event_Handler_Ex.h" +#include "ace/Timer_Queue.h" + +int Logging_Event_Handler_Ex::handle_input (ACE_HANDLE h) { + time_of_last_log_record_ = + reactor ()->timer_queue ()->gettimeofday (); + return PARENT::handle_input (h); +} + +int Logging_Event_Handler_Ex::open () { + int result = PARENT::open (); + if (result != -1) { + ACE_Time_Value reschedule (max_client_timeout_.sec () / 4); + result = + reactor ()->schedule_timer + (this, + 0, + max_client_timeout_, // Initial timeout. + reschedule); // Subsequent timeouts. + } + return result; +} + +int Logging_Event_Handler_Ex::handle_timeout + (const ACE_Time_Value &now, const void *) { + if (now - time_of_last_log_record_ >= max_client_timeout_) + reactor ()->remove_handler (this, ACE_Event_Handler::READ_MASK); + return 0; +} + +int Logging_Event_Handler_Ex::handle_close (ACE_HANDLE, + ACE_Reactor_Mask) { + reactor ()->cancel_timer (this); + return PARENT::handle_close (); +} diff --git a/ACE/examples/C++NPv2/Logging_Event_Handler_Ex.h b/ACE/examples/C++NPv2/Logging_Event_Handler_Ex.h new file mode 100644 index 00000000000..d6639cf78d2 --- /dev/null +++ b/ACE/examples/C++NPv2/Logging_Event_Handler_Ex.h @@ -0,0 +1,57 @@ +/* +** $Id$ +** +** Copyright 2002 Addison Wesley. All Rights Reserved. +*/ + +#ifndef _LOGGING_EVENT_HANDLER_EX_H +#define _LOGGING_EVENT_HANDLER_EX_H + +#include "ace/Reactor.h" +#include "ace/Time_Value.h" +#include "ace/Recursive_Thread_Mutex.h" + +#include "Logging_Event_Handler.h" + +class Logging_Event_Handler_Ex : public Logging_Event_Handler +{ +private: + // Time when a client last sent a log record. + ACE_Time_Value time_of_last_log_record_; + + // Maximum time to wait for a client log record. + const ACE_Time_Value max_client_timeout_; + +public: + typedef Logging_Event_Handler PARENT; + + // 3600 seconds == one hour. + enum { MAX_CLIENT_TIMEOUT = 3600 }; + + Logging_Event_Handler_Ex + (ACE_Reactor *reactor, + const ACE_Time_Value &max_client_timeout + = ACE_Time_Value (MAX_CLIENT_TIMEOUT)) + : Logging_Event_Handler (reactor), + time_of_last_log_record_ (0), + max_client_timeout_ (max_client_timeout) {} + + virtual ~Logging_Event_Handler_Ex () {} + + virtual int open (); // Activate the event handler. + + // Called by a reactor when logging events arrive. + virtual int handle_input (ACE_HANDLE); + + // Called when a timeout expires to check if the client has + // been idle for an excessive amount of time. + virtual int handle_timeout (const ACE_Time_Value &tv, + const void *act); + + // Called when this object is destroyed, e.g., when it's + // removed from a reactor. + virtual int handle_close (ACE_HANDLE = ACE_INVALID_HANDLE, + ACE_Reactor_Mask = 0); +}; + +#endif /* _LOGGING_EVENT_HANDLER_EX_H */ diff --git a/ACE/examples/C++NPv2/Logging_Handler.cpp b/ACE/examples/C++NPv2/Logging_Handler.cpp new file mode 100644 index 00000000000..a3febb8234d --- /dev/null +++ b/ACE/examples/C++NPv2/Logging_Handler.cpp @@ -0,0 +1,110 @@ +/* +** $Id$ +** +** Copyright 2001 Addison Wesley. All Rights Reserved. +*/ + +#include "ace/ACE.h" +#include "ace/CDR_Stream.h" +#include "ace/INET_Addr.h" +#include "ace/Log_Record.h" +#include "ace/Message_Block.h" + +// FUZZ: disable check_for_streams_include +#include "ace/streams.h" + +#include "Logging_Handler.h" +#include "ace/os_include/os_netdb.h" +#include "ace/OS_NS_string.h" + +int Logging_Handler::recv_log_record (ACE_Message_Block *&mblk) +{ + // Put <logging_peer>'s hostname in new message block. + ACE_INET_Addr peer_addr; + logging_peer_.get_remote_addr (peer_addr); + mblk = new ACE_Message_Block (MAXHOSTNAMELEN + 1); + peer_addr.get_host_name (mblk->wr_ptr (), MAXHOSTNAMELEN); + mblk->wr_ptr (ACE_OS::strlen (mblk->wr_ptr ()) + 1); // Go past name + + // Allocate a message block for the payload; initially at least + // large enough to hold the header, but needs some room for + // alignment. + ACE_Message_Block *payload = + new ACE_Message_Block (ACE_DEFAULT_CDR_BUFSIZE); + // Align the Message Block for a CDR stream + ACE_CDR::mb_align (payload); + if (logging_peer_.recv_n (payload->wr_ptr (), 8) == 8) { + payload->wr_ptr (8); // Reflect addition of 8 bytes + + // Create a CDR stream to parse the 8-byte header. + ACE_InputCDR cdr (payload); + + // Extract the byte-order and use helper methods to + // disambiguate octet, booleans, and chars. + ACE_CDR::Boolean byte_order; + cdr >> ACE_InputCDR::to_boolean (byte_order); + + // Set the byte-order on the stream... + cdr.reset_byte_order (byte_order); + + // Extract the length + ACE_CDR::ULong length; + cdr >> length; + + // Ensure there's sufficient room for log record payload. + ACE_CDR::grow (payload, 8 + ACE_CDR::MAX_ALIGNMENT + length); + + // Use <recv_n> to obtain the contents. + if (logging_peer_.recv_n (payload->wr_ptr (), length) > 0) { + payload->wr_ptr (length); // Reflect additional bytes + // Chain the payload to mblk via the contination field. + mblk->cont (payload); + return length; + } + } + // Error cases end up here, so we need to release the memory to + // prevent a leak. + payload->release (); + payload = 0; + mblk->release (); + mblk = 0; + return -1; +} + + +int Logging_Handler::write_log_record (ACE_Message_Block *mblk) +{ + // Peer hostname is in the <mblk> and the log record data + // is in its continuation. + if (log_file_->send_n (mblk) == -1) + return -1; + if (ACE::debug ()) { + // Build a CDR stream from the log record data. + ACE_InputCDR cdr (mblk->cont ()); + ACE_CDR::Boolean byte_order; + ACE_CDR::ULong length; + // Extract the byte-order and length, ending up at the start + // of the log record itself. Use the byte order to properly + // set the CDR stream for extracting the contents. + cdr >> ACE_InputCDR::to_boolean (byte_order); + cdr.reset_byte_order (byte_order); + cdr >> length; + ACE_Log_Record log_record; + cdr >> log_record; // Finally extract the <ACE_log_record>. + log_record.print (mblk->rd_ptr (), 1, cerr); + } + return mblk->total_length (); +} + + +int Logging_Handler::log_record () +{ + ACE_Message_Block *mblk = 0; + if (recv_log_record (mblk) == -1) + return -1; + else { + int result = write_log_record (mblk); + mblk->release (); // Free up the contents. + return result == -1 ? -1 : 0; + } +} diff --git a/ACE/examples/C++NPv2/Logging_Handler.h b/ACE/examples/C++NPv2/Logging_Handler.h new file mode 100644 index 00000000000..41945c3a182 --- /dev/null +++ b/ACE/examples/C++NPv2/Logging_Handler.h @@ -0,0 +1,57 @@ +/* +** $Id$ +** +** Copyright 2001 Addison Wesley. All Rights Reserved. +*/ + +#ifndef _LOGGING_HANDLER_H +#define _LOGGING_HANDLER_H + +#include "ace/FILE_IO.h" +#include "ace/SOCK_Stream.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL +class ACE_Message_Block; +ACE_END_VERSIONED_NAMESPACE_DECL + +class Logging_Handler +{ +protected: + ACE_FILE_IO *log_file_; // Pointer to a log file. + + ACE_SOCK_Stream logging_peer_; // Connected to the client. + +public: + // Initialization and termination methods. + Logging_Handler (ACE_FILE_IO &log_file): log_file_ (&log_file) {}; + Logging_Handler (ACE_FILE_IO &log_file, + ACE_HANDLE handle): log_file_ (&log_file) + { logging_peer_.set_handle (handle); }; + Logging_Handler (ACE_FILE_IO &log_file, + const ACE_SOCK_Stream &logging_peer) + : log_file_ (&log_file), logging_peer_ (logging_peer) {}; + Logging_Handler (const ACE_SOCK_Stream &logging_peer) + : log_file_ (0), logging_peer_ (logging_peer) {}; + int close () { return logging_peer_.close (); }; + + // Receive one log record from a connected client. Returns + // length of record on success and <mblk> contains the + // hostname, <mblk->cont()> contains the log record header + // (the byte order and the length) and the data. Returns -1 on + // failure or connection close. + int recv_log_record (ACE_Message_Block *&log_record); + + // Write one record to the log file. The <mblk> contains the + // hostname and the <mblk->cont> contains the log record. + // Returns length of record written on success, or -1 on failure. + int write_log_record (ACE_Message_Block *log_record); + + // Log one record by calling <recv_log_record> and + // <write_log_record>. Returns 0 on success and -1 on failure. + int log_record (); + + // Accessor method. + ACE_SOCK_Stream &peer () { return logging_peer_; }; +}; + +#endif /* _LOGGING_HANDLER_H */ diff --git a/ACE/examples/C++NPv2/Makefile.am b/ACE/examples/C++NPv2/Makefile.am new file mode 100644 index 00000000000..e15da126644 --- /dev/null +++ b/ACE/examples/C++NPv2/Makefile.am @@ -0,0 +1,424 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +ACE_BUILDDIR = $(top_builddir) +ACE_ROOT = $(top_srcdir) + +noinst_HEADERS = +noinst_LTLIBRARIES = +noinst_PROGRAMS = + +## Makefile.C++NPv2_AC_CLD.am + +if BUILD_SSL +if !BUILD_ACE_FOR_TAO +if !BUILD_USES_WCHAR + +noinst_LTLIBRARIES += libAC_CLD.la + +libAC_CLD_la_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) \ + -DACE_HAS_SSL=1 \ + @ACE_TLS_CPPFLAGS@ \ + -DAC_CLD_BUILD_DLL + +libAC_CLD_la_SOURCES = \ + AC_Client_Logging_Daemon.cpp \ + Logging_Handler.cpp + +libAC_CLD_la_LDFLAGS = \ + @ACE_TLS_LDFLAGS@ + +noinst_HEADERS += \ + AC_Client_Logging_Daemon.h \ + Logging_Handler.h \ + Reactor_Logging_Server_T.cpp + +endif !BUILD_USES_WCHAR +endif !BUILD_ACE_FOR_TAO +endif BUILD_SSL + +## Makefile.C++NPv2_AIO_CLD.am + +if BUILD_SSL +if !BUILD_ACE_FOR_TAO + +noinst_LTLIBRARIES += libAIO_CLD.la + +libAIO_CLD_la_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) \ + -DACE_HAS_SSL=1 \ + @ACE_TLS_CPPFLAGS@ \ + -DAIO_CLD_BUILD_DLL + +libAIO_CLD_la_SOURCES = \ + AIO_Client_Logging_Daemon.cpp + +libAIO_CLD_la_LDFLAGS = \ + @ACE_TLS_LDFLAGS@ + +noinst_HEADERS += \ + AIO_Client_Logging_Daemon.h \ + Reactor_Logging_Server_T.cpp + +endif !BUILD_ACE_FOR_TAO +endif BUILD_SSL + +## Makefile.C++NPv2_CLD.am + +if !BUILD_ACE_FOR_TAO +if !BUILD_USES_WCHAR + +noinst_LTLIBRARIES += libCLD.la + +libCLD_la_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) \ + -DCLD_BUILD_DLL + +libCLD_la_SOURCES = \ + Client_Logging_Daemon.cpp \ + Logging_Acceptor.cpp \ + Logging_Event_Handler.cpp \ + Logging_Handler.cpp + +noinst_HEADERS += \ + Logging_Acceptor.h \ + Logging_Event_Handler.h \ + Logging_Handler.h \ + Reactor_Logging_Server_T.cpp + +endif !BUILD_USES_WCHAR +endif !BUILD_ACE_FOR_TAO + +## Makefile.C++NPv2_Configurable_Log_Server.am + +if !BUILD_USES_WCHAR +noinst_PROGRAMS += configurable_logging_server + +configurable_logging_server_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +configurable_logging_server_SOURCES = \ + Configurable_Logging_Server.cpp \ + Service_Reporter.cpp \ + Service_Reporter.h + +configurable_logging_server_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_USES_WCHAR + +## Makefile.C++NPv2_Display_Logfile.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS += display_logfile + +display_logfile_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +display_logfile_SOURCES = \ + display_logfile.cpp \ + AC_CLD_export.h \ + AC_Client_Logging_Daemon.h \ + AIO_CLD_export.h \ + AIO_Client_Logging_Daemon.h \ + CLD_export.h \ + Logging_Acceptor.h \ + Logging_Acceptor_Ex.h \ + Logging_Event_Handler.h \ + Logging_Event_Handler_Ex.h \ + Logging_Handler.h \ + Reactor_Logging_Server_Adapter.h \ + Reactor_Logging_Server_T.h \ + SLDEX_export.h \ + SLD_export.h \ + Service_Reporter.h \ + TPCLS_export.h \ + TPC_Logging_Server.h \ + TPLS_export.h \ + TP_Logging_Server.h + +display_logfile_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Makefile.C++NPv2_Reactor_Log_Server.am + +if !BUILD_ACE_FOR_TAO +if !BUILD_USES_WCHAR +noinst_PROGRAMS += reactor_logging_server + +reactor_logging_server_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +reactor_logging_server_SOURCES = \ + Logging_Acceptor.cpp \ + Logging_Event_Handler.cpp \ + Logging_Event_Handler_Ex.cpp \ + Logging_Handler.cpp \ + Reactor_Logging_Server.cpp \ + Logging_Acceptor.h \ + Logging_Event_Handler.h \ + Logging_Event_Handler_Ex.h \ + Logging_Handler.h + +reactor_logging_server_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_USES_WCHAR +endif !BUILD_ACE_FOR_TAO + +## Makefile.C++NPv2_SLD.am + +if !BUILD_ACE_FOR_TAO +if !BUILD_USES_WCHAR + +noinst_LTLIBRARIES += libSLD.la + +libSLD_la_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) \ + -DSLD_BUILD_DLL + +libSLD_la_SOURCES = \ + Logging_Acceptor.cpp \ + Logging_Event_Handler.cpp \ + Logging_Handler.cpp \ + SLD.cpp + +noinst_HEADERS += \ + Logging_Acceptor.h \ + Logging_Event_Handler.h \ + Logging_Handler.h \ + Reactor_Logging_Server_T.cpp + +endif !BUILD_USES_WCHAR +endif !BUILD_ACE_FOR_TAO + +## Makefile.C++NPv2_SLDex.am + +if !BUILD_ACE_FOR_TAO +if !BUILD_USES_WCHAR + +noinst_LTLIBRARIES += libSLDex.la + +libSLDex_la_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) \ + -DSLDEX_BUILD_DLL + +libSLDex_la_SOURCES = \ + Logging_Acceptor.cpp \ + Logging_Event_Handler.cpp \ + Logging_Event_Handler_Ex.cpp \ + Logging_Handler.cpp \ + Reactor_Logging_Server_Adapter.cpp \ + SLDex.cpp \ + Server_Shutdown.cpp + +noinst_HEADERS += \ + Logging_Acceptor.h \ + Logging_Event_Handler.h \ + Logging_Event_Handler_Ex.h \ + Logging_Handler.h \ + Reactor_Logging_Server_Adapter.h \ + Reactor_Logging_Server_T.cpp + +endif !BUILD_USES_WCHAR +endif !BUILD_ACE_FOR_TAO + +## Makefile.C++NPv2_SR_Configurable_Log_Server.am +noinst_PROGRAMS += sr_configurable_logging_server + +sr_configurable_logging_server_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +sr_configurable_logging_server_SOURCES = \ + SR_Configurable_Logging_Server.cpp \ + AC_CLD_export.h \ + AC_Client_Logging_Daemon.h \ + AIO_CLD_export.h \ + AIO_Client_Logging_Daemon.h \ + CLD_export.h \ + Logging_Acceptor.h \ + Logging_Acceptor_Ex.h \ + Logging_Event_Handler.h \ + Logging_Event_Handler_Ex.h \ + Logging_Handler.h \ + Reactor_Logging_Server_Adapter.h \ + Reactor_Logging_Server_T.h \ + SLDEX_export.h \ + SLD_export.h \ + Service_Reporter.h \ + TPCLS_export.h \ + TPC_Logging_Server.h \ + TPLS_export.h \ + TP_Logging_Server.h + +sr_configurable_logging_server_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.C++NPv2_Select_Reactor_Log_Server.am + +if !BUILD_ACE_FOR_TAO +if !BUILD_USES_WCHAR +noinst_PROGRAMS += select_reactor_logging_server + +select_reactor_logging_server_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +select_reactor_logging_server_SOURCES = \ + Logging_Acceptor.cpp \ + Logging_Event_Handler.cpp \ + Logging_Event_Handler_Ex.cpp \ + Logging_Handler.cpp \ + Select_Reactor_Logging_Server.cpp \ + Logging_Acceptor.h \ + Logging_Event_Handler.h \ + Logging_Event_Handler_Ex.h \ + Logging_Handler.h + +select_reactor_logging_server_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_USES_WCHAR +endif !BUILD_ACE_FOR_TAO + +## Makefile.C++NPv2_TPCLS.am + +if BUILD_SSL +if !BUILD_ACE_FOR_TAO +if !BUILD_USES_WCHAR + +noinst_LTLIBRARIES += libTPCLS.la + +libTPCLS_la_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) \ + -DACE_HAS_SSL=1 \ + @ACE_TLS_CPPFLAGS@ \ + -DTPCLS_BUILD_DLL + +libTPCLS_la_SOURCES = \ + Logging_Handler.cpp \ + TPC_Logging_Server.cpp + +libTPCLS_la_LDFLAGS = \ + @ACE_TLS_LDFLAGS@ + +noinst_HEADERS += \ + Logging_Handler.h \ + Reactor_Logging_Server_T.cpp \ + TPC_Logging_Server.h + +endif !BUILD_USES_WCHAR +endif !BUILD_ACE_FOR_TAO +endif BUILD_SSL + +## Makefile.C++NPv2_TPLS.am + +if !BUILD_ACE_FOR_TAO +if !BUILD_USES_WCHAR + +noinst_LTLIBRARIES += libTPLS.la + +libTPLS_la_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) \ + -DTPLS_BUILD_DLL + +libTPLS_la_SOURCES = \ + Logging_Acceptor.cpp \ + Logging_Event_Handler.cpp \ + Logging_Handler.cpp \ + TP_Logging_Server.cpp + +noinst_HEADERS += \ + Logging_Acceptor.h \ + Logging_Event_Handler.h \ + Logging_Handler.h \ + Reactor_Logging_Server_T.cpp \ + TP_Logging_Server.h + +endif !BUILD_USES_WCHAR +endif !BUILD_ACE_FOR_TAO + +## Makefile.C++NPv2_TP_Reactor_Log_Server.am + +if !BUILD_ACE_FOR_TAO +if !BUILD_USES_WCHAR +noinst_PROGRAMS += tp_reactor_logging_server + +tp_reactor_logging_server_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +tp_reactor_logging_server_SOURCES = \ + Logging_Acceptor.cpp \ + Logging_Event_Handler.cpp \ + Logging_Event_Handler_Ex.cpp \ + Logging_Handler.cpp \ + TP_Reactor_Logging_Server.cpp \ + Logging_Acceptor.h \ + Logging_Event_Handler.h \ + Logging_Event_Handler_Ex.h \ + Logging_Handler.h + +tp_reactor_logging_server_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_USES_WCHAR +endif !BUILD_ACE_FOR_TAO + +## Makefile.C++NPv2_WFMO_Reactor_Log_Server.am + +if BUILD_WFMO +if !BUILD_ACE_FOR_TAO +if !BUILD_USES_WCHAR +noinst_PROGRAMS += wfmo_reactor_logging_server + +wfmo_reactor_logging_server_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +wfmo_reactor_logging_server_SOURCES = \ + Logging_Acceptor.cpp \ + Logging_Event_Handler.cpp \ + Logging_Event_Handler_Ex.cpp \ + Logging_Handler.cpp \ + WFMO_Reactor_Logging_Server.cpp \ + Logging_Acceptor.h \ + Logging_Event_Handler.h \ + Logging_Event_Handler_Ex.h \ + Logging_Handler.h + +wfmo_reactor_logging_server_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_USES_WCHAR +endif !BUILD_ACE_FOR_TAO +endif BUILD_WFMO + +## Clean up template repositories, etc. +clean-local: + -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.* + -rm -f gcctemp.c gcctemp so_locations *.ics + -rm -rf cxx_repository ptrepository ti_files + -rm -rf templateregistry ir.out + -rm -rf ptrepository SunWS_cache Templates.DB diff --git a/ACE/examples/C++NPv2/README b/ACE/examples/C++NPv2/README new file mode 100644 index 00000000000..a2d8759dd80 --- /dev/null +++ b/ACE/examples/C++NPv2/README @@ -0,0 +1,99 @@ +(This is file $Id$) + +The files in this directory contain the source code from the book +``C++ Network Programming: Systematic Reuse with ACE and Frameworks'' +(C++NPv2) by Douglas C. Schmidt and Stephen D. Huston (Addison-Wesley +2001, ISBN 0-201-79525-6). + +We have compiled and run these files on the following platforms: + + Sun Solaris 8 on SPARC using Sun Forte 6. + Redhat Linux 7.1 using g++ 2.96. + Microsoft Windows 2000 using Microsoft Visual C++ 6. + +You must have the ACE_ROOT environment variable set correctly to build +these examples. ACE_ROOT must refer to the top-level ACE_wrappers +directory. Please see $ACE_ROOT/ACE-INSTALL.html for instructions on +how to build the ACE toolkit. + +Mapping Source Files to Book Chapters +------------------------------------- + +The files in this directory map to the chapters in C++NPv2 as follows: + +Chapter 3 Logging_Acceptor.cpp + Logging_Acceptor.h + Logging_Acceptor_Ex.h + Logging_Event_Handler.cpp + Logging_Event_Handler.h + Logging_Event_Handler_Ex.cpp + Logging_Event_Handler_Ex.h + Logging_Handler.cpp + Logging_Handler.h + Reactor_Logging_Server.cpp + Reactor_Logging_Server_T.h + Reactor_Logging_Server_T.cpp + +Chapter 4 Select_Reactor_Logging_Server.cpp + TP_Reactor_Logging_Server.cpp + WFMO_Reactor_Logging_Server.cpp + +Chapter 5 Configurable_Logging_Server.cpp + Reactor_Logging_Server_Adapter.cpp + Reactor_Logging_Server_Adapter.h + Service_Reporter.cpp + Service_Reporter.h + Server_Shutdown.cpp + SLD.cpp + SLDEX_export.h + SLD_export.h + SLDex.cpp + +Chapter 6 Client_Logging_Daemon.cpp + CLD_export.h + TPLS_export.h + TP_Logging_Server.cpp + TP_Logging_Server.h + +Chapter 7 AC_CLD_export.h + AC_Client_Logging_Daemon.cpp + SR_Configurable_Logging_Server.cpp + TPC_Logging_Server.cpp + TPC_Logging_Server.h + TPCLS_export.h + +Chapter 8 AIO_CLD_export.h + AIO_Client_Logging_Daemon.cpp + +Chapter 9 display_logfile.cpp + +Microsoft Visual C++ users: +--------------------------- + +The examples.dsw file is a Microsoft Visual C++ workspace file that +contains projects for the individual programs. You can either build +them separately, or use the Batch Build command to build multiple +projects at once. + +All other users: +---------------- + +Assuming that your system is configured correctly, you should be able +to type + +% make + +to compile all of the programs, and + +% make clean + +to remove all the files that were generated during compilation. + +There are also individual Makefiles for each separate example program. +These makefiles have a ".mak" suffix. For example, display_logfile.mak +is the makefile for the display_logfile program. + +All of the files in these directories are copyright Addison Wesley, +and they come with absolutely no warranty whatsoever. Permission is +hereby granted to use these programs for educational or commercial +purposes. diff --git a/ACE/examples/C++NPv2/Reactor_Logging_Server.cpp b/ACE/examples/C++NPv2/Reactor_Logging_Server.cpp new file mode 100644 index 00000000000..b36539c2a6d --- /dev/null +++ b/ACE/examples/C++NPv2/Reactor_Logging_Server.cpp @@ -0,0 +1,29 @@ +/* +** $Id$ +** +** Copyright 2002 Addison Wesley. All Rights Reserved. +*/ + +#include "Reactor_Logging_Server_T.h" +#include "Logging_Acceptor_Ex.h" +#include "ace/Log_Msg.h" + +typedef Reactor_Logging_Server<Logging_Acceptor_Ex> + Server_Logging_Daemon; + +int main (int argc, char *argv[]) +{ + ACE_Reactor reactor; + Server_Logging_Daemon *server; + // Ignore argv[0]... + --argc; ++argv; + ACE_NEW_RETURN (server, + Server_Logging_Daemon (argc, argv, &reactor), + 1); + + if (reactor.run_reactor_event_loop () == -1) + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", + "run_reactor_event_loop()"), 1); + return 0; +} + diff --git a/ACE/examples/C++NPv2/Reactor_Logging_Server_Adapter.cpp b/ACE/examples/C++NPv2/Reactor_Logging_Server_Adapter.cpp new file mode 100644 index 00000000000..128ad5cabd3 --- /dev/null +++ b/ACE/examples/C++NPv2/Reactor_Logging_Server_Adapter.cpp @@ -0,0 +1,69 @@ +/* +** $Id$ +** +** Copyright 2002 Addison Wesley. All Rights Reserved. +*/ + +#ifndef _REACTOR_LOGGING_SERVER_ADAPTER_C +#define _REACTOR_LOGGING_SERVER_ADAPTER_C + +#include "ace/ACE.h" +#include "ace/Auto_Ptr.h" +#include "ace/INET_Addr.h" +#include "Reactor_Logging_Server_Adapter.h" +#include "ace/OS_NS_string.h" +#include "ace/OS_NS_stdio.h" + +template <class ACCEPTOR> int +Reactor_Logging_Server_Adapter<ACCEPTOR>::init (int argc, + ACE_TCHAR *argv[]) { + int i; + char **array = 0; + ACE_NEW_RETURN (array, char*[argc], -1); + ACE_Auto_Array_Ptr<char *> char_argv (array); + + for (i = 0; i < argc; ++i) + char_argv[i] = ACE::strnew (ACE_TEXT_ALWAYS_CHAR (argv[i])); + ACE_NEW_NORETURN (server_, Reactor_Logging_Server<ACCEPTOR> + (i, char_argv.get (), + ACE_Reactor::instance ())); + for (i = 0; i < argc; ++i) ACE::strdelete (char_argv[i]); + return server_ == 0 ? -1 : 0; +} + + +template <class ACCEPTOR> int +Reactor_Logging_Server_Adapter<ACCEPTOR>::fini () +{ server_->handle_close (); server_ = 0; return 0; } + + +template <class ACCEPTOR> int +Reactor_Logging_Server_Adapter<ACCEPTOR>::info + (ACE_TCHAR **bufferp, size_t length) const { + ACE_INET_Addr local_addr; + server_->acceptor ().get_local_addr (local_addr); + + ACE_TCHAR buf[BUFSIZ]; + ACE_OS::sprintf (buf, + ACE_TEXT ("%hu"), + local_addr.get_port_number ()); + ACE_OS::strcat + (buf, ACE_TEXT ("/tcp # Reactor-based logging server\n")); + if (*bufferp == 0) + *bufferp = ACE::strnew (buf); + else + ACE_OS::strncpy (*bufferp, buf, length); + return ACE_OS::strlen (*bufferp); +} + + +template <class ACCEPTOR> int +Reactor_Logging_Server_Adapter<ACCEPTOR>::suspend () +{ return server_->reactor ()->suspend_handler (server_); } + + +template <class ACCEPTOR> int +Reactor_Logging_Server_Adapter<ACCEPTOR>::resume () +{ return server_->reactor ()->resume_handler (server_); } + +#endif /* _REACTOR_LOGGING_SERVER_ADAPTER_C */ diff --git a/ACE/examples/C++NPv2/Reactor_Logging_Server_Adapter.h b/ACE/examples/C++NPv2/Reactor_Logging_Server_Adapter.h new file mode 100644 index 00000000000..aeda81205ab --- /dev/null +++ b/ACE/examples/C++NPv2/Reactor_Logging_Server_Adapter.h @@ -0,0 +1,35 @@ +/* +** $Id$ +** +** Copyright 2002 Addison Wesley. All Rights Reserved. +*/ + +#ifndef _REACTOR_LOGGING_SERVER_ADAPTER_H +#define _REACTOR_LOGGING_SERVER_ADAPTER_H + +#include "ace/Service_Object.h" +#include "Reactor_Logging_Server_T.h" + +template <class ACCEPTOR> +class Reactor_Logging_Server_Adapter : public ACE_Service_Object { +public: + // Hook methods inherited from <ACE_Service_Object>. + virtual int init (int argc, ACE_TCHAR *argv[]); + virtual int fini (); + virtual int info (ACE_TCHAR **, size_t) const; + virtual int suspend (); + virtual int resume (); + +private: + Reactor_Logging_Server<ACCEPTOR> *server_; +}; + +#if defined (ACE_TEMPLATES_REQUIRE_SOURCE) +#include "Reactor_Logging_Server_Adapter.cpp" +#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */ + +#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA) +#pragma implementation ("Reactor_Logging_Server_Adapter.cpp") +#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */ + +#endif /* _REACTOR_LOGGING_SERVER_ADAPTER_H */ diff --git a/ACE/examples/C++NPv2/Reactor_Logging_Server_T.cpp b/ACE/examples/C++NPv2/Reactor_Logging_Server_T.cpp new file mode 100644 index 00000000000..3e25be39373 --- /dev/null +++ b/ACE/examples/C++NPv2/Reactor_Logging_Server_T.cpp @@ -0,0 +1,26 @@ +/* +** $Id$ +** +** Copyright 2002 Addison Wesley. All Rights Reserved. +*/ + +// Implementations for Reactor_Logging_Server<> + +template <class ACCEPTOR> +Reactor_Logging_Server<ACCEPTOR>::Reactor_Logging_Server + (int argc, char *argv[], ACE_Reactor *reactor) + : ACCEPTOR (reactor) { + u_short logger_port = argc > 0 ? atoi (argv[0]) : 0; + ACE_TYPENAME ACCEPTOR::PEER_ADDR server_addr; + int result; + + if (logger_port != 0) + result = server_addr.set (logger_port, + (ACE_UINT32) INADDR_ANY); + else + result = server_addr.set ("ace_logger", + (ACE_UINT32) INADDR_ANY); + if (result != -1) + result = ACCEPTOR::open (server_addr); + if (result == -1) reactor->end_reactor_event_loop (); +} diff --git a/ACE/examples/C++NPv2/Reactor_Logging_Server_T.h b/ACE/examples/C++NPv2/Reactor_Logging_Server_T.h new file mode 100644 index 00000000000..ee16f8a061e --- /dev/null +++ b/ACE/examples/C++NPv2/Reactor_Logging_Server_T.h @@ -0,0 +1,29 @@ +/* +** $Id$ +** +** Copyright 2002 Addison Wesley. All Rights Reserved. +*/ + +#ifndef _REACTOR_LOGGING_SERVER_T_H +#define _REACTOR_LOGGING_SERVER_T_H + +#include "ace/ACE.h" +#include "ace/Reactor.h" + +template <class ACCEPTOR> +class Reactor_Logging_Server : public ACCEPTOR +{ +public: + Reactor_Logging_Server (int argc, char *argv[], + ACE_Reactor *reactor); +}; + +#if defined (ACE_TEMPLATES_REQUIRE_SOURCE) +#include "Reactor_Logging_Server_T.cpp" +#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */ + +#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA) +#pragma implementation ("Reactor_Logging_Server_T.cpp") +#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */ + +#endif /* _REACTOR_LOGGING_SERVER_T_H */ diff --git a/ACE/examples/C++NPv2/SLD.cpp b/ACE/examples/C++NPv2/SLD.cpp new file mode 100644 index 00000000000..3aef89d0df6 --- /dev/null +++ b/ACE/examples/C++NPv2/SLD.cpp @@ -0,0 +1,17 @@ +/* +** $Id$ +** +** Copyright 2002 Addison Wesley. All Rights Reserved. +*/ + +#include "ace/Log_Msg.h" + +#include "Reactor_Logging_Server_Adapter.h" +#include "Logging_Acceptor.h" +#include "SLD_export.h" + +typedef Reactor_Logging_Server_Adapter<Logging_Acceptor> + Server_Logging_Daemon; + +ACE_FACTORY_DEFINE (SLD, Server_Logging_Daemon) + diff --git a/ACE/examples/C++NPv2/SLDEX_export.h b/ACE/examples/C++NPv2/SLDEX_export.h new file mode 100644 index 00000000000..b6cfca66b04 --- /dev/null +++ b/ACE/examples/C++NPv2/SLDEX_export.h @@ -0,0 +1,38 @@ + +// -*- C++ -*- +// $Id$ +// Definition for Win32 Export directives. +// This file is generated automatically by generate_export_file.pl SLDEX +// ------------------------------ +#ifndef SLDEX_EXPORT_H +#define SLDEX_EXPORT_H + +#include "ace/config-all.h" + +#if defined (ACE_AS_STATIC_LIBS) && !defined (SLDEX_HAS_DLL) +# define SLDEX_HAS_DLL 0 +#endif /* ACE_AS_STATIC_LIBS && ! SLDEX_HAS_DLL */ + +#if !defined (SLDEX_HAS_DLL) +# define SLDEX_HAS_DLL 1 +#endif /* ! SLDEX_HAS_DLL */ + +#if defined (SLDEX_HAS_DLL) && (SLDEX_HAS_DLL == 1) +# if defined (SLDEX_BUILD_DLL) +# define SLDEX_Export ACE_Proper_Export_Flag +# define SLDEX_SINGLETON_DECLARATION(T) ACE_EXPORT_SINGLETON_DECLARATION (T) +# define SLDEX_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) ACE_EXPORT_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) +# else /* SLDEX_BUILD_DLL */ +# define SLDEX_Export ACE_Proper_Import_Flag +# define SLDEX_SINGLETON_DECLARATION(T) ACE_IMPORT_SINGLETON_DECLARATION (T) +# define SLDEX_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) ACE_IMPORT_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) +# endif /* SLDEX_BUILD_DLL */ +#else /* SLDEX_HAS_DLL == 1 */ +# define SLDEX_Export +# define SLDEX_SINGLETON_DECLARATION(T) +# define SLDEX_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) +#endif /* SLDEX_HAS_DLL == 1 */ + +#endif /* SLDEX_EXPORT_H */ + +// End of auto generated file. diff --git a/ACE/examples/C++NPv2/SLD_export.h b/ACE/examples/C++NPv2/SLD_export.h new file mode 100644 index 00000000000..77f7467b43a --- /dev/null +++ b/ACE/examples/C++NPv2/SLD_export.h @@ -0,0 +1,38 @@ + +// -*- C++ -*- +// $Id$ +// Definition for Win32 Export directives. +// This file is generated automatically by generate_export_file.pl SLD +// ------------------------------ +#ifndef SLD_EXPORT_H +#define SLD_EXPORT_H + +#include "ace/config-all.h" + +#if defined (ACE_AS_STATIC_LIBS) && !defined (SLD_HAS_DLL) +# define SLD_HAS_DLL 0 +#endif /* ACE_AS_STATIC_LIBS && ! SLD_HAS_DLL */ + +#if !defined (SLD_HAS_DLL) +# define SLD_HAS_DLL 1 +#endif /* ! SLD_HAS_DLL */ + +#if defined (SLD_HAS_DLL) && (SLD_HAS_DLL == 1) +# if defined (SLD_BUILD_DLL) +# define SLD_Export ACE_Proper_Export_Flag +# define SLD_SINGLETON_DECLARATION(T) ACE_EXPORT_SINGLETON_DECLARATION (T) +# define SLD_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) ACE_EXPORT_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) +# else /* SLD_BUILD_DLL */ +# define SLD_Export ACE_Proper_Import_Flag +# define SLD_SINGLETON_DECLARATION(T) ACE_IMPORT_SINGLETON_DECLARATION (T) +# define SLD_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) ACE_IMPORT_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) +# endif /* SLD_BUILD_DLL */ +#else /* SLD_HAS_DLL == 1 */ +# define SLD_Export +# define SLD_SINGLETON_DECLARATION(T) +# define SLD_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) +#endif /* SLD_HAS_DLL == 1 */ + +#endif /* SLD_EXPORT_H */ + +// End of auto generated file. diff --git a/ACE/examples/C++NPv2/SLDex.cpp b/ACE/examples/C++NPv2/SLDex.cpp new file mode 100644 index 00000000000..fbaf7cb3111 --- /dev/null +++ b/ACE/examples/C++NPv2/SLDex.cpp @@ -0,0 +1,17 @@ +/* +** $Id$ +** +** Copyright 2002 Addison Wesley. All Rights Reserved. +*/ + +#include "ace/Log_Msg.h" + +#include "Reactor_Logging_Server_Adapter.h" +#include "Logging_Acceptor_Ex.h" +#include "SLDEX_export.h" + +typedef Reactor_Logging_Server_Adapter<Logging_Acceptor_Ex> + Server_Logging_Daemon_Ex; + +ACE_FACTORY_DEFINE (SLDEX, Server_Logging_Daemon_Ex) + diff --git a/ACE/examples/C++NPv2/SR_Configurable_Logging_Server.cpp b/ACE/examples/C++NPv2/SR_Configurable_Logging_Server.cpp new file mode 100644 index 00000000000..97fc65d386e --- /dev/null +++ b/ACE/examples/C++NPv2/SR_Configurable_Logging_Server.cpp @@ -0,0 +1,26 @@ +/* +** $Id$ +** +** Copyright 2002 Addison Wesley. All Rights Reserved. +*/ + +#include "ace/OS_main.h" +#include "ace/OS_Memory.h" +#include "ace/Reactor.h" +#include "ace/Select_Reactor.h" +#include "ace/Service_Config.h" + + +int ACE_TMAIN (int argc, ACE_TCHAR *argv[]) { + ACE_Select_Reactor *select_reactor; + ACE_NEW_RETURN (select_reactor, ACE_Select_Reactor, 1); + ACE_Reactor *reactor; + ACE_NEW_RETURN (reactor, ACE_Reactor (select_reactor, 1), 1); + ACE_Reactor::close_singleton (); + ACE_Reactor::instance (reactor, 1); + + ACE_Service_Config::open (argc, argv); + + ACE_Reactor::instance ()->run_reactor_event_loop (); + return 0; +} diff --git a/ACE/examples/C++NPv2/Select_Reactor_Logging_Server.cpp b/ACE/examples/C++NPv2/Select_Reactor_Logging_Server.cpp new file mode 100644 index 00000000000..24123c3b3c6 --- /dev/null +++ b/ACE/examples/C++NPv2/Select_Reactor_Logging_Server.cpp @@ -0,0 +1,105 @@ +/* +** $Id$ +** +** Copyright 2002 Addison Wesley. All Rights Reserved. +*/ + +// FUZZ: disable check_for_streams_include +#include "ace/streams.h" + +#include "ace/Reactor.h" +#include "ace/Select_Reactor.h" +#include "ace/Thread_Manager.h" + +#if defined (ACE_WIN32) && (!defined (ACE_HAS_STANDARD_CPP_LIBRARY) || \ + (ACE_HAS_STANDARD_CPP_LIBRARY == 0) || \ + defined (ACE_USES_OLD_IOSTREAMS)) +# include <stdio.h> +#else +# include <string> +#endif + +#include "Reactor_Logging_Server_T.h" +#include "Logging_Acceptor_Ex.h" + +typedef Reactor_Logging_Server<Logging_Acceptor_Ex> + Server_Logging_Daemon; + + +class Quit_Handler : public ACE_Event_Handler { + friend class ace_dewarn_gplusplus; +public: + Quit_Handler (ACE_Reactor *r) : ACE_Event_Handler (r) {} + + virtual int handle_exception (ACE_HANDLE) { + reactor ()->end_reactor_event_loop (); + return -1; // Trigger call to handle_close() method. + } + + virtual int handle_close (ACE_HANDLE, ACE_Reactor_Mask) + { delete this; return 0; } + +private: + + // Private destructor ensures dynamic allocation. + virtual ~Quit_Handler () {} +}; + + +static ACE_THR_FUNC_RETURN event_loop (void *arg) { + ACE_Reactor *reactor = static_cast<ACE_Reactor *> (arg); + + reactor->owner (ACE_OS::thr_self ()); + reactor->run_reactor_event_loop (); + return 0; +} + + +static ACE_THR_FUNC_RETURN controller (void *arg) { + ACE_Reactor *reactor = static_cast<ACE_Reactor *> (arg); + + Quit_Handler *quit_handler = 0; + ACE_NEW_RETURN (quit_handler, Quit_Handler (reactor), 0); + +#if defined (ACE_WIN32) && (!defined (ACE_HAS_STANDARD_CPP_LIBRARY) || \ + (ACE_HAS_STANDARD_CPP_LIBRARY == 0) || \ + defined (ACE_USES_OLD_IOSTREAMS)) + for (;;) { + char user_input[80]; + fgets (user_input, sizeof (user_input), stdin); + if (ACE_OS::strcmp (user_input, "quit") == 0) { + reactor->notify (quit_handler); + break; + } + } +#else + for (;;) { + std::string user_input; + std::getline (cin, user_input, '\n'); + if (user_input == "quit") { + reactor->notify (quit_handler); + break; + } + } +#endif + + return 0; +} + + +int main (int argc, char *argv[]) +{ + ACE_Select_Reactor select_reactor; + ACE_Reactor reactor (&select_reactor); + + Server_Logging_Daemon *server; + // Ignore argv[0]... + --argc; ++argv; + ACE_NEW_RETURN (server, + Server_Logging_Daemon (argc, argv, &reactor), + 1); + ACE_Thread_Manager::instance ()->spawn (event_loop, &reactor); + ACE_Thread_Manager::instance ()->spawn (controller, &reactor); + return ACE_Thread_Manager::instance ()->wait (); +} + diff --git a/ACE/examples/C++NPv2/Server_Shutdown.cpp b/ACE/examples/C++NPv2/Server_Shutdown.cpp new file mode 100644 index 00000000000..f0d6df0cdfd --- /dev/null +++ b/ACE/examples/C++NPv2/Server_Shutdown.cpp @@ -0,0 +1,98 @@ +/* +** $Id$ +** +** Copyright 2002 Addison Wesley. All Rights Reserved. +*/ + +#include "ace/Event_Handler.h" +#include "ace/Reactor.h" +#include "ace/Service_Object.h" +#include "ace/Thread_Manager.h" +#include "ace/OS_NS_string.h" + +// FUZZ: disable check_for_streams_include +#include "ace/streams.h" + +#if defined (ACE_WIN32) && (!defined (ACE_HAS_STANDARD_CPP_LIBRARY) || \ + (ACE_HAS_STANDARD_CPP_LIBRARY == 0) || \ + defined (ACE_USES_OLD_IOSTREAMS)) +# include <stdio.h> +#else +# include <string> +#endif + +#include "SLDEX_export.h" + + +class Quit_Handler : public ACE_Event_Handler { + friend class ace_dewarn_gplusplus; +public: + Quit_Handler (ACE_Reactor *r) : ACE_Event_Handler (r) {} + + virtual int handle_exception (ACE_HANDLE) { + reactor ()->end_reactor_event_loop (); + return -1; // Trigger call to handle_close() method. + } + + virtual int handle_close (ACE_HANDLE, ACE_Reactor_Mask) + { delete this; return 0; } + +private: + + // Private destructor ensures dynamic allocation. + virtual ~Quit_Handler () {} +}; + + +static ACE_THR_FUNC_RETURN controller (void *arg) { + ACE_Reactor *reactor = static_cast<ACE_Reactor *> (arg); + + Quit_Handler *quit_handler = 0; + ACE_NEW_RETURN (quit_handler, Quit_Handler (reactor), 0); + +#if defined (ACE_WIN32) && (!defined (ACE_HAS_STANDARD_CPP_LIBRARY) || \ + (ACE_HAS_STANDARD_CPP_LIBRARY == 0) || \ + defined (ACE_USES_OLD_IOSTREAMS)) + for (;;) { + char user_input[80]; + fgets (user_input, sizeof (user_input), stdin); + if (ACE_OS::strcmp (user_input, "quit") == 0) { + reactor->notify (quit_handler); + break; + } + } +#else + for (;;) { + std::string user_input; + std::getline (cin, user_input, '\n'); + if (user_input == "quit") { + reactor->notify (quit_handler); + break; + } + } +#endif + + return 0; +} + + +class Server_Shutdown : public ACE_Service_Object { +public: + virtual int init (int, ACE_TCHAR *[]) { + reactor_ = ACE_Reactor::instance (); + return ACE_Thread_Manager::instance ()->spawn + (controller, reactor_, THR_DETACHED); + } + + virtual int fini () { + Quit_Handler *quit_handler = 0; + ACE_NEW_RETURN (quit_handler, + Quit_Handler (reactor_), -1); + return reactor_->notify (quit_handler); + } + +private: + ACE_Reactor *reactor_; +}; + +ACE_FACTORY_DEFINE (SLDEX, Server_Shutdown) diff --git a/ACE/examples/C++NPv2/Service_Reporter.cpp b/ACE/examples/C++NPv2/Service_Reporter.cpp new file mode 100644 index 00000000000..ad9cd05d26c --- /dev/null +++ b/ACE/examples/C++NPv2/Service_Reporter.cpp @@ -0,0 +1,125 @@ +/* +** $Id$ +** +** Copyright 2002 Addison Wesley. All Rights Reserved. +*/ + +#include "ace/OS_NS_stdio.h" +#include "ace/OS_NS_string.h" +#include "ace/Get_Opt.h" +#include "ace/INET_Addr.h" +#include "ace/Log_Msg.h" +#include "ace/Service_Config.h" +#include "ace/Service_Repository.h" +#include "ace/Service_Types.h" +#include "ace/SOCK_Stream.h" +#include "Service_Reporter.h" + + +int Service_Reporter::init (int argc, ACE_TCHAR *argv[]) { + ACE_INET_Addr local_addr (Service_Reporter::DEFAULT_PORT); + + // Start at argv[0]. + ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("p:"), 0); + get_opt.long_option (ACE_TEXT ("port"), + 'p', + ACE_Get_Opt::ARG_REQUIRED); + + for (int c; (c = get_opt ()) != -1; ) + switch (c) { + case 'p': + local_addr.set_port_number + (ACE_OS::atoi (get_opt.opt_arg ())); + } + + acceptor_.open (local_addr); + return reactor ()->register_handler + (this, + ACE_Event_Handler::ACCEPT_MASK); +} + + +int Service_Reporter::handle_input (ACE_HANDLE) { + ACE_SOCK_Stream peer_stream; + acceptor_.accept (peer_stream); + + ACE_Service_Repository_Iterator iterator + (*ACE_Service_Repository::instance (), 0); + + for (const ACE_Service_Type *st; + iterator.next (st) != 0; + iterator.advance ()) { + iovec iov[3]; + iov[0].iov_base = const_cast<ACE_TCHAR *> (st->name ()); + iov[0].iov_len = + ACE_OS::strlen (st->name ()) * sizeof (ACE_TCHAR); + const ACE_TCHAR *state = st->active () ? + ACE_TEXT (" (active) ") : ACE_TEXT (" (paused) "); + iov[1].iov_base = const_cast<ACE_TCHAR *> (state); + iov[1].iov_len = + ACE_OS::strlen (state) * sizeof (ACE_TCHAR); + ACE_TCHAR *report = 0; // Ask info() to allocate buffer + int len = st->type ()->info (&report, 0); + iov[2].iov_base = static_cast<ACE_TCHAR *> (report); + iov[2].iov_len = static_cast<size_t> (len); + iov[2].iov_len *= sizeof (ACE_TCHAR); + peer_stream.sendv_n (iov, 3); + ACE::strdelete (report); + } + + peer_stream.close (); + return 0; +} + + +int Service_Reporter::info (ACE_TCHAR **bufferp, + size_t length) const { + ACE_INET_Addr local_addr; + acceptor_.get_local_addr (local_addr); + + ACE_TCHAR buf[BUFSIZ]; + ACE_OS::sprintf + (buf, ACE_TEXT ("%hu"), local_addr.get_port_number ()); + ACE_OS::strcat + (buf, ACE_TEXT ("/tcp # lists services in daemon\n")); + if (*bufferp == 0) + *bufferp = ACE::strnew (buf); + else + ACE_OS::strncpy (*bufferp, buf, length); + return ACE_OS::strlen (*bufferp); +} + + +int Service_Reporter::suspend () +{ return reactor ()->suspend_handler (this); } + +int Service_Reporter::resume () +{ return reactor ()->resume_handler (this); } + + +int Service_Reporter::fini () { + reactor ()->remove_handler + (this, + ACE_Event_Handler::ACCEPT_MASK + | ACE_Event_Handler::DONT_CALL); + return acceptor_.close (); +} + +// Define the service object make and gobble functions. +ACE_FACTORY_DEFINE (ACE_Local_Service, Service_Reporter) + +// Define the ACE_Static_Svc_Descriptor that conveys the service information +// to the ACE_Service_Config. +ACE_STATIC_SVC_DEFINE ( + Reporter_Descriptor, + ACE_TEXT ("Service_Reporter"), + ACE_SVC_OBJ_T, + &ACE_SVC_NAME (Service_Reporter), + ACE_Service_Type::DELETE_THIS + | ACE_Service_Type::DELETE_OBJ, + 0 // This object is not initially active. +) + +// Define the class that will register this service with ACE_Service_Config +// at program startup. +ACE_STATIC_SVC_REQUIRE (Reporter_Descriptor) diff --git a/ACE/examples/C++NPv2/Service_Reporter.h b/ACE/examples/C++NPv2/Service_Reporter.h new file mode 100644 index 00000000000..c6de7484767 --- /dev/null +++ b/ACE/examples/C++NPv2/Service_Reporter.h @@ -0,0 +1,38 @@ +/* +** $Id$ +** +** Copyright 2002 Addison Wesley. All Rights Reserved. +*/ + +#ifndef _SERVICE_REPORTER_H +#define _SERVICE_REPORTER_H + +#include "ace/Reactor.h" +#include "ace/Service_Object.h" +#include "ace/SOCK_Acceptor.h" + + +class Service_Reporter : public ACE_Service_Object { +public: + Service_Reporter (ACE_Reactor *r = ACE_Reactor::instance ()) + : ACE_Service_Object (r) {} + +protected: + // Hook methods inherited from <ACE_Service_Object>. + virtual int init (int argc, ACE_TCHAR *argv[]); + virtual int fini (); + virtual int info (ACE_TCHAR **, size_t) const; + virtual int suspend (); + virtual int resume (); + + // Reactor hook methods. + virtual int handle_input (ACE_HANDLE); + virtual ACE_HANDLE get_handle () const + { return acceptor_.get_handle (); } + +private: + ACE_SOCK_Acceptor acceptor_; // Acceptor instance. + enum { DEFAULT_PORT = 9411 }; +}; + +#endif /* _SERVICE_REPORTER_H */ diff --git a/ACE/examples/C++NPv2/TPCLS_export.h b/ACE/examples/C++NPv2/TPCLS_export.h new file mode 100644 index 00000000000..b550ef28a95 --- /dev/null +++ b/ACE/examples/C++NPv2/TPCLS_export.h @@ -0,0 +1,54 @@ + +// -*- C++ -*- +// $Id$ +// Definition for Win32 Export directives. +// This file is generated automatically by generate_export_file.pl TPCLS +// ------------------------------ +#ifndef TPCLS_EXPORT_H +#define TPCLS_EXPORT_H + +#include "ace/config-all.h" + +#if defined (ACE_AS_STATIC_LIBS) && !defined (TPCLS_HAS_DLL) +# define TPCLS_HAS_DLL 0 +#endif /* ACE_AS_STATIC_LIBS && ! TPCLS_HAS_DLL */ + +#if !defined (TPCLS_HAS_DLL) +# define TPCLS_HAS_DLL 1 +#endif /* ! TPCLS_HAS_DLL */ + +#if defined (TPCLS_HAS_DLL) && (TPCLS_HAS_DLL == 1) +# if defined (TPCLS_BUILD_DLL) +# define TPCLS_Export ACE_Proper_Export_Flag +# define TPCLS_SINGLETON_DECLARATION(T) ACE_EXPORT_SINGLETON_DECLARATION (T) +# define TPCLS_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) ACE_EXPORT_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) +# else /* TPCLS_BUILD_DLL */ +# define TPCLS_Export ACE_Proper_Import_Flag +# define TPCLS_SINGLETON_DECLARATION(T) ACE_IMPORT_SINGLETON_DECLARATION (T) +# define TPCLS_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) ACE_IMPORT_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) +# endif /* TPCLS_BUILD_DLL */ +#else /* TPCLS_HAS_DLL == 1 */ +# define TPCLS_Export +# define TPCLS_SINGLETON_DECLARATION(T) +# define TPCLS_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) +#endif /* TPCLS_HAS_DLL == 1 */ + +// Set TPCLS_NTRACE = 0 to turn on library specific tracing even if +// tracing is turned off for ACE. +#if !defined (TPCLS_NTRACE) +# if (ACE_NTRACE == 1) +# define TPCLS_NTRACE 1 +# else /* (ACE_NTRACE == 1) */ +# define TPCLS_NTRACE 0 +# endif /* (ACE_NTRACE == 1) */ +#endif /* !TPCLS_NTRACE */ + +#if (TPCLS_NTRACE == 1) +# define TPCLS_TRACE(X) +#else /* (TPCLS_NTRACE == 1) */ +# define TPCLS_TRACE(X) ACE_TRACE_IMPL(X) +#endif /* (TPCLS_NTRACE == 1) */ + +#endif /* TPCLS_EXPORT_H */ + +// End of auto generated file. diff --git a/ACE/examples/C++NPv2/TPC_Logging_Server.cpp b/ACE/examples/C++NPv2/TPC_Logging_Server.cpp new file mode 100644 index 00000000000..b6ce76e1d40 --- /dev/null +++ b/ACE/examples/C++NPv2/TPC_Logging_Server.cpp @@ -0,0 +1,106 @@ +/* +** $Id$ +** +** This is the Thread-per-connection logging server example from Chapter 7. +** +** Copyright 2002 Addison Wesley. All Rights Reserved. +*/ + +#include "ace/OS_NS_string.h" +#include "ace/FILE_Addr.h" +#include "ace/FILE_Connector.h" +#include "ace/os_include/os_netdb.h" +#include "Reactor_Logging_Server_Adapter.h" +#include "TPC_Logging_Server.h" +#include "TPCLS_export.h" + +int TPC_Logging_Handler::open (void *) { + static const ACE_TCHAR LOGFILE_SUFFIX[] = ACE_TEXT (".log"); + ACE_TCHAR filename[MAXHOSTNAMELEN + sizeof (LOGFILE_SUFFIX)]; + ACE_INET_Addr logging_peer_addr; + + peer ().get_remote_addr (logging_peer_addr); + logging_peer_addr.get_host_name (filename, MAXHOSTNAMELEN); + ACE_OS::strcat (filename, LOGFILE_SUFFIX); + + ACE_FILE_Connector connector; + connector.connect (log_file_, + ACE_FILE_Addr (filename), + 0, // No timeout. + ACE_Addr::sap_any, // Ignored. + 0, // Don't try to reuse the addr. + O_RDWR | O_CREAT | O_APPEND, + ACE_DEFAULT_FILE_PERMS); + + logging_handler_.peer ().set_handle (peer ().get_handle ()); + + return activate (THR_NEW_LWP | THR_DETACHED); +} + + +#if !defined (TPC_CERTIFICATE_FILENAME) +# define TPC_CERTIFICATE_FILENAME "tpc-cert.pem" +#endif /* !TPC_CERTIFICATE_FILENAME */ +#if !defined (TPC_KEY_FILENAME) +# define TPC_KEY_FILENAME "tpc-key.pem" +#endif /* !TPC_KEY_FILENAME */ + +int TPC_Logging_Acceptor::open + (const ACE_SOCK_Acceptor::PEER_ADDR &local_addr, + ACE_Reactor *reactor, + int flags, int use_select, int reuse_addr) { + if (PARENT::open (local_addr, reactor, flags, + use_select, reuse_addr) != 0) + return -1; + OpenSSL_add_ssl_algorithms (); + ssl_ctx_ = SSL_CTX_new (SSLv3_server_method ()); + if (ssl_ctx_ == 0) return -1; + + if (SSL_CTX_use_certificate_file (ssl_ctx_, + TPC_CERTIFICATE_FILENAME, + SSL_FILETYPE_PEM) <= 0 + || SSL_CTX_use_PrivateKey_file (ssl_ctx_, + TPC_KEY_FILENAME, + SSL_FILETYPE_PEM) <= 0 + || !SSL_CTX_check_private_key (ssl_ctx_)) + return -1; + ssl_ = SSL_new (ssl_ctx_); + return ssl_ == 0 ? -1 : 0; +} + + +int TPC_Logging_Acceptor::handle_close (ACE_HANDLE h, + ACE_Reactor_Mask mask) { + PARENT::handle_close (h, mask); + delete this; + return 0; +} + + +int TPC_Logging_Acceptor::accept_svc_handler + (TPC_Logging_Handler *sh) { + if (PARENT::accept_svc_handler (sh) == -1) return -1; + SSL_clear (ssl_); // Reset for new SSL connection. +#if defined (ACE_WIN32) + // ACE_WIN32 is the only platform where ACE_HANDLE is not an int. + // See ace/config-lite.h for the typedefs. + SSL_set_fd (ssl_, reinterpret_cast<int> (sh->get_handle ())); +#else + SSL_set_fd (ssl_, sh->get_handle ()); +#endif /* ACE_WIN32 */ + + SSL_set_verify + (ssl_, + SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, + 0); + if (SSL_accept (ssl_) == -1 + || SSL_shutdown (ssl_) == -1) return -1; + return 0; +} + + +typedef Reactor_Logging_Server_Adapter<TPC_Logging_Acceptor> + TPC_Logging_Server; + +ACE_FACTORY_DEFINE (TPCLS, TPC_Logging_Server) + diff --git a/ACE/examples/C++NPv2/TPC_Logging_Server.h b/ACE/examples/C++NPv2/TPC_Logging_Server.h new file mode 100644 index 00000000000..2617c3b95ec --- /dev/null +++ b/ACE/examples/C++NPv2/TPC_Logging_Server.h @@ -0,0 +1,87 @@ +/* +** $Id$ +** +** This is the Thread-per-connection logging server example from Chapter 7. +** +** Copyright 2002 Addison Wesley. All Rights Reserved. +*/ + +#ifndef _TPC_LOGGING_SERVER_H +#define _TPC_LOGGING_SERVER_H + +#include "ace/Acceptor.h" +#include "ace/INET_Addr.h" +#include "ace/Reactor.h" +#include "ace/Svc_Handler.h" +#include "ace/FILE_IO.h" +#include "Logging_Handler.h" + +#include "ace/SOCK_Acceptor.h" +#include <openssl/ssl.h> + +class TPC_Logging_Handler + : public ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH> { +protected: + ACE_FILE_IO log_file_; // File of log records. + + // Connection to peer service handler. + Logging_Handler logging_handler_; + +public: + TPC_Logging_Handler () : logging_handler_ (log_file_) {} + + virtual int open (void *); + + virtual int svc (void) { + for (;;) + switch (logging_handler_.log_record ()) { + case -1: return -1; // Error. + case 0: return 0; // Client closed connection. + default: continue; // Default case. + } + /* NOTREACHED */ + return 0; + } +}; + + +class TPC_Logging_Acceptor + : public ACE_Acceptor<TPC_Logging_Handler, ACE_SOCK_ACCEPTOR> { +protected: + // The SSL ``context'' data structure. + SSL_CTX *ssl_ctx_; + + // The SSL data structure corresponding to authenticated + // SSL connections. + SSL *ssl_; + +public: + typedef ACE_Acceptor<TPC_Logging_Handler, ACE_SOCK_ACCEPTOR> + PARENT; + typedef ACE_SOCK_Acceptor::PEER_ADDR PEER_ADDR; + + // Constructor. + TPC_Logging_Acceptor (ACE_Reactor *r) + : PARENT (r), ssl_ctx_ (0), ssl_ (0) {} + + // Destructor frees the SSL resources. + virtual ~TPC_Logging_Acceptor (void) { + SSL_free (this->ssl_); + SSL_CTX_free (this->ssl_ctx_); + } + + // Initialize the acceptor instance. + virtual int open + (const ACE_SOCK_Acceptor::PEER_ADDR &local_addr, + ACE_Reactor *reactor = ACE_Reactor::instance (), + int flags = 0, int use_select = 1, int reuse_addr = 1); + + virtual int handle_close + (ACE_HANDLE = ACE_INVALID_HANDLE, + ACE_Reactor_Mask = ACE_Event_Handler::ALL_EVENTS_MASK); + + // Connection establishment and authentication hook method. + virtual int accept_svc_handler (TPC_Logging_Handler *sh); +}; + +#endif /* _TPC_LOGGING_SERVER_H */ diff --git a/ACE/examples/C++NPv2/TPLS_export.h b/ACE/examples/C++NPv2/TPLS_export.h new file mode 100644 index 00000000000..71448e71a50 --- /dev/null +++ b/ACE/examples/C++NPv2/TPLS_export.h @@ -0,0 +1,38 @@ + +// -*- C++ -*- +// $Id$ +// Definition for Win32 Export directives. +// This file is generated automatically by generate_export_file.pl TPLS +// ------------------------------ +#ifndef TPLS_EXPORT_H +#define TPLS_EXPORT_H + +#include "ace/config-all.h" + +#if defined (ACE_AS_STATIC_LIBS) && !defined (TPLS_HAS_DLL) +# define TPLS_HAS_DLL 0 +#endif /* ACE_AS_STATIC_LIBS && ! TPLS_HAS_DLL */ + +#if !defined (TPLS_HAS_DLL) +# define TPLS_HAS_DLL 1 +#endif /* ! TPLS_HAS_DLL */ + +#if defined (TPLS_HAS_DLL) && (TPLS_HAS_DLL == 1) +# if defined (TPLS_BUILD_DLL) +# define TPLS_Export ACE_Proper_Export_Flag +# define TPLS_SINGLETON_DECLARATION(T) ACE_EXPORT_SINGLETON_DECLARATION (T) +# define TPLS_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) ACE_EXPORT_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) +# else /* TPLS_BUILD_DLL */ +# define TPLS_Export ACE_Proper_Import_Flag +# define TPLS_SINGLETON_DECLARATION(T) ACE_IMPORT_SINGLETON_DECLARATION (T) +# define TPLS_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) ACE_IMPORT_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) +# endif /* TPLS_BUILD_DLL */ +#else /* TPLS_HAS_DLL == 1 */ +# define TPLS_Export +# define TPLS_SINGLETON_DECLARATION(T) +# define TPLS_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) +#endif /* TPLS_HAS_DLL == 1 */ + +#endif /* TPLS_EXPORT_H */ + +// End of auto generated file. diff --git a/ACE/examples/C++NPv2/TP_Logging_Server.cpp b/ACE/examples/C++NPv2/TP_Logging_Server.cpp new file mode 100644 index 00000000000..7342cf4c757 --- /dev/null +++ b/ACE/examples/C++NPv2/TP_Logging_Server.cpp @@ -0,0 +1,70 @@ +/* +** $Id$ +** +** Copyright 2002 Addison Wesley. All Rights Reserved. +*/ + +#include "ace/OS_Memory.h" +#include "ace/Guard_T.h" +#include "ace/Message_Block.h" +#include "TP_Logging_Server.h" + +int TP_Logging_Handler::handle_input (ACE_HANDLE) { + ACE_Message_Block *mblk = 0; + if (logging_handler_.recv_log_record (mblk) != -1) { + ACE_Message_Block *log_blk = 0; + ACE_NEW_RETURN + (log_blk, ACE_Message_Block + (reinterpret_cast<char *> (this)), -1); + log_blk->cont (mblk); + ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, guard, lock_, -1); + if (TP_LOGGING_TASK::instance ()->put (log_blk) == -1) + { log_blk->release (); return -1; } + ++queued_count_; + return 0; + } else return -1; +} + + +int +TP_Logging_Handler::handle_close (ACE_HANDLE handle, + ACE_Reactor_Mask) { + int close_now = 0; + if (handle != ACE_INVALID_HANDLE) { + ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, guard, lock_, -1); + if (queued_count_ == 0) + close_now = 1; + else + deferred_close_ = 1; + } else { + ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, guard, lock_, -1); + queued_count_--; + if (queued_count_ == 0) close_now = deferred_close_; + } + + if (close_now) + return Logging_Event_Handler::handle_close (); + return 0; +} + + +int TP_Logging_Task::svc () { + for (ACE_Message_Block *log_blk; getq (log_blk) != -1; ) { + TP_Logging_Handler *tp_handler = reinterpret_cast<TP_Logging_Handler *> (log_blk->rd_ptr ()); + Logging_Handler logging_handler (tp_handler->log_file ()); + logging_handler.write_log_record (log_blk->cont ()); + + log_blk->release (); + tp_handler->handle_close (ACE_INVALID_HANDLE, 0); + } + return 0; +} + +ACE_FACTORY_DEFINE (TPLS, TP_Logging_Server) + +#if defined (ACE_HAS_EXPLICIT_STATIC_TEMPLATE_MEMBER_INSTANTIATION) +template ACE_Singleton<TP_Logging_Task, ACE_Null_Mutex> * + ACE_Singleton<TP_Logging_Task, ACE_Null_Mutex>::singleton_; +template ACE_Unmanaged_Singleton<TP_Logging_Task, ACE_Null_Mutex> * + ACE_Unmanaged_Singleton<TP_Logging_Task, ACE_Null_Mutex>::singleton_; +#endif /* ACE_HAS_EXPLICIT_STATIC_TEMPLATE_MEMBER_INSTANTIATION */ diff --git a/ACE/examples/C++NPv2/TP_Logging_Server.h b/ACE/examples/C++NPv2/TP_Logging_Server.h new file mode 100644 index 00000000000..9c4869cdcee --- /dev/null +++ b/ACE/examples/C++NPv2/TP_Logging_Server.h @@ -0,0 +1,131 @@ +/* +** $Id$ +** +** Copyright 2002 Addison Wesley. All Rights Reserved. +*/ + +#ifndef _TP_LOGGING_SERVER_H +#define _TP_LOGGING_SERVER_H + +#include "ace/Auto_Ptr.h" +#include "ace/Singleton.h" +#include "ace/Synch.h" +#include "ace/Task.h" +#include "Logging_Acceptor.h" +#include "Logging_Event_Handler.h" +#include "Reactor_Logging_Server_T.h" +#include "TPLS_export.h" + +class TP_Logging_Task : public ACE_Task<ACE_SYNCH> { + // Instantiated with an MT synchronization trait. +public: + enum { MAX_THREADS = 4 }; + + virtual int open (void * = 0) + { return activate (THR_NEW_LWP, MAX_THREADS); } + + virtual int put (ACE_Message_Block *mblk, + ACE_Time_Value *timeout = 0) + { return putq (mblk, timeout); } + + virtual int svc (void); +}; + +typedef ACE_Unmanaged_Singleton<TP_Logging_Task, ACE_Null_Mutex> + TP_LOGGING_TASK; + +/*******************************************************/ + +class TP_Logging_Acceptor; + +class TP_Logging_Handler : public Logging_Event_Handler { + friend class TP_Logging_Acceptor; +protected: + virtual ~TP_Logging_Handler () {} // No-op destructor. + + // Number of pointers to this class instance that currently + // reside in the <TP_LOGGING_TASK> singleton's message queue. + int queued_count_; + + // Indicates whether <Logging_Event_Handler::handle_close()> + // must be called to cleanup and delete this object. + int deferred_close_; + + // Serialize access to <queued_count_> and <deferred_close_>. + ACE_SYNCH_MUTEX lock_; + +public: + TP_Logging_Handler (ACE_Reactor *reactor) + : Logging_Event_Handler (reactor), + queued_count_ (0), + deferred_close_ (0) {} + + // Called when input events occur, e.g., connection or data. + virtual int handle_input (ACE_HANDLE); + + // Called when this object is destroyed, e.g., when it's + // removed from a reactor. + virtual int handle_close (ACE_HANDLE, ACE_Reactor_Mask); +}; + +/*******************************************************/ + +class TP_Logging_Acceptor : public Logging_Acceptor { +public: + TP_Logging_Acceptor (ACE_Reactor *r = ACE_Reactor::instance ()) + : Logging_Acceptor (r) {} + + virtual int handle_input (ACE_HANDLE) { + TP_Logging_Handler *peer_handler = 0; + ACE_NEW_RETURN (peer_handler, + TP_Logging_Handler (reactor ()), -1); + if (acceptor_.accept (peer_handler->peer ()) == -1) { + delete peer_handler; + return -1; + } else if (peer_handler->open () == -1) + peer_handler->handle_close (ACE_INVALID_HANDLE, 0); + return 0; + } +}; + +/*******************************************************/ + +class TP_Logging_Server : public ACE_Service_Object { +protected: + // Contains the reactor, acceptor, and handlers. + typedef Reactor_Logging_Server<TP_Logging_Acceptor> + LOGGING_DISPATCHER; + LOGGING_DISPATCHER *logging_dispatcher_; + +public: + TP_Logging_Server (): logging_dispatcher_ (0) {} + + virtual int init (int argc, ACE_TCHAR *argv[]) { + int i; + char **array = 0; + ACE_NEW_RETURN (array, char*[argc], -1); + ACE_Auto_Array_Ptr<char *> char_argv (array); + + for (i = 0; i < argc; ++i) + char_argv[i] = ACE::strnew (ACE_TEXT_ALWAYS_CHAR (argv[i])); + ACE_NEW_NORETURN + (logging_dispatcher_, + TP_Logging_Server::LOGGING_DISPATCHER + (i, char_argv.get (), ACE_Reactor::instance ())); + for (i = 0; i < argc; ++i) ACE::strdelete (char_argv[i]); + if (logging_dispatcher_ == 0) return -1; + else return TP_LOGGING_TASK::instance ()->open (); + } + + virtual int fini () { + TP_LOGGING_TASK::instance ()->flush (); + TP_LOGGING_TASK::instance ()->wait (); + TP_LOGGING_TASK::close (); + delete logging_dispatcher_; + return 0; + } +}; + +ACE_FACTORY_DECLARE (TPLS, TP_Logging_Handler) + +#endif /* _TP_LOGGING_SERVER_H */ diff --git a/ACE/examples/C++NPv2/TP_Reactor_Logging_Server.cpp b/ACE/examples/C++NPv2/TP_Reactor_Logging_Server.cpp new file mode 100644 index 00000000000..0d3216fe4e5 --- /dev/null +++ b/ACE/examples/C++NPv2/TP_Reactor_Logging_Server.cpp @@ -0,0 +1,117 @@ +/* +** $Id$ +** +** Copyright 2002 Addison Wesley. All Rights Reserved. +*/ + +// FUZZ: disable check_for_streams_include +#include "ace/streams.h" + +#include "ace/Auto_Ptr.h" +#include "ace/Reactor.h" +#include "ace/TP_Reactor.h" +#include "ace/Thread_Manager.h" + +#if defined (ACE_WIN32) && (!defined (ACE_HAS_STANDARD_CPP_LIBRARY) || \ + (ACE_HAS_STANDARD_CPP_LIBRARY == 0) || \ + defined (ACE_USES_OLD_IOSTREAMS)) +# include <stdio.h> +#else +# include <string> +#endif + +#include "Reactor_Logging_Server_T.h" +#include "Logging_Acceptor_Ex.h" + +typedef Reactor_Logging_Server<Logging_Acceptor_Ex> + Server_Logging_Daemon; + + +class Quit_Handler : public ACE_Event_Handler { + friend class ace_dewarn_gplusplus; +public: + Quit_Handler (ACE_Reactor *r) : ACE_Event_Handler (r) {} + + virtual int handle_exception (ACE_HANDLE) { + reactor ()->end_reactor_event_loop (); + return -1; // Trigger call to handle_close() method. + } + + virtual int handle_close (ACE_HANDLE, ACE_Reactor_Mask) + { delete this; return 0; } + +private: + + // Private destructor ensures dynamic allocation. + virtual ~Quit_Handler () {} +}; + + +static ACE_THR_FUNC_RETURN event_loop (void *arg) { + ACE_Reactor *reactor = static_cast<ACE_Reactor *> (arg); + + reactor->owner (ACE_OS::thr_self ()); + reactor->run_reactor_event_loop (); + return 0; +} + + +static ACE_THR_FUNC_RETURN controller (void *arg) { + ACE_Reactor *reactor = static_cast<ACE_Reactor *> (arg); + + Quit_Handler *quit_handler = 0; + ACE_NEW_RETURN (quit_handler, Quit_Handler (reactor), 0); + +#if defined (ACE_WIN32) && (!defined (ACE_HAS_STANDARD_CPP_LIBRARY) || \ + (ACE_HAS_STANDARD_CPP_LIBRARY == 0) || \ + defined (ACE_USES_OLD_IOSTREAMS)) + for (;;) { + char user_input[80]; + fgets (user_input, sizeof (user_input), stdin); + if (ACE_OS::strcmp (user_input, "quit") == 0) { + reactor->notify (quit_handler); + break; + } + } +#else + for (;;) { +#if defined (ACE_USES_STD_NAMESPACE_FOR_STDCPP_LIB) && (ACE_USES_STD_NAMESPACE_FOR_STDCPP_LIB == 0) + string user_input; + getline (cin, user_input, '\n'); +#else + std::string user_input; + std::getline (cin, user_input, '\n'); +#endif + if (user_input == "quit") { + reactor->notify (quit_handler); + break; + } + } +#endif + + return 0; +} + + +int main (int argc, char *argv[]) +{ + const size_t N_THREADS = 4; + ACE_TP_Reactor tp_reactor; + ACE_Reactor reactor (&tp_reactor); + auto_ptr<ACE_Reactor> delete_instance + (ACE_Reactor::instance (&reactor)); + + Server_Logging_Daemon *server; + // Ignore argv[0]... + --argc; ++argv; + ACE_NEW_RETURN (server, + Server_Logging_Daemon (argc, argv, + ACE_Reactor::instance ()), + 1); + ACE_Thread_Manager::instance ()->spawn_n + (N_THREADS, event_loop, ACE_Reactor::instance ()); + ACE_Thread_Manager::instance ()->spawn + (controller, ACE_Reactor::instance ()); + return ACE_Thread_Manager::instance ()->wait (); +} + diff --git a/ACE/examples/C++NPv2/WFMO_Reactor_Logging_Server.cpp b/ACE/examples/C++NPv2/WFMO_Reactor_Logging_Server.cpp new file mode 100644 index 00000000000..2174cd20412 --- /dev/null +++ b/ACE/examples/C++NPv2/WFMO_Reactor_Logging_Server.cpp @@ -0,0 +1,145 @@ +/* +** $Id$ +** +** Copyright 2002 Addison Wesley. All Rights Reserved. +*/ + +#include "ace/config-all.h" + +#if defined (ACE_WIN32) + +#include "ace/Reactor.h" +#include "ace/WFMO_Reactor.h" +#include "ace/Thread_Manager.h" +#include "ace/OS_NS_string.h" + +#include "Reactor_Logging_Server_T.h" +#include "Logging_Acceptor_Ex.h" +#include "Logging_Event_Handler_Ex.h" + +class Quit_Handler : public ACE_Event_Handler { +private: + ACE_Manual_Event quit_seen_; + +public: + Quit_Handler (ACE_Reactor *r) : ACE_Event_Handler (r) { + SetConsoleMode (ACE_STDIN, ENABLE_LINE_INPUT + | ENABLE_ECHO_INPUT + | ENABLE_PROCESSED_INPUT); + if (reactor ()->register_handler + (this, quit_seen_.handle ()) == -1 + || ACE_Event_Handler::register_stdin_handler + (this, r, ACE_Thread_Manager::instance ()) == -1) + r->end_reactor_event_loop (); + } + + ~Quit_Handler () { + ACE_Event_Handler::remove_stdin_handler + (reactor (), ACE_Thread_Manager::instance ()); + reactor ()->remove_handler (quit_seen_.handle (), + ACE_Event_Handler::DONT_CALL); + } + + virtual int handle_input (ACE_HANDLE h) { + CHAR user_input[BUFSIZ]; + DWORD count; + if (!ReadFile (h, user_input, BUFSIZ, &count, 0)) + return -1; + + user_input[count] = '\0'; + if (ACE_OS::strncmp (user_input, "quit", 4) == 0) + return -1; + return 0; + } + + virtual int handle_close (ACE_HANDLE, ACE_Reactor_Mask) { + quit_seen_.signal (); + return 0; + } + + virtual int handle_signal (int, siginfo_t *, ucontext_t *) { + reactor ()->end_reactor_event_loop (); + return 0; + } +}; + + +class Logging_Event_Handler_WFMO : public Logging_Event_Handler_Ex +{ +public: + Logging_Event_Handler_WFMO (ACE_Reactor *r) + : Logging_Event_Handler_Ex (r) {} + +protected: + int handle_input (ACE_HANDLE) { + ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, monitor, lock_, -1); + return logging_handler_.log_record (); + } + + ACE_Thread_Mutex lock_; // Serialize threads in thread pool. +}; + + +class Logging_Acceptor_WFMO : public Logging_Acceptor_Ex +{ +public: + // Simple constructor to pass ACE_Reactor to base class. + Logging_Acceptor_WFMO (ACE_Reactor *r = ACE_Reactor::instance ()) + : Logging_Acceptor_Ex (r) {}; + +protected: + virtual int handle_input (ACE_HANDLE) { + Logging_Event_Handler_WFMO *peer_handler = 0; + ACE_NEW_RETURN (peer_handler, + Logging_Event_Handler_WFMO (reactor ()), + -1); + + if (acceptor_.accept (peer_handler->peer ()) == -1) { + delete peer_handler; + return -1; + } else if (peer_handler->open () == -1) { + peer_handler->handle_close (); + return -1; + } + return 0; + } +}; + + +static ACE_THR_FUNC_RETURN event_loop (void *arg) { + ACE_Reactor *reactor = static_cast<ACE_Reactor *> (arg); + + reactor->owner (ACE_OS::thr_self ()); + reactor->run_reactor_event_loop (); + return 0; +} + + +typedef Reactor_Logging_Server<Logging_Acceptor_WFMO> + Server_Logging_Daemon; + + +int main (int argc, char *argv[]) +{ + const size_t N_THREADS = 4; + ACE_WFMO_Reactor wfmo_reactor; + ACE_Reactor reactor (&wfmo_reactor); + + Server_Logging_Daemon *server; + // Ignore argv[0]... + --argc; ++argv; + ACE_NEW_RETURN (server, + Server_Logging_Daemon (argc, argv, &reactor), + 1); + Quit_Handler quit_handler (&reactor); + ACE_Thread_Manager::instance ()->spawn_n + (N_THREADS, event_loop, &reactor); + return ACE_Thread_Manager::instance ()->wait (); +} + +#else /* !ACE_WIN32 */ +int main (int, char *[]) +{ + return 0; +} +#endif /* ACE_WIN32 */ diff --git a/ACE/examples/C++NPv2/display_logfile.cpp b/ACE/examples/C++NPv2/display_logfile.cpp new file mode 100644 index 00000000000..19f251e9463 --- /dev/null +++ b/ACE/examples/C++NPv2/display_logfile.cpp @@ -0,0 +1,361 @@ +/* +** $Id$ +** +** Copyright 2002 Addison Wesley. All Rights Reserved. +*/ + +#include "ace/ACE.h" +#include "ace/CDR_Stream.h" +#include "ace/FILE_Addr.h" +#include "ace/FILE_Connector.h" +#include "ace/FILE_IO.h" +#include "ace/Message_Block.h" +#include "ace/Module.h" +#include "ace/SString.h" +#include "ace/Stream.h" +#include "ace/Task.h" +#include "ace/Thread_Manager.h" +#include "ace/Lock_Adapter_T.h" +#include "ace/OS_NS_string.h" +#include "ace/OS_NS_time.h" + +template <class TASK> +class Logrec_Module : public ACE_Module<ACE_SYNCH> +{ +public: + Logrec_Module (const ACE_TCHAR *name) + { + this->open (name, + &task_, // Initialize writer-side task. + 0, // Ignore reader-side task. + 0, + ACE_Module<ACE_SYNCH>::M_DELETE_READER); + } +private: + TASK task_; +}; +#define LOGREC_MODULE(NAME) \ + typedef Logrec_Module<NAME> NAME##_Module + +class Logrec_Reader : public ACE_Task<ACE_SYNCH> +{ +private: + ACE_TString filename_; // Name of logfile. + ACE_FILE_IO logfile_; // File containing log records. + +public: + enum {MB_CLIENT = ACE_Message_Block::MB_USER, + MB_TYPE, MB_PID, MB_TIME, MB_TEXT}; + + Logrec_Reader (const ACE_TString &file): filename_ (file) {} + + virtual int open (void *) { + ACE_FILE_Addr name (filename_.c_str ()); + ACE_FILE_Connector connector; + if (connector.connect (logfile_, name) == -1) + return -1; + return activate (); + } + + virtual int svc () { + const size_t FileReadSize = 8 * 1024; + ACE_Message_Block mblk (FileReadSize); + + for (;; mblk.crunch ()) { + // Read as much as will fit in the message block. + ssize_t bytes_read = logfile_.recv (mblk.wr_ptr (), + mblk.space ()); + if (bytes_read <= 0) + break; + mblk.wr_ptr (static_cast<size_t> (bytes_read)); + + // We have a bunch of data from the log file. The data is + // arranged like so: + // hostname\0 + // CDR-encoded log record + // So, first we scan for the end of the host name, then + // initialize another ACE_Message_Block aligned for CDR + // demarshaling and copy the remainder of the block into it. We + // can't use duplicate() because we need to be sure the data + // pointer is aligned properly for CDR demarshaling. If at any + // point, there's not enough data left in the message block to + // extract what's needed, crunch the block to move all remaining + // data to the beginning and read more from the file. + for (;;) { + size_t name_len = ACE_OS::strnlen + (mblk.rd_ptr (), mblk.length ()); + if (name_len == mblk.length ()) break; + + char *name_p = mblk.rd_ptr (); + ACE_Message_Block *rec, *head, *temp; + ACE_NEW_RETURN + (head, ACE_Message_Block (name_len, MB_CLIENT), 0); + head->copy (name_p, name_len); + mblk.rd_ptr (name_len + 1); // Skip nul also + + size_t need = mblk.length () + ACE_CDR::MAX_ALIGNMENT; + ACE_NEW_RETURN (rec, ACE_Message_Block (need), 0); + ACE_CDR::mb_align (rec); + rec->copy (mblk.rd_ptr (), mblk.length ()); + + // Now rec contains the remaining data we've read so far from + // the file. Create an ACE_InputCDR to start demarshaling the + // log record, header first to find the length, then the data. + // Since the ACE_InputCDR constructor increases the reference count + // on rec, we release it upon return to prevent leaks. + // The cdr 'read' methods return 0 on failure, 1 on success. + ACE_InputCDR cdr (rec); rec->release (); + ACE_CDR::Boolean byte_order; + if (!cdr.read_boolean (byte_order)) { + head->release (); rec->release (); break; + } + cdr.reset_byte_order (byte_order); + + // Now read the length of the record. From there, we'll know + // if rec contains the complete record or not. + ACE_CDR::ULong length; + if (!cdr.read_ulong (length)) { + head->release (); mblk.rd_ptr (name_p); break; + } + if (length > cdr.length ()) { + head->release (); mblk.rd_ptr (name_p); break; + } + + // The complete record is in rec... grab all the fields into + // separate, chained message blocks. + ACE_NEW_RETURN (temp, + ACE_Message_Block (length, MB_TEXT), + 0); + ACE_NEW_RETURN + (temp, + ACE_Message_Block (2 * sizeof (ACE_CDR::Long), + MB_TIME, temp), + 0); + ACE_NEW_RETURN + (temp, + ACE_Message_Block (sizeof (ACE_CDR::Long), + MB_PID, temp), + 0); + ACE_NEW_RETURN + (temp, + ACE_Message_Block (sizeof (ACE_CDR::Long), + MB_TYPE, temp), + 0); + head->cont (temp); + + // Extract the type + ACE_CDR::Long *lp; + lp = reinterpret_cast<ACE_CDR::Long*> (temp->wr_ptr ()); + cdr >> *lp; + temp->wr_ptr (sizeof (ACE_CDR::Long)); + temp = temp->cont (); + + // Extract the pid + lp = reinterpret_cast<ACE_CDR::Long*> (temp->wr_ptr ()); + cdr >> *lp; + temp->wr_ptr (sizeof (ACE_CDR::Long)); + temp = temp->cont (); + + // Extract the timestamp (2 Longs) + lp = reinterpret_cast<ACE_CDR::Long*> (temp->wr_ptr ()); + cdr >> *lp; ++lp; cdr >> *lp; + temp->wr_ptr (2 * sizeof (ACE_CDR::Long)); + temp = temp->cont (); + + // Demarshal the length of the message text, then demarshal + // the text into the block. + ACE_CDR::ULong text_len; + cdr >> text_len; + cdr.read_char_array (temp->wr_ptr (), text_len); + temp->wr_ptr (text_len); + + // Forward the whole lot to the next module. + if (put_next (head) == -1) break; + + // Move the file-content block's read pointer up past whatever + // was just processed. Although the mblk's rd_ptr has not been + // moved, cdr's has. Therefore, use its length() to determine + // how much is left. + mblk.rd_ptr (mblk.length () - cdr.length ()); + } + } + + // Now that the file is done, send a block down the stream to tell + // the other modules to stop. + ACE_Message_Block *stop; + ACE_NEW_RETURN + (stop, ACE_Message_Block (0, ACE_Message_Block::MB_STOP), + 0); + put_next (stop); + return 0; + } +}; + +class Logrec_Reader_Module : public ACE_Module<ACE_SYNCH> +{ +public: + Logrec_Reader_Module (const ACE_TString &filename) + : task_ (filename) + { + this->open (ACE_TEXT ("Logrec Reader"), + &task_, // Initialize writer-side. + 0, // Ignore reader-side. + 0, + ACE_Module<ACE_SYNCH>::M_DELETE_READER); + } +private: + Logrec_Reader task_; +}; + +class Logrec_Writer : public ACE_Task<ACE_SYNCH> +{ +public: + // Initialization hook method. + virtual int open (void *) { return activate (); } + + virtual int put (ACE_Message_Block *mblk, ACE_Time_Value *to) + { return putq (mblk, to); } + + virtual int svc () { + int stop = 0; + for (ACE_Message_Block *mb; !stop && getq (mb) != -1; ) { + if (mb->msg_type () == ACE_Message_Block::MB_STOP) + stop = 1; + else + ACE::write_n (ACE_STDOUT, mb); + put_next (mb); + } + return 0; + } +}; + +LOGREC_MODULE (Logrec_Writer); + +class Logrec_Formatter : public ACE_Task<ACE_SYNCH> +{ +public: + typedef void (*FORMATTER[5])(ACE_Message_Block *); +private: + static FORMATTER format_; // Array of format static methods. + +public: + virtual int put (ACE_Message_Block *mblk, ACE_Time_Value *) { + if (mblk->msg_type () == Logrec_Reader::MB_CLIENT) + for (ACE_Message_Block *temp = mblk; + temp != 0; + temp = temp->cont ()) { + int mb_type = + temp->msg_type () - ACE_Message_Block::MB_USER; + (*format_[mb_type])(temp); + } + return put_next (mblk); + } + + static void format_client (ACE_Message_Block *) { + return; + } + + static void format_type (ACE_Message_Block *mblk) { + ACE_CDR::Long type = * (ACE_CDR::Long *)mblk->rd_ptr (); + mblk->size (11); // Max size in ASCII of 32-bit word. + mblk->reset (); + mblk->wr_ptr ((size_t) sprintf (mblk->wr_ptr (), "%d", type)); + } + + static void format_pid (ACE_Message_Block *mblk) { + ACE_CDR::Long pid = * (ACE_CDR::Long *)mblk->rd_ptr (); + mblk->size (11); // Max size in ASCII of 32-bit word. + mblk->reset (); + mblk->wr_ptr ((size_t) sprintf (mblk->wr_ptr (), "%d", pid)); + } + + static void format_time (ACE_Message_Block *mblk) { + ACE_CDR::Long secs = * (ACE_CDR::Long *)mblk->rd_ptr (); + mblk->rd_ptr (sizeof (ACE_CDR::Long)); + ACE_CDR::Long usecs = * (ACE_CDR::Long *)mblk->rd_ptr (); + ACE_TCHAR timestamp_t[26]; + char timestamp[26]; // Max size of ctime_r() string. + time_t time_secs (secs); + ACE_OS::ctime_r (&time_secs, timestamp_t, sizeof timestamp_t); + ACE_OS::strcpy (timestamp, ACE_TEXT_ALWAYS_CHAR (timestamp_t)); + mblk->size (26); // Max size of ctime_r() string. + mblk->reset (); + timestamp[19] = '\0'; // NUL-terminate after the time. + timestamp[24] = '\0'; // NUL-terminate after the date. + size_t fmt_len (sprintf (mblk->wr_ptr (), + "%s.%03d %s", + timestamp + 4, + usecs / 1000, + timestamp + 20)); + mblk->wr_ptr (fmt_len); + } + + static void format_data (ACE_Message_Block *) { + return; + } +}; + +Logrec_Formatter::FORMATTER Logrec_Formatter::format_ = { + format_client, format_type, format_pid, format_time, format_data +}; + +LOGREC_MODULE (Logrec_Formatter); + +class Logrec_Separator : public ACE_Task<ACE_SYNCH> +{ +private: + ACE_Lock_Adapter<ACE_SYNCH_MUTEX> lock_strategy_; + +public: + virtual int put (ACE_Message_Block *mblk, + ACE_Time_Value *) { + if (mblk->msg_type () != ACE_Message_Block::MB_STOP) { + ACE_Message_Block *separator; + ACE_NEW_RETURN + (separator, + ACE_Message_Block (ACE_OS::strlen ("|") + 1, + ACE_Message_Block::MB_DATA, + 0, 0, 0, &lock_strategy_), + -1); + separator->copy ("|"); + + ACE_Message_Block *dup = 0; + for (ACE_Message_Block *temp = mblk; temp != 0; ) { + dup = separator->duplicate (); + dup->cont (temp->cont ()); + temp->cont (dup); + temp = dup->cont (); + } + ACE_Message_Block *nl; + ACE_NEW_RETURN (nl, ACE_Message_Block (2), 0); + nl->copy ("\n"); + dup->cont (nl); + separator->release (); + } + return put_next (mblk); + } +}; + +LOGREC_MODULE (Logrec_Separator); + +int ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + if (argc != 2) + ACE_ERROR_RETURN ((LM_ERROR, + "usage: %s logfile\n", argv[0]), + 1); + ACE_TString logfile (argv[1]); + ACE_Stream<ACE_SYNCH> stream; + + if (stream.push + (new Logrec_Writer_Module (ACE_TEXT ("Writer"))) != -1 + && stream.push + (new Logrec_Separator_Module (ACE_TEXT ("Separator"))) != -1 + && stream.push + (new Logrec_Formatter_Module (ACE_TEXT ("Formatter"))) != -1 + && stream.push + (new Logrec_Reader_Module (logfile)) != -1) + return ACE_Thread_Manager::instance ()->wait () == 0 ? 0 : 1; + return 1; +} + diff --git a/ACE/examples/C++NPv2/svc.conf b/ACE/examples/C++NPv2/svc.conf new file mode 100644 index 00000000000..e97f3748cf6 --- /dev/null +++ b/ACE/examples/C++NPv2/svc.conf @@ -0,0 +1,8 @@ +static Service_Reporter "-p $SERVICE_REPORTER_PORT" + +dynamic AIO_Client_Logging_Daemon Service_Object * +AIO_CLD:_make_AIO_Client_Logging_Daemon() + "-p 7777" + +dynamic Server_Logging_Daemon Service_Object * +TPCLS:_make_TPC_Logging_Server() diff --git a/ACE/examples/ConfigViewer/ConfigTreeCtrl.cpp b/ACE/examples/ConfigViewer/ConfigTreeCtrl.cpp new file mode 100644 index 00000000000..7700272b9ba --- /dev/null +++ b/ACE/examples/ConfigViewer/ConfigTreeCtrl.cpp @@ -0,0 +1,229 @@ +// $Id$ +#include "stdafx.h" +#include "ConfigTreeCtrl.h" +#include "MainFrame.h" +#include "ValueDlg.h" +#include "ValueListCtrl.h" + +enum {CFGNEWKEY=100, CFGNEWSTRING, CFGNEWUINT, CFGNEWBINARY, CFGNEWSUBMENU, CFGFIND, CFGDELETE, CFGRENAME, CFGCOPYKEYNAME}; + + +BEGIN_EVENT_TABLE(ConfigTreeCtrl, wxTreeCtrl) + EVT_RIGHT_DOWN(ConfigTreeCtrl::OnRightDown) + EVT_RIGHT_UP(ConfigTreeCtrl::OnRightUp) + EVT_MENU(CFGNEWKEY, ConfigTreeCtrl::OnNewKey) + EVT_MENU(CFGNEWSTRING, ConfigTreeCtrl::OnNewString) + EVT_MENU(CFGNEWUINT, ConfigTreeCtrl::OnNewUINT) + EVT_MENU(CFGNEWBINARY, ConfigTreeCtrl::OnNewBinary) + EVT_MENU(CFGFIND, ConfigTreeCtrl::OnFind) + EVT_MENU(CFGDELETE, ConfigTreeCtrl::OnDelete) + EVT_TREE_SEL_CHANGED(FRAME_TREE, ConfigTreeCtrl::OnSelChanged) +END_EVENT_TABLE() + + +ConfigTreeCtrl::ConfigTreeCtrl(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style, const wxValidator& validator, const wxString& name) +: wxTreeCtrl(parent, id, pos, size, style, validator, name) +{ + // Load the tree + LoadTree(); +} + +ConfigTreeCtrl::~ConfigTreeCtrl() +{ +} + +void ConfigTreeCtrl::LoadTree() +{ + m_pConfig = MainFrame::Instance()->GetpConfig(); + const ACE_Configuration_Section_Key& Key = m_pConfig->root_section(); + wxTreeItemId Root = AppendItem(GetRootItem(), "Root"); + LoadSection(Root, Key); +} + +void ConfigTreeCtrl::LoadSection(wxTreeItemId& ParentItem, const ACE_Configuration_Section_Key& Key) +{ + ACE_TString Name; + int Index = 0; + while(!m_pConfig->enumerate_sections(Key, Index, Name)) + { + wxTreeItemId Item = AppendItem(ParentItem, Name.fast_rep()); + ACE_Configuration_Section_Key Child; + m_pConfig->open_section(Key, Name.fast_rep(), 0, Child); + LoadSection( Item, Child); + ++Index; + } +} + +void ConfigTreeCtrl::OnRightDown(wxMouseEvent& event) +{ + //EndEditLabel(TRUE); + int Flags = wxTREE_HITTEST_ONITEMLABEL | wxTREE_HITTEST_ONITEMICON; + long ItemID = HitTest(wxPoint(event.m_x, event.m_y), Flags); + SelectItem(ItemID); +} + +void ConfigTreeCtrl::OnRightUp(wxMouseEvent& event) +{ + wxTreeItemId ItemID = GetSelection(); + + wxMenu* pMenu = new wxMenu; + wxMenu* pNewMenu = new wxMenu; + pNewMenu->Append(CFGNEWKEY, "Key"); + pNewMenu->AppendSeparator(); + pNewMenu->Append(CFGNEWSTRING, "String"); + pNewMenu->Append(CFGNEWUINT, "Unsigned Int"); + //pNewMenu->Append(CFGNEWBINARY, "Binary"); + pMenu->Append(CFGNEWSUBMENU, "New", pNewMenu); + pMenu->Append(CFGFIND, "Find"); + pMenu->AppendSeparator(); + pMenu->Append(CFGDELETE, "Delete"); + //pMenu->Append(CFGRENAME, "Rename"); // not supported + //pMenu->AppendSeparator(); + //pMenu->Append(CFGCOPYKEYNAME, "Copy Key Name"); // not supported + PopupMenu(pMenu, event.m_x, event.m_y); + delete pMenu; +} + +void ConfigTreeCtrl::ResolveKey(wxTreeItemId Item, ACE_Configuration_Section_Key& Key) +{ + wxTreeItemId OriginalItem = Item; + ACE_TString Path(""); + ACE_TString Temp; + while(Item != GetRootItem()) + { + wxString Text = GetItemText(Item); + Temp = Path; + Path = Text.c_str(); + if(Temp.length()) + { + Path += "\\"; + Path += Temp; + } + Item = GetParent(Item); + } + if(Path.length()) + { + m_pConfig->expand_path(m_pConfig->root_section(), Path, Key, 0); + } + else + { + Key = m_pConfig->root_section(); + } +} + + +void ConfigTreeCtrl::OnNewKey(wxCommandEvent& event) +{ + wxTextEntryDialog Dlg(this, "Test", "Key Name"); + if(Dlg.ShowModal() != wxID_OK) + { + return; + } + + wxString Value = Dlg.GetValue(); + + // Get the key for this node + wxTreeItemId ItemID = GetSelection(); + ACE_Configuration_Section_Key Key, NewKey; + ResolveKey(ItemID, Key); + m_pConfig->open_section(Key, Value, 1, NewKey); + wxTreeItemId NewItemID = AppendItem(ItemID, Value); + EnsureVisible(NewItemID); +} + +void ConfigTreeCtrl::OnNewString(wxCommandEvent& event) +{ + ValueDlg Dlg(this, true); + if(Dlg.ShowModal() != wxID_OK) + { + return; + } + + ACE_TString Value = Dlg.GetStringValue(); + ACE_TString Name = Dlg.GetName(); + + // Get the key for this node + wxTreeItemId ItemID = GetSelection(); + ACE_Configuration_Section_Key Key; + ResolveKey(ItemID, Key); + m_pConfig->set_string_value(Key, Name.fast_rep(), Value); + m_pListCtrl->DisplaySection(Key); +} + +void ConfigTreeCtrl::OnNewUINT(wxCommandEvent& event) +{ + ValueDlg Dlg(this, false); + if(Dlg.ShowModal() != wxID_OK) + { + return; + } + + u_int Value = Dlg.GetUINTValue(); + ACE_TString Name = Dlg.GetName(); + + // Get the key for this node + wxTreeItemId ItemID = GetSelection(); + ACE_Configuration_Section_Key Key; + ResolveKey(ItemID, Key); + m_pConfig->set_integer_value(Key, Name.fast_rep(), Value); + m_pListCtrl->DisplaySection(Key); +} + +void ConfigTreeCtrl::OnNewBinary(wxCommandEvent& event) +{ + assert(0); + /* + ValueDlg Dlg(this, true); + if(Dlg.ShowModal() != wxID_OK) + { + return; + } + + ACE_TString Value = Dlg.GetStringValue(); + ACE_TString Name = Dlg.GetName(); + + // Get the key for this node + wxTreeItemId ItemID = GetSelection(); + ACE_Configuration_Section_Key Key; + ResolveKey(ItemID, Key); + m_pConfig->set_string_value(Key, Name.fast_rep(), Value); + m_pListCtrl->DisplaySection(Key); + */ +} + +void ConfigTreeCtrl::OnSelChanged(wxTreeEvent& event) +{ + wxTreeItemId ItemID = GetSelection(); + ACE_Configuration_Section_Key Key; + ResolveKey(ItemID, Key); + m_pListCtrl->DisplaySection(Key); +} + +void ConfigTreeCtrl::OnFind(wxCommandEvent& event) +{ +} + +void ConfigTreeCtrl::OnDelete(wxCommandEvent& event) +{ + wxTreeItemId ItemID = GetSelection(); + wxTreeItemId Parent = GetParent(ItemID); + ACE_Configuration_Section_Key Key; + ResolveKey(Parent, Key); + wxMessageDialog Dlg(this, "Are you sure you want to delete this section?", "Confirm Section Delete", wxYES_NO | wxICON_EXCLAMATION ); + if(Dlg.ShowModal() != wxID_YES) + { + return; + } + wxString Text = GetItemText(ItemID); + m_pConfig->remove_section(Key, Text, 1); + // Reload parent + Delete(ItemID); +} + +void ConfigTreeCtrl::ChangeConfig(ACE_Configuration* pConfig) +{ + m_pConfig = pConfig; + DeleteAllItems(); + LoadTree(); +} + diff --git a/ACE/examples/ConfigViewer/ConfigTreeCtrl.h b/ACE/examples/ConfigViewer/ConfigTreeCtrl.h new file mode 100644 index 00000000000..e44eb837384 --- /dev/null +++ b/ACE/examples/ConfigViewer/ConfigTreeCtrl.h @@ -0,0 +1,52 @@ +/* -*- C++ -*- */ +// $Id$ + +#ifndef _ConfigurationViewer_ConfigTreeCtrl_H +#define _ConfigurationViewer_ConfigTreeCtrl_H + +class ValueListCtrl; + +class ConfigTreeCtrl : public wxTreeCtrl +{ +public: + /////////////////////////////////////////// + // Initializers + /////////////////////////////////////////// + ConfigTreeCtrl(wxWindow* parent, wxWindowID id, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = wxTR_HAS_BUTTONS, const wxValidator& validator = wxDefaultValidator, const wxString& name = "listCtrl"); + virtual ~ConfigTreeCtrl(); + + /////////////////////////////////////////// + // Methods + /////////////////////////////////////////// + void LoadTree(); + void OnRightDown(wxMouseEvent& event); + void OnRightUp(wxMouseEvent& event); + void OnNewKey(wxCommandEvent& event); + void OnNewString(wxCommandEvent& event); + void OnNewUINT(wxCommandEvent& event); + void OnNewBinary(wxCommandEvent& event); + void OnFind(wxCommandEvent& event); + void OnDelete(wxCommandEvent& event); + void OnSelChanged(wxTreeEvent& event); + void ChangeConfig(ACE_Configuration* pConfig); + /////////////////////////////////////////// + // Attribute Accessors + /////////////////////////////////////////// + void SetpListCtrl(ValueListCtrl* pListCtrl) {m_pListCtrl = pListCtrl;}; + +protected: + // Not Used + ConfigTreeCtrl(const ConfigTreeCtrl& RHS); + const ConfigTreeCtrl& operator=(const ConfigTreeCtrl& RHS); + + void LoadSection(wxTreeItemId& ParentItem, const ACE_Configuration_Section_Key& Key); + void ResolveKey(wxTreeItemId Item, ACE_Configuration_Section_Key& Key); +private: + DECLARE_EVENT_TABLE() + + ACE_Configuration* m_pConfig; + ValueListCtrl* m_pListCtrl; +}; + +#endif + diff --git a/ACE/examples/ConfigViewer/ConfigViewer.mpc b/ACE/examples/ConfigViewer/ConfigViewer.mpc new file mode 100644 index 00000000000..7927fb9b694 --- /dev/null +++ b/ACE/examples/ConfigViewer/ConfigViewer.mpc @@ -0,0 +1,7 @@ +// -*- MPC -*- +// $Id$ + +project : aceexe, wxwindows { + pch_header = stdafx.h + pch_source = stdafx.cpp +}
\ No newline at end of file diff --git a/ACE/examples/ConfigViewer/ConfigurationViewer.cpp b/ACE/examples/ConfigViewer/ConfigurationViewer.cpp new file mode 100644 index 00000000000..20d3dc02d2e --- /dev/null +++ b/ACE/examples/ConfigViewer/ConfigurationViewer.cpp @@ -0,0 +1,45 @@ +// $Id$ +#ifdef __GNUG__ + #pragma implementation "minimal.cpp" + #pragma interface "minimal.cpp" +#endif + +#include "stdafx.h" +#include "MainFrame.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +// the application icon +#if defined(__WXGTK__) || defined(__WXMOTIF__) + #include "mondrian.xpm" +#endif + +class ConfigurationViewerApp : public wxApp +{ +public: + virtual bool OnInit(); +}; + +IMPLEMENT_APP(ConfigurationViewerApp) + +bool ConfigurationViewerApp::OnInit() +{ + // Create the main application window + MainFrame *frame = new MainFrame("Configuration Viewer", + wxPoint(50, 50), wxSize(450, 340)); + + // Give it an icon +#ifdef __WXMSW__ + frame->SetIcon(wxIcon("mondrian")); +#else + frame->SetIcon(wxIcon( mondrian_xpm )); +#endif + + frame->Show(TRUE); + SetTopWindow(frame); + + return TRUE; +} + diff --git a/ACE/examples/ConfigViewer/ConfigurationViewer.rc b/ACE/examples/ConfigViewer/ConfigurationViewer.rc new file mode 100644 index 00000000000..f490ccefc2d --- /dev/null +++ b/ACE/examples/ConfigViewer/ConfigurationViewer.rc @@ -0,0 +1,9 @@ +/* -*- C++ -*- */ +// $Id$ + +#include "wx/msw/wx.rc" +mondrian ICON "mondrian.ico" + +#define MINIMAL_QUIT 1 +#define MINIMAL_ABOUT 102 + diff --git a/ACE/examples/ConfigViewer/MainFrame.cpp b/ACE/examples/ConfigViewer/MainFrame.cpp new file mode 100644 index 00000000000..ace1c1c5e52 --- /dev/null +++ b/ACE/examples/ConfigViewer/MainFrame.cpp @@ -0,0 +1,199 @@ +// $Id$ +#include "stdafx.h" +#include "MainFrame.h" +#include "ConfigTreeCtrl.h" +#include "ValueListCtrl.h" + +// Singleton +MainFrame* MainFrame::m_pInstance = 0; + +// IDs for the controls and the menu commands + +BEGIN_EVENT_TABLE(MainFrame, wxFrame) + EVT_MENU(FILE_NEW_PERSISTENT_HEAP, MainFrame::OnFileNewPersistentHeap) + EVT_MENU(FILE_NEW_TRANSIENT_HEAP, MainFrame::OnFileNewTransientHeap) + EVT_MENU(FILE_OPEN_PERSISTENT_HEAP, MainFrame::OnFileOpenPersistentHeap) + EVT_MENU(FILE_OPEN_REGISTRY, MainFrame::OnFileOpenRegistry) + EVT_MENU(FILE_EXPORT, MainFrame::OnFileExport) + EVT_MENU(FILE_IMPORT, MainFrame::OnFileImport) + EVT_MENU(QUIT, MainFrame::OnQuit) + EVT_MENU(ABOUT, MainFrame::OnAbout) +END_EVENT_TABLE() + +// frame constructor +MainFrame::MainFrame(const wxString& title, const wxPoint& pos, const wxSize& size) +: wxFrame((wxFrame *)NULL, -1, title, pos, size), + m_pConfig(0) +{ + m_pInstance = this; + + // Create a persistent heap based configuration + + ACE_Configuration_Heap* pHeapConfig = new ACE_Configuration_Heap; + pHeapConfig->open(); + m_pConfig = pHeapConfig; + + // set the frame icon + SetIcon(wxICON(mondrian)); + + // Create Splitter + m_pSplitter = new wxSplitterWindow(this, -1); + wxSize sz( m_pSplitter->GetSize() ); + sz.SetWidth(sz.GetWidth() / 2); + + // List Control + m_pListCtrl = new ValueListCtrl(m_pSplitter, -1, wxDefaultPosition, sz); + + // Tree Control + m_pTreeCtrl = new ConfigTreeCtrl(m_pSplitter, FRAME_TREE, wxDefaultPosition, sz, + wxTR_EDIT_LABELS | wxTR_HAS_BUTTONS | wxTR_LINES_AT_ROOT); + m_pTreeCtrl->SetpListCtrl(m_pListCtrl); + + + // Setup splitter + m_pSplitter->SplitVertically(m_pTreeCtrl, m_pListCtrl); + m_pSplitter->SetMinimumPaneSize(100); + m_pSplitter->SetSashPosition(size.GetWidth() / 3); + + // create a menu bar + wxMenu *menuFile = new wxMenu("", wxMENU_TEAROFF); + menuFile->Append(FILE_NEW_PERSISTENT_HEAP, "New Persistent Heap", "Create a new persistent heap"); + menuFile->Append(FILE_NEW_TRANSIENT_HEAP, "New Transient Heap", "Create a new transient heap"); + menuFile->Append(FILE_OPEN_PERSISTENT_HEAP, "Open Persistent Heap", "Open Persistent Heap"); +#if defined (ACE_WIN32) + menuFile->Append(FILE_OPEN_REGISTRY, "Open Win32 Registry", "Open Win32 Registry"); +#endif + menuFile->AppendSeparator(); + menuFile->Append(FILE_IMPORT, "Import from INI file", "Import from INI file"); + menuFile->Append(FILE_EXPORT, "Export to INI file", "Export to INI file"); + menuFile->AppendSeparator(); + menuFile->Append(ABOUT, "&About...\tCtrl-A", "Show about dialog"); + menuFile->AppendSeparator(); + menuFile->Append(QUIT, "E&xit\tAlt-X", "Quit this program"); + + // now append the freshly created menu to the menu bar... + wxMenuBar *menuBar = new wxMenuBar(); + menuBar->Append(menuFile, "&File"); + + // ... and attach this menu bar to the frame + SetMenuBar(menuBar); + +#if wxUSE_STATUSBAR + CreateStatusBar(2); + SetStatusText("Ready"); +#endif // wxUSE_STATUSBAR +} + + +MainFrame::~MainFrame() +{ + delete m_pConfig; + m_pInstance = 0; +} + +MainFrame* MainFrame::Instance() +{ + assert(m_pInstance); + return m_pInstance; +} + + +// event handlers + +void MainFrame::OnSize(wxSizeEvent& event) +{ + wxLayoutAlgorithm layout; + layout.LayoutFrame(this, m_pListCtrl); +} + + +void MainFrame::OnQuit(wxCommandEvent& WXUNUSED(event)) +{ + // TRUE is to force the frame to close + Close(TRUE); +} + +void MainFrame::OnAbout(wxCommandEvent& WXUNUSED(event)) +{ + wxString msg; + msg.Printf( _T("Configuration Viewer v1.0\nWritten by Chris Hafey (chris@stentorsoft.com)\n")); + wxMessageBox(msg, "About", wxOK | wxICON_INFORMATION, this); +} + +void MainFrame::OnFileNewPersistentHeap(wxCommandEvent& event) +{ + wxFileDialog Dlg(this, "Enter Filename:", "", "", "*.*", 0); + if(Dlg.ShowModal() != wxID_OK) + { + return; + } + delete m_pConfig; + ACE_Configuration_Heap* pHeapConfig = new ACE_Configuration_Heap; + pHeapConfig->open(Dlg.GetFilename()); + SetNewConfig(pHeapConfig); +} + +void MainFrame::OnFileNewTransientHeap(wxCommandEvent& event) +{ + delete m_pConfig; + ACE_Configuration_Heap* pHeapConfig = new ACE_Configuration_Heap; + pHeapConfig->open(); + SetNewConfig(pHeapConfig); +} + +void MainFrame::OnFileOpenPersistentHeap(wxCommandEvent& event) +{ + wxFileDialog Dlg(this, "Choose a file", "", "", "*.*", wxOPEN); + if(Dlg.ShowModal() != wxID_OK) + { + return; + } + delete m_pConfig; + ACE_Configuration_Heap* pHeapConfig = new ACE_Configuration_Heap; + pHeapConfig->open(Dlg.GetFilename()); + SetNewConfig(pHeapConfig); +} + +void MainFrame::OnFileOpenRegistry(wxCommandEvent& event) +{ +#if defined (ACE_WIN32) + wxTextEntryDialog Dlg(this, "Enter Root:"); + if(Dlg.ShowModal() != wxID_OK) + { + return; + } + HKEY Root = ACE_Configuration_Win32Registry::resolve_key(HKEY_LOCAL_MACHINE, Dlg.GetValue(), 0); + ACE_Configuration_Win32Registry* pWin32Reg = new ACE_Configuration_Win32Registry(Root);; + delete m_pConfig; + SetNewConfig(pWin32Reg); +#endif +} + +void MainFrame::OnFileExport(wxCommandEvent& event) +{ + wxFileDialog Dlg(this, "Enter Filename:", "", "", "*.*",0); + if(Dlg.ShowModal() != wxID_OK) + { + return; + } + m_pConfig->export_config(Dlg.GetFilename()); +} + +void MainFrame::OnFileImport(wxCommandEvent& event) +{ + wxFileDialog Dlg(this, "Choose a file", "", "", "*.*", wxOPEN); + if(Dlg.ShowModal() != wxID_OK) + { + return; + } + m_pConfig->import_config(Dlg.GetFilename()); + SetNewConfig(m_pConfig); +} + +void MainFrame::SetNewConfig(ACE_Configuration* pConfig) +{ + m_pConfig = pConfig; + m_pListCtrl->ChangeConfig(pConfig); + m_pTreeCtrl->ChangeConfig(pConfig); +} + diff --git a/ACE/examples/ConfigViewer/MainFrame.h b/ACE/examples/ConfigViewer/MainFrame.h new file mode 100644 index 00000000000..1ae7725fe80 --- /dev/null +++ b/ACE/examples/ConfigViewer/MainFrame.h @@ -0,0 +1,72 @@ +/* -*- C++ -*- */ +// $Id$ + +#ifndef _ConfigurationViewer_MainFrame_H +#define _ConfigurationViewer_MainFrame_H + +class ConfigTreeCtrl; +class ValueListCtrl; + +enum +{ + // menu items + QUIT = 1, + ABOUT, + FILE_NEW_PERSISTENT_HEAP, + FILE_NEW_TRANSIENT_HEAP, + FILE_OPEN_PERSISTENT_HEAP, + FILE_OPEN_REGISTRY, + FILE_EXPORT, + FILE_IMPORT, + LEFT_SASH, + FRAME_TREE +}; + + +class MainFrame : public wxFrame +{ +public: + /////////////////////////////////////////// + // Initializers + /////////////////////////////////////////// + MainFrame(const wxString& title, const wxPoint& pos, const wxSize& size); + virtual ~MainFrame(); + + /////////////////////////////////////////// + // Methods + /////////////////////////////////////////// + static MainFrame* Instance(); + void OnQuit(wxCommandEvent& event); + void OnAbout(wxCommandEvent& event); + void OnFileNewPersistentHeap(wxCommandEvent& event); + void OnFileNewTransientHeap(wxCommandEvent& event); + void OnFileOpenPersistentHeap(wxCommandEvent& event); + void OnFileOpenRegistry(wxCommandEvent& event); + void OnFileExport(wxCommandEvent& event); + void OnFileImport(wxCommandEvent& event); + void OnSize(wxSizeEvent& event); + + /////////////////////////////////////////// + // Attribute Accessors + /////////////////////////////////////////// + ACE_Configuration* GetpConfig() {return m_pConfig;}; +protected: + // Not Used + MainFrame(const MainFrame& RHS); + const MainFrame& operator=(const MainFrame& RHS); + + // Operations + void SetNewConfig(ACE_Configuration* pConfig); + + // Attributes + wxSplitterWindow* m_pSplitter; + ConfigTreeCtrl* m_pTreeCtrl; + ValueListCtrl* m_pListCtrl; +private: + DECLARE_EVENT_TABLE() + ACE_Configuration* m_pConfig; + static MainFrame* m_pInstance; +}; + +#endif + diff --git a/ACE/examples/ConfigViewer/README b/ACE/examples/ConfigViewer/README new file mode 100644 index 00000000000..1f83c2dc848 --- /dev/null +++ b/ACE/examples/ConfigViewer/README @@ -0,0 +1,74 @@ +Configuration Viewer 1.0 +======================== + +This is something I quickly threw together to allow GUI editing of +ACE_Configuration files. I thought it would be useful and serve as a +better example of how to use ACE_Configuration. I developed this under +Windows 2000, but it should easily port to any platform that wxWindows +supports (see http://www.wxwindows.org.). + +============== + Usage +============== +All functionality is delivered through the file menu and right mouse button +context menus. The file menu lets you create the different types of +ACE_Configurations such as a transient heap, persistent heap or Win32 +Registry heap. A new persistent heap may be created, or an older one +may be opened. The win32 registry will require you to enter the path +from HKEY_LOCAL_MACHINE that you want to open. For example: "Software/TAO" +would set the Win32Registry's root to HKEY_LOCAL_MACHINE/Software/TAO. +Note that this quick implementation loads the entire tree, so if you +enter "Software" it may take a minute to load up - beware! Next you +may import or export entries from a heap to an INI file using the +Import/Export file commands. + +The right mouse button opens up a context menu in both the tree control +and the list control. +From the tree context menu, you can: +1) Create new keys (these hold name/value pairs) +2) Create new string values +3) Create new integer values +4) Delete a key (beware, everything beneath it will be removed as well) + +From the list control context menu, you can: +1) Modify a the value of an entry +2) Delete the entry +3) Rename the entry + +Known Bugs/Issues: +*) You cannot enter/edit binary types +*) Adding a new string/integer value with the same name as an existing + entry will overwrite the existing entry without warning. I think there + is a memory leak that occurs as well. +*) You can add entries to the root key, but they will not be imported + or exported. I think this is by design and the GUI should prevent + this. I need to investigate this further. +*) The entire configuration file is loaded into the tree when it is opened. + For large configurations, this may take a while. A good improvement + would be to load items as the user expands them. +*) At the time of this writing, there is a nasty bug in + ACE_Configuration_Heap that has to do with changing the value + of an existing entry. I have submitted a patch to fix this, but + it may not go in until 5.1.3 (current version is 5.1.2). I strongly + recommend that you get the patch/newer version! +*) Renaming of Keys is not supported. This requires an enhancement to + ACE_Configuration first. +*) No makefiles for other platforms exist, can you donate one? +*) This has only been tested for non MFC DLL builds of ACE, it + should work fine in the other configurations, but I haven't tested it. + +============================================= + +This was developed using: +*) wxWindows 2.1.15 +*) ACE 5.0.16 + My patch to fix a bug in ACE_Configuration_Heap +*) Windows 2000 +*) MSVC 6.0 + SP3 + +If you have any questions or comments, please send me an email. I really +enjoy hearing about others that find this contribution useful! + +Chris Hafey +May 2, 2000 +chris@stentorsoft.com + diff --git a/ACE/examples/ConfigViewer/ValueDlg.cpp b/ACE/examples/ConfigViewer/ValueDlg.cpp new file mode 100644 index 00000000000..16ec9c34b22 --- /dev/null +++ b/ACE/examples/ConfigViewer/ValueDlg.cpp @@ -0,0 +1,63 @@ +// $Id$ +#include "stdafx.h" +#include "ValueDlg.h" + +ValueDlg::ValueDlg(wxWindow* pParent, bool String) +: wxDialog(pParent, -1, String ? "New String" : "New Value", wxDefaultPosition, wxSize(300,140)) +{ + m_pName= new wxStaticText(this, -1, "Name:", wxPoint(20, 20)); + m_pNameText = new wxTextCtrl(this, -1, "", wxPoint(60, 20), wxDefaultSize, 0, wxTextValidator(wxFILTER_NONE, &m_Name)); + m_pValue = new wxStaticText(this, -1, "Value:", wxPoint(20, 50)); + m_pValueText = new wxTextCtrl(this, -1, "", wxPoint(60, 50), wxDefaultSize, 0, wxTextValidator(String ? wxFILTER_NONE : wxFILTER_NUMERIC, &m_Value)); + m_pOK = new wxButton(this, wxID_OK, "OK", wxPoint(60, 80)); + m_pCancel = new wxButton(this, wxID_CANCEL, "Cancel", wxPoint(160, 80)); +} + +ValueDlg::ValueDlg(wxWindow* pParent, wxString& Name, wxString& Value) +: wxDialog(pParent, -1, "Edit String", wxDefaultPosition, wxSize(300,140)) +{ + m_Name = Name; + m_Value = Value; + m_pName= new wxStaticText(this, -1, "Name:", wxPoint(20, 20)); + m_pNameText = new wxTextCtrl(this, -1, "", wxPoint(60, 20), wxDefaultSize, 0, wxTextValidator(wxFILTER_NONE, &m_Name)); + m_pNameText->SetEditable(false); + m_pValue = new wxStaticText(this, -1, "Value:", wxPoint(20, 50)); + m_pValueText = new wxTextCtrl(this, -1, Value, wxPoint(60, 50), wxDefaultSize, 0, wxTextValidator(wxFILTER_NONE, &m_Value)); + m_pOK = new wxButton(this, wxID_OK, "OK", wxPoint(60, 80)); + m_pCancel = new wxButton(this, wxID_CANCEL, "Cancel", wxPoint(160, 80)); +} + +ValueDlg::ValueDlg(wxWindow* pParent, wxString& Name, u_int Value) +: wxDialog(pParent, -1, "Edit String", wxDefaultPosition, wxSize(300,140)) +{ + m_Name = Name; + m_Value.sprintf("%d", Value); + m_pName= new wxStaticText(this, -1, "Name:", wxPoint(20, 20)); + m_pNameText = new wxTextCtrl(this, -1, "", wxPoint(60, 20), wxDefaultSize, 0, wxTextValidator(wxFILTER_NONE, &m_Name)); + m_pNameText->SetEditable(false); + m_pValue = new wxStaticText(this, -1, "Value:", wxPoint(20, 50)); + m_pValueText = new wxTextCtrl(this, -1, m_Value, wxPoint(60, 50), wxDefaultSize, 0, wxTextValidator(wxFILTER_NUMERIC, &m_Value)); + m_pOK = new wxButton(this, wxID_OK, "OK", wxPoint(60, 80)); + m_pCancel = new wxButton(this, wxID_CANCEL, "Cancel", wxPoint(160, 80)); +} + + +ValueDlg::~ValueDlg() +{ +} + +const wxString& ValueDlg::GetName() +{ + return m_Name; +} + +const wxString& ValueDlg::GetStringValue() +{ + return m_Value; +} + +u_int ValueDlg::GetUINTValue() +{ + return atoi(m_Value); +} + diff --git a/ACE/examples/ConfigViewer/ValueDlg.h b/ACE/examples/ConfigViewer/ValueDlg.h new file mode 100644 index 00000000000..2ea4f026567 --- /dev/null +++ b/ACE/examples/ConfigViewer/ValueDlg.h @@ -0,0 +1,51 @@ +/* -*- C++ -*- */ +// $Id$ + +#ifndef _ConfigurationViewer_ValueDlg_H +#define _ConfigurationViewer_ValueDlg_H + +class ValueDlg : public wxDialog +{ +public: + /////////////////////////////////////////// + // Initializers + /////////////////////////////////////////// + ValueDlg(wxWindow* pParent, bool String); + // New Value Ctor + ValueDlg(wxWindow* pParent, wxString& Name, wxString& Value); + // Edit String Ctor + ValueDlg(wxWindow* pParent, wxString& Name, u_int Value); + // Edit UINT Ctor + virtual ~ValueDlg(); + + /////////////////////////////////////////// + // Methods + /////////////////////////////////////////// + const wxString& GetName(); + const wxString& GetStringValue(); + u_int GetUINTValue(); + + /////////////////////////////////////////// + // Attribute Accessors + /////////////////////////////////////////// + wxButton* m_pOK; + wxButton* m_pCancel; + wxStaticText* m_pName; + wxTextCtrl* m_pNameText; + wxStaticText* m_pValue; + wxTextCtrl* m_pValueText; +protected: + // Not Used + ValueDlg(const ValueDlg& RHS); + const ValueDlg& operator=(const ValueDlg& RHS); + + wxString m_Name; + wxString m_Value; + u_int m_UINTValue; + +private: + +}; + +#endif + diff --git a/ACE/examples/ConfigViewer/ValueListCtrl.cpp b/ACE/examples/ConfigViewer/ValueListCtrl.cpp new file mode 100644 index 00000000000..93c9af14fcb --- /dev/null +++ b/ACE/examples/ConfigViewer/ValueListCtrl.cpp @@ -0,0 +1,227 @@ +// $Id$ +#include "stdafx.h" +#include "ValueListCtrl.h" +#include "MainFrame.h" +#include "ValueDlg.h" + + +enum {VALUEMODIFY=200, VALUEDELETE, VALUERENAME}; + +BEGIN_EVENT_TABLE(ValueListCtrl, wxListCtrl) + EVT_RIGHT_DOWN(ValueListCtrl::OnRightDown) + EVT_MENU(VALUEMODIFY, ValueListCtrl::OnModify) + EVT_MENU(VALUEDELETE, ValueListCtrl::OnDelete) + EVT_MENU(VALUERENAME, ValueListCtrl::OnRename) +END_EVENT_TABLE() + + +ValueListCtrl::ValueListCtrl(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style, const wxValidator& validator, const wxString& name) +: wxListCtrl(parent, id, pos, size, style | wxLC_REPORT | wxLC_SINGLE_SEL, validator, name) +{ + InsertColumn(0, "Name"); + InsertColumn(1, "Type"); + InsertColumn(2, "Data"); +} + +ValueListCtrl::~ValueListCtrl() +{ +} + +void ValueListCtrl::DisplaySection(const ACE_Configuration_Section_Key& Key) +{ + m_Key = Key; + DeleteAllItems(); + m_pConfig = MainFrame::Instance()->GetpConfig(); + ACE_TString Name; + int Index = 0; + ACE_Configuration::VALUETYPE Type; + ACE_TString StringValue; + u_int UINTValue; + while(!m_pConfig->enumerate_values(Key, Index, Name, Type)) + { + int Row = InsertItem(0, Name.fast_rep()); + switch(Type) + { + case ACE_Configuration::STRING: + SetItem(Row, 1, "String"); + m_pConfig->get_string_value(Key, Name.fast_rep(), StringValue); + SetItem(Row, 2, StringValue.fast_rep()); + break; + case ACE_Configuration::INTEGER: + { + SetItem(Row, 1, "Integer"); + m_pConfig->get_integer_value(Key, Name.fast_rep(), UINTValue); + wxString Text; + Text.sprintf("%d", UINTValue); + SetItem(Row, 2, Text); + } + break; + case ACE_Configuration::BINARY: + SetItem(Row, 1, "Binary"); + break; + } + SetItemData(Row, Type); + ++Index; + } +} + +long ValueListCtrl::GetSelectedItem() +{ + return GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); +} + +void ValueListCtrl::SelectItem(long ItemID) +{ + // XXX Something isn't right here... When I use a mask it doesn't work at + // all someone explain.. + long State = wxLIST_STATE_SELECTED | wxLIST_STATE_FOCUSED; + SetItemState(ItemID, State, State); +} + +void ValueListCtrl::OnRightDown(wxMouseEvent& event) +{ + int Flags = wxLIST_HITTEST_ONITEM; + long ItemID = HitTest(wxPoint(event.m_x, event.m_y), Flags); + if(ItemID < 0) + { + return; + } + SelectItem(ItemID); + + wxMenu* pMenu = new wxMenu; + pMenu->Append(VALUEMODIFY, "Modify"); + pMenu->AppendSeparator(); + pMenu->Append(VALUEDELETE, "Delete"); + pMenu->Append(VALUERENAME, "Rename"); + PopupMenu(pMenu, event.m_x, event.m_y); + delete pMenu; +} + +void ValueListCtrl::OnModify(wxCommandEvent& event) +{ + long Item = GetSelectedItem(); + if(Item == -1) + { + return ; + } + wxListItem ListItem; + ACE_Configuration::VALUETYPE Type = (ACE_Configuration::VALUETYPE)GetItemData(Item); + wxString Name = GetItemText(Item); + + switch(Type) + { + case ACE_Configuration::STRING: + { + ACE_TString Value; + m_pConfig->get_string_value(m_Key, Name, Value); + wxString ValueText(Value.fast_rep()); + ValueDlg Dlg(this, Name, ValueText); + if(Dlg.ShowModal() != wxID_OK) + { + return; + } + + Value = (const char*)Dlg.GetStringValue(); + m_pConfig->set_string_value(m_Key, Name, Value); + } + break; + case ACE_Configuration::INTEGER: + { + u_int Value; + m_pConfig->get_integer_value(m_Key, Name, Value); + ValueDlg Dlg(this, Name, Value); + if(Dlg.ShowModal() != wxID_OK) + { + return; + } + + Value = Dlg.GetUINTValue(); + m_pConfig->set_integer_value(m_Key, Name, Value); + + } + break; + case ACE_Configuration::BINARY: + { + wxMessageBox("Binary modification not supported (why don't you implement it?)"); + //assert(0); + } + break; + } + DisplaySection(m_Key); +} + +void ValueListCtrl::OnDelete(wxCommandEvent& event) +{ + wxMessageDialog Dlg(this, "Are you sure you want to delete this value?", "Confirm Value Delete", wxYES_NO | wxICON_EXCLAMATION ); + if(Dlg.ShowModal() != wxID_YES) + { + return; + } + long Item = GetSelectedItem(); + if(Item == -1) + { + return ; + } + wxString Text = GetItemText(Item); + m_pConfig->remove_value(m_Key, Text); + DeleteItem(Item); +} + +void ValueListCtrl::OnRename(wxCommandEvent& event) +{ + long Item = GetSelectedItem(); + if(Item == -1) + { + return ; + } + wxListItem ListItem; + ACE_Configuration::VALUETYPE Type = (ACE_Configuration::VALUETYPE)GetItemData(Item); + wxString Name = GetItemText(Item); + wxString Message; + Message.sprintf("Enter new name for '%s'", Name); + wxTextEntryDialog Dlg(this, Message, "Please enter text", Name); + if(Dlg.ShowModal() != wxID_OK) + { + return; + } + wxString NewName = Dlg.GetValue(); + if(NewName == Name) + { + return; + } + + // XXX Check to see if an entry with this new name already exists + + switch(Type) + { + case ACE_Configuration::STRING: + { + ACE_TString Value; + m_pConfig->get_string_value(m_Key, Name, Value); + m_pConfig->set_string_value(m_Key, NewName, Value); + } + break; + case ACE_Configuration::INTEGER: + { + u_int Value; + m_pConfig->get_integer_value(m_Key, Name, Value); + m_pConfig->set_integer_value(m_Key, NewName, Value); + } + break; + case ACE_Configuration::BINARY: + { + wxMessageBox("Rename binary not supported (Why don't you implement it?)"); + assert(0); + } + } + m_pConfig->remove_value(m_Key, Name); + DisplaySection(m_Key); +} + +void ValueListCtrl::ChangeConfig(ACE_Configuration* pConfig) +{ + m_pConfig = pConfig; + DisplaySection(pConfig->root_section()); +} + + diff --git a/ACE/examples/ConfigViewer/ValueListCtrl.h b/ACE/examples/ConfigViewer/ValueListCtrl.h new file mode 100644 index 00000000000..ce802e67e96 --- /dev/null +++ b/ACE/examples/ConfigViewer/ValueListCtrl.h @@ -0,0 +1,47 @@ +/* -*- C++ -*- */ +// $Id$ + +#ifndef _ConfigurationViewer_ValueListCtrl_H +#define _ConfigurationViewer_ValueListCtrl_H + +class ValueListCtrl : public wxListCtrl +{ +public: + /////////////////////////////////////////// + // Initializers + /////////////////////////////////////////// + ValueListCtrl(wxWindow* parent, wxWindowID id, const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, long style = wxLC_ICON, + const wxValidator& validator = wxDefaultValidator, + const wxString& name = "listCtrl"); + virtual ~ValueListCtrl(); + + /////////////////////////////////////////// + // Methods + /////////////////////////////////////////// + void DisplaySection(const ACE_Configuration_Section_Key& Key); + long GetSelectedItem(); + void SelectItem(long ItemID); + void OnRightDown(wxMouseEvent& event); + void OnModify(wxCommandEvent& event); + void OnDelete(wxCommandEvent& event); + void OnRename(wxCommandEvent& event); + void ChangeConfig(ACE_Configuration* pConfig); + /////////////////////////////////////////// + // Attribute Accessors + /////////////////////////////////////////// + +protected: + // Not Used + ValueListCtrl(const ValueListCtrl& RHS); + const ValueListCtrl& operator=(const ValueListCtrl& RHS); + + DECLARE_EVENT_TABLE() +private: + + ACE_Configuration* m_pConfig; + ACE_Configuration_Section_Key m_Key; +}; + +#endif + diff --git a/ACE/examples/ConfigViewer/mondrian.ico b/ACE/examples/ConfigViewer/mondrian.ico Binary files differnew file mode 100644 index 00000000000..2310c5d275a --- /dev/null +++ b/ACE/examples/ConfigViewer/mondrian.ico diff --git a/ACE/examples/ConfigViewer/mondrian.xpm b/ACE/examples/ConfigViewer/mondrian.xpm new file mode 100644 index 00000000000..409f27a843c --- /dev/null +++ b/ACE/examples/ConfigViewer/mondrian.xpm @@ -0,0 +1,44 @@ +/* XPM */ +static char *mondrian_xpm[] = { +/* columns rows colors chars-per-pixel */ +"32 32 6 1", +" c Black", +". c Blue", +"X c #00bf00", +"o c Red", +"O c Yellow", +"+ c Gray100", +/* pixels */ +" ", +" oooooo +++++++++++++++++++++++ ", +" oooooo +++++++++++++++++++++++ ", +" oooooo +++++++++++++++++++++++ ", +" oooooo +++++++++++++++++++++++ ", +" oooooo +++++++++++++++++++++++ ", +" oooooo +++++++++++++++++++++++ ", +" oooooo +++++++++++++++++++++++ ", +" ", +" ++++++ ++++++++++++++++++ .... ", +" ++++++ ++++++++++++++++++ .... ", +" ++++++ ++++++++++++++++++ .... ", +" ++++++ ++++++++++++++++++ .... ", +" ++++++ ++++++++++++++++++ .... ", +" ++++++ ++++++++++++++++++ ", +" ++++++ ++++++++++++++++++ ++++ ", +" ++++++ ++++++++++++++++++ ++++ ", +" ++++++ ++++++++++++++++++ ++++ ", +" ++++++ ++++++++++++++++++ ++++ ", +" ++++++ ++++++++++++++++++ ++++ ", +" ++++++ ++++++++++++++++++ ++++ ", +" ++++++ ++++++++++++++++++ ++++ ", +" ++++++ ++++++++++++++++++ ++++ ", +" ++++++ ++++++++++++++++++ ++++ ", +" ++++++ ++++ ", +" ++++++ OOOOOOOOOOOO XXXXX ++++ ", +" ++++++ OOOOOOOOOOOO XXXXX ++++ ", +" ++++++ OOOOOOOOOOOO XXXXX ++++ ", +" ++++++ OOOOOOOOOOOO XXXXX ++++ ", +" ++++++ OOOOOOOOOOOO XXXXX ++++ ", +" ++++++ OOOOOOOOOOOO XXXXX ++++ ", +" " +}; diff --git a/ACE/examples/ConfigViewer/stdafx.cpp b/ACE/examples/ConfigViewer/stdafx.cpp new file mode 100644 index 00000000000..0c0c239bca0 --- /dev/null +++ b/ACE/examples/ConfigViewer/stdafx.cpp @@ -0,0 +1,3 @@ +// $Id$ +#include "stdafx.h" + diff --git a/ACE/examples/ConfigViewer/stdafx.h b/ACE/examples/ConfigViewer/stdafx.h new file mode 100644 index 00000000000..565059d0dd3 --- /dev/null +++ b/ACE/examples/ConfigViewer/stdafx.h @@ -0,0 +1,16 @@ +/* -*- C++ -*- */ +// $Id$ + +#include "ace/ace.h" +#include "ace/os.h" +#include "ace/Configuration.h" +#include "wx/wxprec.h" +#include "wx/laywin.h" +#include "wx/treectrl.h" +#include "wx/listctrl.h" +#include "wx/splitter.h" + + + + + diff --git a/ACE/examples/Connection/Makefile.am b/ACE/examples/Connection/Makefile.am new file mode 100644 index 00000000000..8aa21d598ff --- /dev/null +++ b/ACE/examples/Connection/Makefile.am @@ -0,0 +1,15 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +SUBDIRS = \ + blocking \ + misc \ + non_blocking + diff --git a/ACE/examples/Connection/blocking/.cvsignore b/ACE/examples/Connection/blocking/.cvsignore new file mode 100644 index 00000000000..07fde30990a --- /dev/null +++ b/ACE/examples/Connection/blocking/.cvsignore @@ -0,0 +1,4 @@ +acceptor +acceptor +connector +connector diff --git a/ACE/examples/Connection/blocking/Connection_Blocking.mpc b/ACE/examples/Connection/blocking/Connection_Blocking.mpc new file mode 100644 index 00000000000..758e2bfbf95 --- /dev/null +++ b/ACE/examples/Connection/blocking/Connection_Blocking.mpc @@ -0,0 +1,21 @@ +// -*- MPC -*- +// $Id$ + +project(*acceptor) : aceexe { + avoids += ace_for_tao + exename = acceptor + Source_Files { + SPIPE-acceptor.cpp + test_spipe_acceptor.cpp + } +} + +project(*connector) : aceexe { + avoids += ace_for_tao + exename = connector + Source_Files { + SPIPE-connector.cpp + test_spipe_connector.cpp + } +} + diff --git a/ACE/examples/Connection/blocking/Makefile.am b/ACE/examples/Connection/blocking/Makefile.am new file mode 100644 index 00000000000..a12eab920b8 --- /dev/null +++ b/ACE/examples/Connection/blocking/Makefile.am @@ -0,0 +1,60 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +ACE_BUILDDIR = $(top_builddir) +ACE_ROOT = $(top_srcdir) + +noinst_PROGRAMS = + +## Makefile.Connection_Blocking_Acceptor.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS += acceptor + +acceptor_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +acceptor_SOURCES = \ + SPIPE-acceptor.cpp \ + test_spipe_acceptor.cpp \ + SPIPE-acceptor.h + +acceptor_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Makefile.Connection_Blocking_Connector.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS += connector + +connector_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +connector_SOURCES = \ + SPIPE-connector.cpp \ + test_spipe_connector.cpp \ + SPIPE-connector.h + +connector_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Clean up template repositories, etc. +clean-local: + -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.* + -rm -f gcctemp.c gcctemp so_locations *.ics + -rm -rf cxx_repository ptrepository ti_files + -rm -rf templateregistry ir.out + -rm -rf ptrepository SunWS_cache Templates.DB diff --git a/ACE/examples/Connection/blocking/README b/ACE/examples/Connection/blocking/README new file mode 100644 index 00000000000..c7763e3ed04 --- /dev/null +++ b/ACE/examples/Connection/blocking/README @@ -0,0 +1,36 @@ +Presently, this directory contains only one example application for +SPIPEs. The test source code is contained in SPIPE-acceptor.h and +SPIPE-connector.h. + +The SPIPE-acceptor example illustrates how named pipes are used on NT. +Once the server establishes a connection to a single client, it spawns +a thread pool to handle incoming requests via the proactor event loop. +That is, a separate thread from the pool is used to process each +message sent by a client. The size of the thread pool can be +specified by command-line arguments. This example leverages the +queueing performed by the NT kernel to trivially implement a thread +pool architecture. + +test_spipe_acceptor has the following command-line arguments: + +test_spipe_acceptor -t <threads> + +<threads> specifies the size of the thread-pool running in the +proactor event loop. + +Here's how to run the tests: + +% test_spipe_acceptor -t 1000000 +starting up daemon test_sock_acceptor +Opening acepipe +hello + +% test_spipe_connector +starting up daemon test_sock_connector +Opening acepipe +activating 5 + +please enter input..: hello + +There are a number of other options that you can provide. Please see +the source code for details. diff --git a/ACE/examples/Connection/blocking/SPIPE-acceptor.cpp b/ACE/examples/Connection/blocking/SPIPE-acceptor.cpp new file mode 100644 index 00000000000..8885b0353cd --- /dev/null +++ b/ACE/examples/Connection/blocking/SPIPE-acceptor.cpp @@ -0,0 +1,224 @@ +// $Id$ + +#if !defined (SPIPE_ACCEPTOR_C) +#define SPIPE_ACCEPTOR_C + +#include "ace/OS_NS_string.h" +#include "ace/SPIPE_Addr.h" +#include "ace/SPIPE_Acceptor.h" +#include "ace/Proactor.h" +#include "ace/Get_Opt.h" +#include "ace/Signal.h" +#include "SPIPE-acceptor.h" + +ACE_RCSID(blocking, SPIPE_acceptor, "$Id$") + +#if ((defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)) || (defined (ACE_HAS_AIO_CALLS))) + +Svc_Handler::Svc_Handler (void) + : mb_ (BUFSIZ + 1) +{ + // An extra byte for null termination. + this->mb_.size (BUFSIZ); +} + +Svc_Handler::~Svc_Handler (void) +{ +} + +int +Svc_Handler::open (void *) +{ + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("client connected on handle %d\n"), + this->peer ().get_handle ())); + if (this->ar_.open (*this, + this->peer ().get_handle ()) == -1) + return -1; + return this->ar_.read (this->mb_, + this->mb_.size ()); +} + +void +Svc_Handler::handle_read_stream (const ACE_Asynch_Read_Stream::Result &result) +{ + if (result.success () && result.bytes_transferred () > 0) + { + result.message_block ().rd_ptr ()[result.message_block ().length ()] = '\0'; + + // Print out the message received from the server. + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%t) message size %d.\n"), + result.message_block ().length ())); + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("%C"), + result.message_block ().rd_ptr ())); + // Reset the message block here to make sure multiple writes to + // the pipe don't keep appending to the message_block! + this->mb_.reset (); + + this->ar_.read (this->mb_, this->mb_.size ()); + } + else + ACE_Proactor::end_event_loop (); +} + +IPC_Server::IPC_Server (void) + : n_threads_ (1), + shutdown_ (0) +{ + ACE_OS::strcpy (rendezvous_, ACE_TEXT ("acepipe")); +} + +IPC_Server::~IPC_Server (void) +{ +} + +int +IPC_Server::handle_signal (int, + siginfo_t *, + ucontext_t *) +{ + ACE_LOG_MSG->log (LM_INFO, ACE_TEXT ("IPC_Server::handle_signal().\n")); + + // Flag the main <svc> loop to shutdown. + this->shutdown_ = 1; + + this->acceptor ().close (); // Close underlying acceptor. + // This should cause the <accept> to fail, which will "bounce" + // us out of the loop in <svc>. + return 0; +} + +int +IPC_Server::init (int argc, ACE_TCHAR *argv[]) +{ + if (this->parse_args (argc, argv) == -1) + return -1; + + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Opening %s\n"), rendezvous_)); + + // Initialize named pipe listener. + if (this->open (ACE_SPIPE_Addr (rendezvous_)) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("open")), 1); + + // Register to receive shutdowns using this handler. + else if (ACE_Reactor::instance ()->register_handler + (SIGINT, this) == -1) + return -1; + else + return 0; +} + +int +IPC_Server::fini (void) +{ + return 0; +} + +int +IPC_Server::parse_args (int argc, ACE_TCHAR *argv[]) +{ + ACE_LOG_MSG->open (argv[0]); + + ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("ut:r:")); + + for (int c; (c = get_opt ()) != -1; ) + { + switch (c) + { + case 'r': + ACE_OS::strncpy (rendezvous_, + get_opt.opt_arg (), + sizeof (rendezvous_) / sizeof (ACE_TCHAR)); + break; + case 't': + n_threads_ = ACE_OS::atoi (get_opt.opt_arg ()); + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("%s == %d.\n"), + get_opt.opt_arg (), + n_threads_)); + ACE_Proactor::instance (2 * n_threads_); + // This is a lame way to tell the proactor how many threads + // we'll be using. + break; + case 'u': + default: + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("usage: %n -t <threads>\n") + ACE_TEXT (" -r <rendezvous>\n")), -1); + break; + } + } + + return 0; +} + +static ACE_THR_FUNC_RETURN +run_reactor_event_loop (void *) +{ + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) worker thread starting\n"))); + + ACE_Proactor::run_event_loop (); + return 0; +} + +int +IPC_Server::svc (void) +{ + // Performs the iterative server activities. + while (this->shutdown_ == 0) + { + Svc_Handler sh; + + // Create a new SH endpoint, which performs all processing in + // its open() method (note no automatic restart if errno == + // EINTR). + if (this->accept (&sh, 0) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("accept")), + 1); + + // SH's destructor closes the stream implicitly but the + // listening endpoint stays open. + else + { + // Run single-threaded. + if (n_threads_ <= 1) + run_reactor_event_loop (0); + else if (ACE_Thread_Manager::instance ()->spawn_n + (n_threads_, + run_reactor_event_loop, + 0, + THR_NEW_LWP) == -1) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("spawn_n")), + 1); + + ACE_Thread_Manager::instance ()->wait (); + } + + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) main thread exiting.\n"))); + + // Reset the Proactor so another accept will work. + ACE_Proactor::reset_event_loop(); + + // Must use some other method now to terminate this thing + // instead of the ACE_Signal_Adapter just running + // ACE_Proactor::end_event_loop()... Since this is an + // ACE_Event_Handler, doesn't it seem possible to implement + // a handle_signal() hook, and catch the signal there? + } + } + + /* NOTREACHED */ + return 0; +} + +#endif /* ACE_WIN32 || ACE_HAS_AIO_CALLS*/ +#endif /* SPIPE_ACCEPTOR_C */ + diff --git a/ACE/examples/Connection/blocking/SPIPE-acceptor.h b/ACE/examples/Connection/blocking/SPIPE-acceptor.h new file mode 100644 index 00000000000..546941c48fb --- /dev/null +++ b/ACE/examples/Connection/blocking/SPIPE-acceptor.h @@ -0,0 +1,79 @@ +/* -*- C++ -*- */ +// $Id$ + +#ifndef SP_ACCEPTOR_H +#define SP_ACCEPTOR_H + +#include "ace/Svc_Handler.h" +#include "ace/Service_Config.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Acceptor.h" +#include "ace/SPIPE_Stream.h" +#include "ace/SPIPE_Acceptor.h" +#include "ace/Asynch_IO.h" + +// This only works on Win32 platforms and on Unix platforms +// supporting POSIX aio calls. +#if ((defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)) || (defined (ACE_HAS_AIO_CALLS))) + +// This is the class that does the work once the ACE_Oneshot_Acceptor +// has accepted a connection. + +class Svc_Handler : public ACE_Svc_Handler <ACE_SPIPE_STREAM, ACE_NULL_SYNCH>, public ACE_Handler +{ +public: + Svc_Handler (void); + ~Svc_Handler (void); + + virtual int open (void *); + + virtual void handle_read_stream (const ACE_Asynch_Read_Stream::Result &result); + // This is called when asynchronous read from the socket complete + // Handle data from the client. + +private: + ACE_Asynch_Read_Stream ar_; + ACE_Message_Block mb_; +}; + +class IPC_Server : public ACE_Oneshot_Acceptor<Svc_Handler, ACE_SPIPE_ACCEPTOR> +{ +public: + IPC_Server (void); + ~IPC_Server (void); + + // = Dynamic linking hooks. + virtual int init (int argc, ACE_TCHAR *argv[]); + // Initialize the network server. + + virtual int fini (void); + // Close down the server. + + virtual int svc (void); + // Run the interative service. + +private: + int parse_args (int argc, ACE_TCHAR *argv[]); + // Parse command-line arguments. + + int n_threads_; + // Size of thread pool to use. + + ACE_TCHAR rendezvous_[MAXPATHLEN + 1]; + // Meeting place for pipe. + + int shutdown_; + // Keeps track of when we shut down due to receipt of the SIGINT + // signal. + + int handle_signal (int signum, siginfo_t *, ucontext_t *); + // Signal handler method. +}; + +#endif /* ACE_WIN32 || ACE_HAS_AIO_CALLS*/ +#endif /* SP_ACCEPTOR_H */ + diff --git a/ACE/examples/Connection/blocking/SPIPE-connector.cpp b/ACE/examples/Connection/blocking/SPIPE-connector.cpp new file mode 100644 index 00000000000..6618b64f0cb --- /dev/null +++ b/ACE/examples/Connection/blocking/SPIPE-connector.cpp @@ -0,0 +1,219 @@ +// $Id$ + +#if !defined (SPIPE_CONNECTOR_C) + +#define SPIPE_CONNECTOR_C + +#include "ace/OS_NS_string.h" +#include "ace/SPIPE_Addr.h" +#include "ace/SPIPE_Connector.h" +#include "ace/Proactor.h" +#include "ace/Get_Opt.h" +#include "ace/OS_NS_unistd.h" +#include "SPIPE-connector.h" + +ACE_RCSID(blocking, SPIPE_connector, "$Id$") + +Peer_Handler::Peer_Handler (int iterations) + : iterations_ (iterations) +{ +} + +Peer_Handler::~Peer_Handler (void) +{ +} + +int +Peer_Handler::open (void *) +{ + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("activating %d\n"), this->get_handle ())); + + // If iterations_ has not been set, read from stdin. + if (iterations_ == 0) + { + this->display_menu (); + if (ACE_Event_Handler::register_stdin_handler + (this, + ACE_Reactor::instance (), + ACE_Thread_Manager::instance ()) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("register_stdin_handler")), + -1); + else + return 0; + } + else // If iterations_ has been set, send iterations_ buffers. + { + const char *buffer = + "Oh give me a home\n" + "Where the buffalo roam,\n" + "And the deer and the antelope play.\n" + "Where seldom is heard\n" + "A discouraging word,\n" + "And the skies are not cloudy all day.\n"; + int length = ACE_OS::strlen (buffer); + + while (iterations_-- > 0 + && this->peer ().send_n (buffer, + length) == length) + continue; + + this->peer ().close (); + ACE_Reactor::instance ()->end_reactor_event_loop(); + return 0; + } +} + +int +Peer_Handler::handle_input (ACE_HANDLE) +{ + char buf[BUFSIZ]; + + ssize_t n = ACE_OS::read (ACE_STDIN, + buf, + sizeof buf); + + if (n > 0) + if (this->peer ().send (buf, n) != n) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("write failed")), + -1); + else if (n == 0) // Explicitly close the connection. + { + if (this->peer ().close () == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("close")), + 1); + return -1; + } + else + this->display_menu (); + return 0; +} + +int +Peer_Handler::handle_close (ACE_HANDLE, + ACE_Reactor_Mask) +{ + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Shutting down\n"))); + return 0; +} + +ACE_HANDLE +Peer_Handler::get_handle (void) const +{ + return this->peer ().get_handle (); +} + +void +Peer_Handler::display_menu (void) +{ + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\nplease enter input..: "))); +} + +IPC_Client::IPC_Client (void) + : iterations_ (0), + done_handler_ (ACE_Sig_Handler_Ex (ACE_Proactor::end_event_loop)) +{ + ACE_OS::strcpy (rendezvous_, ACE_TEXT ("acepipe")); +} + +IPC_Client::~IPC_Client (void) +{ +} + +// Dynamic linking hooks. + +int +IPC_Client::init (int argc, ACE_TCHAR *argv[]) +{ + if (this->parse_args (argc, argv) == -1) + return -1; + // Handle signals through the ACE_Reactor. + else if (ACE_Reactor::instance ()->register_handler + (SIGINT, + &this->done_handler_) == -1) + return -1; + + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Opening %s\n"), rendezvous_)); + + Peer_Handler *ph; + + ACE_NEW_RETURN (ph, + Peer_Handler (iterations_), + -1); + + // Connect to the peer, reusing the local addr if necessary. + if (this->connect (ph, + ACE_SPIPE_Addr (rendezvous_), + ACE_Synch_Options::defaults, + ACE_sap_any_cast (ACE_SPIPE_Addr &), + 0, + O_RDWR | FILE_FLAG_OVERLAPPED, + 0) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("connect")), + -1); + + return 0; +} + +int +IPC_Client::fini (void) +{ + return 0; +} + +int +IPC_Client::svc (void) +{ + ACE_Reactor::instance ()->run_reactor_event_loop (); + return 0; +} + +int +IPC_Client::handle_close (ACE_HANDLE, + ACE_Reactor_Mask) +{ + return 0; +} + +int +IPC_Client::parse_args (int argc, ACE_TCHAR *argv[]) +{ + ACE_LOG_MSG->open (argv[0]); + + ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("ui:r:")); + + for (int c; (c = get_opt ()) != -1; ) + { + switch (c) + { + case 'r': + ACE_OS::strncpy (rendezvous_, + get_opt.opt_arg (), + sizeof (rendezvous_) / sizeof (ACE_TCHAR)); + break; + case 'i': + iterations_ = ACE_OS::atoi (get_opt.opt_arg ()); + break; + case 'u': + default: + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("usage: %n -i <iterations>\n") + ACE_TEXT ("-r <rendezvous>\n")), + -1); + break; + } + } + + return 0; +} + + +#endif /* SPIPE_CONNECTOR */ + diff --git a/ACE/examples/Connection/blocking/SPIPE-connector.h b/ACE/examples/Connection/blocking/SPIPE-connector.h new file mode 100644 index 00000000000..66d6ea0d1ed --- /dev/null +++ b/ACE/examples/Connection/blocking/SPIPE-connector.h @@ -0,0 +1,82 @@ +/* -*- C++ -*- */ +// $Id$ + +#ifndef SP_CONNECTOR_H +#define SP_CONNECTOR_H + +#include "ace/Svc_Handler.h" +#include "ace/Service_Config.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/SPIPE_Stream.h" +#include "ace/Connector.h" +#include "ace/SPIPE_Connector.h" +#include "ace/Sig_Adapter.h" + +class Peer_Handler : public ACE_Svc_Handler<ACE_SPIPE_STREAM, ACE_NULL_SYNCH> +{ +public: + // = Initialization + + Peer_Handler (int iterations = 0); + // <iterations> is the number of buffers to send. If <iterations> + // == 0, then read from stdin. + + ~Peer_Handler (void); + + virtual int open (void * = 0); + // Activate the handler when connection is established. + + // = Demultiplexing hooks. + virtual int handle_input (ACE_HANDLE); + virtual int handle_close (ACE_HANDLE handle = ACE_INVALID_HANDLE, + ACE_Reactor_Mask mask = ACE_Event_Handler::ALL_EVENTS_MASK); + + virtual ACE_HANDLE get_handle (void) const; + +private: + void display_menu (void); + + int iterations_; + // No. of buffers to send. +}; + +class IPC_Client : public ACE_Connector<Peer_Handler, ACE_SPIPE_CONNECTOR> +{ +public: + // Initialization + IPC_Client (void); + ~IPC_Client (void); + + // = Dynamic linking hooks. + virtual int init (int argc, ACE_TCHAR *argv[]); + // Initialize the IPC client. + + virtual int fini (void); + // Destroy the IPC client. + + virtual int svc (void); + // Run the svc. + + virtual int handle_close (ACE_HANDLE, ACE_Reactor_Mask); + // Report connection errors. + +private: + int parse_args (int argc, ACE_TCHAR *argv[]); + // Parse command-line arguments. + + int iterations_; + // Number of times to send a buffer. + + ACE_TCHAR rendezvous_[MAXPATHLEN + 1]; + // Meeting place for pipe. + + ACE_Sig_Adapter done_handler_; + // Keeps track of when we shut down due to receipt of the SIGINT + // signal. +}; + +#endif /* SP_CONNECTOR_H */ diff --git a/ACE/examples/Connection/blocking/test_spipe_acceptor.cpp b/ACE/examples/Connection/blocking/test_spipe_acceptor.cpp new file mode 100644 index 00000000000..549690ebf43 --- /dev/null +++ b/ACE/examples/Connection/blocking/test_spipe_acceptor.cpp @@ -0,0 +1,36 @@ +// $Id$ + +// ACE_SPIPE Server. + +#include "SPIPE-acceptor.h" + +ACE_RCSID(blocking, test_spipe_acceptor, "$Id$") + +#if ((defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)) || (defined (ACE_HAS_AIO_CALLS))) + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + // Perform Service_Config initializations + ACE_Service_Config daemon (argv[0]); + + IPC_Server peer_acceptor; + + if (peer_acceptor.init (argc, argv) == -1) + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("init")), -1); + + return peer_acceptor.svc (); +} + +#else + +int +main (int, char *[]) +{ + ACE_DEBUG ((LM_INFO, + ACE_TEXT ("Asynchronous IO is unsupported.\n"))); + + return 0; +} + +#endif diff --git a/ACE/examples/Connection/blocking/test_spipe_connector.cpp b/ACE/examples/Connection/blocking/test_spipe_connector.cpp new file mode 100644 index 00000000000..e10cc023a6f --- /dev/null +++ b/ACE/examples/Connection/blocking/test_spipe_connector.cpp @@ -0,0 +1,21 @@ +// $Id$ + +// ACE_SPIPE Client. + +#include "SPIPE-connector.h" + +ACE_RCSID(blocking, test_spipe_connector, "$Id$") + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + // Perform Service_Config initializations + ACE_Service_Config daemon (argv[0]); + + IPC_Client peer_connector; + + if (peer_connector.init (argc, argv) == -1) + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("init")), -1); + + return peer_connector.svc (); +} diff --git a/ACE/examples/Connection/misc/.cvsignore b/ACE/examples/Connection/misc/.cvsignore new file mode 100644 index 00000000000..444ad7e1b3a --- /dev/null +++ b/ACE/examples/Connection/misc/.cvsignore @@ -0,0 +1,4 @@ +handler +handler +test_upipe +test_upipe diff --git a/ACE/examples/Connection/misc/Connection_Handler.cpp b/ACE/examples/Connection/misc/Connection_Handler.cpp new file mode 100644 index 00000000000..6abc0ee8050 --- /dev/null +++ b/ACE/examples/Connection/misc/Connection_Handler.cpp @@ -0,0 +1,226 @@ +// $Id$ + +// ============================================================================ +// +// = FILENAME +// Connection_Handler.cpp +// +// = DESCRIPTION +// This test illustrates how to use the Acceptor pattern to +// create multiple threads, each running its own Reactor. You +// can connect to this via telnet and keep typing until you enter +// '^D'. +// +// = AUTHOR +// Doug Schmidt +// +// ============================================================================ + +#include "ace/Acceptor.h" +#include "ace/SOCK_Acceptor.h" +#include "ace/Service_Config.h" +#include "ace/Thread.h" +#include "ace/Sig_Adapter.h" + +#include "Connection_Handler.h" + +ACE_RCSID(misc, Connection_Handler, "$Id$") + +int +Connection_Handler::open (void *) +{ + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) in open()\n"))); + + // Make ourselves an Active Object. + return this->activate (THR_NEW_LWP | THR_DETACHED); +} + +int +Connection_Handler::close (u_long) +{ + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) in close()\n"))); + + // Shut ourself down. Note that this doesn't destroy the thread, + // just the state of the object. + this->destroy (); + return 0; +} + +int +Connection_Handler::svc (void) +{ + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) in svc()\n"))); + + this->finished_ = 0; + + // Create our own personal Reactor just for this thread. Note that + // we create this on the stack of the thread since it's only used + // for the duration of this connection! + + ACE_Reactor reactor; + + // Each <ACE_Svc_Handler> has its own <ACE_Reactor *>. By default, + // this points to the <Acceptor's> Reactor. However, we can point + // it to our local Reactor, which is what we do in this case. + this->reactor (&reactor); + + // Register ourselves to handle input in this thread without + // blocking. + if (this->reactor ()->register_handler + (this, ACE_Event_Handler::READ_MASK) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("can' (%P|%t) t register with reactor\n")), + -1); + // Schedule a timer. + else if (this->reactor ()->schedule_timer (this, + (const void *) this, + ACE_Time_Value (2), + ACE_Time_Value (2)) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("(%P|%t) can't register with reactor\n")), + -1); + else + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) connected with client\n"))); + + // Keep looping until we receive SIGQUIT or the client shutsdown. + + while (this->finished_ == 0) + { + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) handling events\n"))); + this->reactor ()->handle_events (); + } + + // Cancel all pending timeouts. + this->reactor ()->cancel_timer (this); + + // Remove ourselves from the Reactor. + this->reactor ()->remove_handler + (this, ACE_Event_Handler::READ_MASK | ACE_Event_Handler::DONT_CALL); + + // Zero-out the Reactor field so it isn't accessed later on. + this->reactor (0); + + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) exiting svc\n"))); + return 0; +} + +int +Connection_Handler::handle_close (ACE_HANDLE, + ACE_Reactor_Mask) +{ + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) in handle_close \n"))); + + // Signal the svc() event loop to shut down. + this->finished_ = 1; + return 0; +} + +int +Connection_Handler::handle_input (ACE_HANDLE) +{ + char buf[BUFSIZ]; + + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) handle_input\n"))); + + switch (this->peer ().recv (buf, sizeof buf)) + { + case -1: + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("(%P|%t) %p bad read\n"), + ACE_TEXT ("client logger")), + -1); + case 0: + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("(%P|%t) closing log daemon (fd = %d)\n"), + this->get_handle ()), + -1); + default: + if (buf[0] == (char) EOF) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("(%P|%t) closing log daemon (fd = %d)\n"), + this->get_handle ()), + -1); + else + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) from client: %s"), buf)); + } + + return 0; +} + +int +Connection_Handler::handle_signal (int signum, + siginfo_t *, + ucontext_t *) +{ + // @@ Note that this code is not portable to all OS platforms since + // it uses print statements within signal handler context. + + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("received signal %S\n"), signum)); + + this->finished_ = 1; + return 0; +} + +int +Connection_Handler::handle_timeout (const ACE_Time_Value &, + const void *arg) +{ +#if defined (ACE_NDEBUG) + ACE_UNUSED_ARG (arg); +#endif /* ACE_NDEBUG */ + + ACE_ASSERT (arg == this); + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) handling timeout from this = %@\n"), + this)); + return 0; +} + +// Define an Acceptor for the <Connection_Handler>. + +typedef ACE_Acceptor <Connection_Handler, ACE_SOCK_ACCEPTOR> + Connection_Acceptor; + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + ACE_Service_Config daemon (argv[0]); + + u_short port = argc > 1 ? ACE_OS::atoi (argv[1]) : ACE_DEFAULT_SERVER_PORT; + + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) in main\n"))); + + // Acceptor factory. + Connection_Acceptor peer_acceptor; + + // Create an adapter to end the event loop. + ACE_Sig_Adapter sa ((ACE_Sig_Handler_Ex) ACE_Reactor::end_event_loop); + + // Register the signal handler adapter. + if (ACE_Reactor::instance ()->register_handler (SIGINT, &sa) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("register_handler")), + -1); + + // Open the Acceptor. + else if (peer_acceptor.open (ACE_INET_Addr (port), + ACE_Reactor::instance ()) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("open")), + -1); + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) starting up connection server\n"))); + + // Perform connection service until we receive SIGINT. + + while (ACE_Reactor::event_loop_done() == 0) + ACE_Reactor::run_event_loop (); + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) shutting down connection server\n"))); + return 0; +} + diff --git a/ACE/examples/Connection/misc/Connection_Handler.h b/ACE/examples/Connection/misc/Connection_Handler.h new file mode 100644 index 00000000000..2e22ac8dc11 --- /dev/null +++ b/ACE/examples/Connection/misc/Connection_Handler.h @@ -0,0 +1,44 @@ +/* -*- C++ -*- */ + +// $Id$ + +#ifndef ACE_CONNECTION_HANDLER_H +#define ACE_CONNECTION_HANDLER_H + +#include "ace/SOCK_Stream.h" +#include "ace/Svc_Handler.h" + +class Connection_Handler : public ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH> +{ +public: + virtual int open (void *); + // Initialize the <Connection_Handler> and make it an Active Object. + + virtual int close (u_long); + // Terminate the <Connection_Handler>. + + virtual int svc (void); + // Run the <Connection_Handler>'s main event loop. + +protected: + virtual int handle_close (ACE_HANDLE, + ACE_Reactor_Mask); + // Signal the Active Object to stop when called. + + virtual int handle_input (ACE_HANDLE); + // Handle input from the client. + + virtual int handle_timeout (const ACE_Time_Value &tv, + const void *arg); + // Handle timeouts. + + virtual int handle_signal (int signum, + siginfo_t *, + ucontext_t *); + // Handle timeouts. + + sig_atomic_t finished_; + // Keeps track of whether we're done. +}; + +#endif /* ACE_CONNECTION_HANDLER_H */ diff --git a/ACE/examples/Connection/misc/Connection_Misc.mpc b/ACE/examples/Connection/misc/Connection_Misc.mpc new file mode 100644 index 00000000000..a960e604338 --- /dev/null +++ b/ACE/examples/Connection/misc/Connection_Misc.mpc @@ -0,0 +1,17 @@ +// -*- MPC -*- +// $Id$ + +project (*Handler) : aceexe { + exename = handler + Source_Files { + Connection_Handler.cpp + } +} + +project (*test_upipe) : aceexe { + avoids += ace_for_tao + exename = test_upipe + Source_Files { + test_upipe.cpp + } +} diff --git a/ACE/examples/Connection/misc/Makefile.am b/ACE/examples/Connection/misc/Makefile.am new file mode 100644 index 00000000000..ce3790d2851 --- /dev/null +++ b/ACE/examples/Connection/misc/Makefile.am @@ -0,0 +1,53 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +ACE_BUILDDIR = $(top_builddir) +ACE_ROOT = $(top_srcdir) + + +## Makefile.Connection_Misc_Handler.am +noinst_PROGRAMS = handler + +handler_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +handler_SOURCES = \ + Connection_Handler.cpp \ + Connection_Handler.h + +handler_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Connection_Misc_Test_Upipe.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS += test_upipe + +test_upipe_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +test_upipe_SOURCES = \ + test_upipe.cpp \ + test_upipe.h + +test_upipe_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Clean up template repositories, etc. +clean-local: + -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.* + -rm -f gcctemp.c gcctemp so_locations *.ics + -rm -rf cxx_repository ptrepository ti_files + -rm -rf templateregistry ir.out + -rm -rf ptrepository SunWS_cache Templates.DB diff --git a/ACE/examples/Connection/misc/test_upipe.cpp b/ACE/examples/Connection/misc/test_upipe.cpp new file mode 100644 index 00000000000..23c85b283a3 --- /dev/null +++ b/ACE/examples/Connection/misc/test_upipe.cpp @@ -0,0 +1,122 @@ +// $Id$ + +// This short program illustrates in implementation of the classic +// "bounded buffer" program using ACE_UPIPEs. This program also shows +// how the ACE_Connector and ACE_Acceptor patterns work when used with +// ACE_UPIPEs. + +#include "ace/Acceptor.h" +#include "ace/UPIPE_Acceptor.h" +#include "ace/UPIPE_Connector.h" +#include "ace/Connector.h" +#include "ace/UPIPE_Addr.h" + +ACE_RCSID(misc, test_upipe, "$Id$") + +#if defined (ACE_HAS_THREADS) + +#include "test_upipe.h" + +class Server : public ACE_Strategy_Acceptor <Server_Service, ACE_UPIPE_ACCEPTOR> +{ + // = TITLE + // Defines the interface for a factory that accepts connections + // and creates/activates Server_Service objects. +public: + Server (ACE_Thread_Manager *thr_mgr, + ACE_Reactor *reactor) + : reactor_ (reactor), + thr_mgr_ (thr_mgr) + { + ACE_TRACE ("Server::Server"); + } + + virtual int init (int argc, ACE_TCHAR *argv[]) + { + ACE_TRACE ("Server::init"); + const ACE_TCHAR *l_addr = argc > 1 ? argv[1] : ACE_DEFAULT_RENDEZVOUS; + + ACE_UPIPE_Addr local_addr (l_addr); + + if (this->thr_strategy_.open (this->thr_mgr_, THR_DETACHED | THR_NEW_LWP) == -1) + return -1; + else if (this->open (local_addr, this->reactor_, + 0, 0, &this->thr_strategy_) == -1) + return -1; + + // Give server a chance to register the STREAM pipe. + ACE_OS::sleep (ACE_Time_Value (4)); + return 0; + } + +private: + ACE_Reactor *reactor_; + // Our instance of the reactor. + + ACE_Thread_Manager *thr_mgr_; + // Our instance of a thread manager. + + ACE_Thread_Strategy<Server_Service> thr_strategy_; + // Our concurrency strategy. +}; + +class Client : public ACE_Connector <Client_Service, ACE_UPIPE_CONNECTOR> +{ + // = TITLE + // Defines the interface for a factory that connects + // a Client_Service with a Server. +public: + Client (ACE_Thread_Manager *thr_mgr) + : thr_mgr_ (thr_mgr) + { + ACE_TRACE ("Client::Client"); + } + + virtual int init (int argc, ACE_TCHAR *argv[]) + { + ACE_TRACE ("Client::init"); + + const ACE_TCHAR *r_addr = argc > 1 ? argv[1] : ACE_DEFAULT_RENDEZVOUS; + + ACE_UPIPE_Addr remote_addr (r_addr); + + Client_Service *cs; + + ACE_NEW_RETURN (cs, Client_Service (this->thr_mgr_), -1); + + return this->connect (cs, remote_addr); + } + +private: + ACE_Thread_Manager *thr_mgr_; +}; + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + ACE_Service_Config svc_conf; + ACE_Thread_Manager thr_mgr; + + Client peer_connector (&thr_mgr); + Server peer_acceptor (&thr_mgr, ACE_Reactor::instance ()); + + // Establish the connection between Acceptor and Connector. + + if (peer_acceptor.init (argc, argv) == -1) + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("init")), -1); + else if (peer_connector.init (argc, argv) == -1) + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("init")), -1); + + // Wait for threads to exit. + thr_mgr.wait (); + return 0; +} +#else +int +main (int, char *[]) +{ + ACE_ERROR_RETURN ((LM_ERROR, + "your platform does not support threads\n"), + 1); +} +#endif /* ACE_HAS_THREADS */ diff --git a/ACE/examples/Connection/misc/test_upipe.h b/ACE/examples/Connection/misc/test_upipe.h new file mode 100644 index 00000000000..89349760e9c --- /dev/null +++ b/ACE/examples/Connection/misc/test_upipe.h @@ -0,0 +1,76 @@ +/* -*- C++ -*- */ + +// $Id$ + +#ifndef ACE_TEST_UPIPE_H +#define ACE_TEST_UPIPE_H + +#include "ace/OS_NS_unistd.h" +#include "ace/Svc_Handler.h" +#include "ace/Service_Config.h" +#include "ace/UPIPE_Stream.h" + +typedef ACE_Svc_Handler <ACE_UPIPE_STREAM, ACE_NULL_SYNCH> SVC_HANDLER; + +class Server_Service : public SVC_HANDLER + // = TITLE + // Defines the interface for a service that recvs data from its + // client and writes the data to its stdout. +{ +public: + Server_Service (ACE_Thread_Manager * = 0) {} + + virtual int open (void *) + { + ACE_TRACE ("Server_Service::open"); + return 0; + } + + virtual int svc (void) + { + ACE_TRACE ("Server_Service::svc"); + + char buf[BUFSIZ]; + ssize_t n; + + while ((n = this->peer ().recv (buf, sizeof buf)) > 0) + ::write (1, buf, n); + + return 0; + } +}; + + +class Client_Service : public SVC_HANDLER + // = TITLE + // Defines the interface for a service that recvs data from its + // stdin and forward the data to its server. +{ +public: + Client_Service (ACE_Thread_Manager *thr_mgr = 0) + : SVC_HANDLER (thr_mgr) + { + ACE_TRACE ("Client_Service::Client_Service"); + } + + virtual int open (void *) + { + ACE_TRACE ("Client_Service::open"); + return this->activate (THR_DETACHED | THR_NEW_LWP); + } + + virtual int svc (void) + { + ACE_TRACE ("Client_Service::svc"); + char buf[BUFSIZ]; + ssize_t n; + + while ((n = ACE_OS::read (ACE_STDIN, buf, sizeof buf)) > 0) + this->peer ().send (buf, n); + + this->peer ().close (); + return 0; + } +}; + +#endif /* ACE_TEST_UPIPE_H */ diff --git a/ACE/examples/Connection/non_blocking/.cvsignore b/ACE/examples/Connection/non_blocking/.cvsignore new file mode 100644 index 00000000000..0cbd7c83956 --- /dev/null +++ b/ACE/examples/Connection/non_blocking/.cvsignore @@ -0,0 +1,16 @@ +lsock_client +lsock_client +lsock_server +lsock_server +sock_client +sock_client +sock_server +sock_server +spipe_client +spipe_client +spipe_server +spipe_server +tli_client +tli_client +tli_server +tli_server diff --git a/ACE/examples/Connection/non_blocking/CPP-acceptor.cpp b/ACE/examples/Connection/non_blocking/CPP-acceptor.cpp new file mode 100644 index 00000000000..12c80c1d939 --- /dev/null +++ b/ACE/examples/Connection/non_blocking/CPP-acceptor.cpp @@ -0,0 +1,247 @@ +// $Id$ + +#if !defined (CPP_ACCEPTOR_C) + +#define CPP_ACCEPTOR_C + +#include "ace/Service_Config.h" +#include "CPP-acceptor.h" +#include "ace/OS_NS_unistd.h" +#include "ace/Signal.h" + +ACE_RCSID(non_blocking, CPP_acceptor, "$Id$") + +#define PR_ST_1 ACE_PEER_STREAM_1 +#define PR_ST_2 ACE_PEER_STREAM_2 +#define PR_AC_1 ACE_PEER_ACCEPTOR_1 +#define PR_AC_2 ACE_PEER_ACCEPTOR_2 +#define PR_AD ACE_PEER_STREAM_ADDR +#define SVH SVC_HANDLER + +template <PR_ST_1> +Svc_Handler<PR_ST_2>::Svc_Handler (ACE_Reactor *r) + : SVC_HANDLER (0, 0, r) +{ +} + +template <PR_ST_1> int +Svc_Handler<PR_ST_2>::close (u_long) +{ + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("calling Svc_Handler close\n"))); + + // Free up the handle. + this->peer ().close (); + return 0; +} + +template <PR_ST_1> int +Svc_Handler<PR_ST_2>::open (void *) +{ + PR_AD client_addr; + ACE_TCHAR buf[BUFSIZ]; + + if (this->peer ().get_remote_addr (client_addr) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("get_remote_addr")), + -1); + else if (client_addr.addr_to_string (buf, + sizeof buf) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("addr_to_string")), + -1); + else + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("client addr %s on handle %d\n"), + buf, + this->peer ().get_handle ())); + + // Process the connection immediately since we are an interative + // server. + return this->handle_input (); +} + +// Receive and process the data from the client. + +template <PR_ST_1> int +Svc_Handler<PR_ST_2>::handle_input (ACE_HANDLE) +{ + char buf[BUFSIZ]; + + // Read data from client (terminate on error). + + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) in handle_input\n"))); + + for (ssize_t r_bytes; + (r_bytes = this->peer ().recv (buf, + sizeof buf)) > 0; + ) + if (ACE_OS::write (ACE_STDOUT, + buf, + r_bytes) != r_bytes) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("ACE::send_n")), + -1); + // Send back ack. + if (this->peer ().send_n ("", + 1) != 1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("send_n")), + -1); + return 0; +} + +template <PR_ST_1> int +Svc_Handler<PR_ST_2>::handle_timeout (const ACE_Time_Value &, + const void *) +{ + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("%p\n"), ACE_TEXT ("handle_timeout"))); + return 0; +} + +template <class SVH, PR_AC_1> int +IPC_Server<SVH, PR_AC_2>::init (int argc, ACE_TCHAR *argv[]) +{ + const ACE_TCHAR *local_addr = argc > 1 + ? argv[1] + : ACE_DEFAULT_SERVER_PORT_STR; + ACE_Time_Value timeout (argc > 2 + ? ACE_OS::atoi (argv[2]) + : ACE_DEFAULT_TIMEOUT); + int use_reactor = argc > 3 + ? ACE_Synch_Options::USE_REACTOR + : 0; + + this->options_.set (ACE_Synch_Options::USE_TIMEOUT | use_reactor, + timeout); + + if (this->server_addr_.set (local_addr) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("set")), + -1); + // Call down to the ACCEPTOR's <open> method to do the + // initialization. + if (this->inherited::open (this->server_addr_, + use_reactor + ? ACE_Reactor::instance () + : 0) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("open")), + -1); + // Handle the SIGINT signal through the <ACE_Reactor>. + else if (ACE_Reactor::instance ()->register_handler + (SIGINT, + &this->done_handler_) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("register_handler")), + -1); +#if !defined (ACE_WIN32) + // Handle the SIGPIPE signal through the <ACE_Reactor>. + else if (ACE_Reactor::instance ()->register_handler + (SIGPIPE, + &this->done_handler_) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("register_handler")), + -1); +#endif /* ACE_WIN32 */ + else + return 0; +} + +template <class SVH, PR_AC_1> +IPC_Server<SVH, PR_AC_2>::IPC_Server (void) + : done_handler_ (ACE_Sig_Handler_Ex (ACE_Reactor::end_event_loop)) +{ +} + +template <class SVH, PR_AC_1> int +IPC_Server<SVH, PR_AC_2>::fini (void) +{ + return 0; +} + +template <class SVH, PR_AC_1> +IPC_Server<SVH, PR_AC_2>::~IPC_Server (void) +{ +} + +template <class SVH, PR_AC_1> int +IPC_Server<SVH, PR_AC_2>::handle_close (ACE_HANDLE handle, + ACE_Reactor_Mask mask) +{ + ACE_UNUSED_ARG (handle); + ACE_UNUSED_ARG (mask); + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("calling IPC_Server handle_close, but accept handle stays open!\n"))); + return 0; +} + +// Run the interative service. + +template <class SVH, PR_AC_1> int +IPC_Server<SVH, PR_AC_2>::svc (void) +{ + ACE_TCHAR buf[BUFSIZ]; + + if (this->server_addr_.addr_to_string (buf, + sizeof buf) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("addr_to_string")), + -1); + else + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("starting server addr %s on handle %d\n"), + buf, + this->get_handle ())); + + // Performs the iterative server activities. + + while (ACE_Reactor::event_loop_done () == 0) + { + SVH sh (this->reactor ()); + + // Create a new <SVH> endpoint, which performs all processing in + // its <open> method (note no automatic restart if errno == + // EINTR). + + if (this->accept (&sh, + 0, + this->options_, + 0) == -1) + { + if (errno == EWOULDBLOCK + && this->reactor ()) + // Handle the accept asynchronously if necessary. + this->reactor ()->handle_events (); + else + // We've probably timed out... + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("%p on handle %d\n"), + ACE_TEXT ("accept"), + this->acceptor ().get_handle ())); + } + + // <SVH>'s destructor closes the stream implicitly but the + // listening endpoint stays open. + } + + /* NOTREACHED */ + return 0; +} + +#undef PR_ST_1 +#undef PR_ST_2 +#undef PR_AC_1 +#undef PR_AC_2 +#undef PR_AD +#undef SVH +#endif /* CPP_ACCEPTOR_C */ diff --git a/ACE/examples/Connection/non_blocking/CPP-acceptor.h b/ACE/examples/Connection/non_blocking/CPP-acceptor.h new file mode 100644 index 00000000000..c06caf50b48 --- /dev/null +++ b/ACE/examples/Connection/non_blocking/CPP-acceptor.h @@ -0,0 +1,96 @@ +/* -*- C++ -*- */ +// $Id$ + +#ifndef CPP_ACCEPTOR_H +#define CPP_ACCEPTOR_H + +#include "ace/Acceptor.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Svc_Handler.h" +#include "ace/Sig_Adapter.h" + + +template <ACE_PEER_STREAM_1> +class Svc_Handler : public ACE_Svc_Handler <ACE_PEER_STREAM_2, ACE_NULL_SYNCH> +{ + // = TITLE + // This class does the work once the <ACE_Oneshot_Acceptor> has + // accepted a connection. +public: + // = Initialization method. + Svc_Handler (ACE_Reactor *r); + + virtual int open (void *); + // Perform the work of the SVC_HANDLER. + + virtual int handle_input (ACE_HANDLE = ACE_INVALID_HANDLE); + // Handle data from the client. + + virtual int close (u_long); + // Called if ACE_Svc_Handler is closed down unexpectedly. + + virtual int handle_timeout (const ACE_Time_Value &, const void *arg); + // Handles acceptor timeouts. + +private: + typedef ACE_Svc_Handler <ACE_PEER_STREAM_2, ACE_NULL_SYNCH> + SVC_HANDLER; +}; + +template <class SVC_HANDLER, ACE_PEER_ACCEPTOR_1> +class IPC_Server : public ACE_Oneshot_Acceptor<SVC_HANDLER, ACE_PEER_ACCEPTOR_2> +{ + // = TITLE + // This class illustrates how the <ACE_Oneshot_Acceptor> works. +public: + // = Initialization and termination. + IPC_Server (void); + // Constructor. + + ~IPC_Server (void); + // Destructor. + + // = Demultiplexing hooks. + virtual int handle_close (ACE_HANDLE handle, + ACE_Reactor_Mask mask); + // Make sure not to close down the <handle> if we're removed from + // the <Reactor>. + + // = Dynamic linking hooks. + virtual int init (int argc, ACE_TCHAR *argv[]); + // Initialize the network server. + + virtual int fini (void); + // Close down the server. + + virtual int svc (void); + // Run the interative service. + +private: + typedef ACE_Oneshot_Acceptor<SVC_HANDLER, ACE_PEER_ACCEPTOR_2> + inherited; + + ACE_PEER_ACCEPTOR_ADDR server_addr_; + // Address of this server. + + ACE_Synch_Options options_; + // Options that this server is using. + + ACE_Sig_Adapter done_handler_; + // Keeps track of when we shut down due to receipt of the SIGINT + // signal. +}; + +#if defined (ACE_TEMPLATES_REQUIRE_SOURCE) +#include "CPP-acceptor.cpp" +#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */ + +#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA) +#pragma implementation ("CPP-acceptor.cpp") +#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */ + +#endif /* CPP_ACCEPTOR_H */ diff --git a/ACE/examples/Connection/non_blocking/CPP-connector.cpp b/ACE/examples/Connection/non_blocking/CPP-connector.cpp new file mode 100644 index 00000000000..e113b5f5acb --- /dev/null +++ b/ACE/examples/Connection/non_blocking/CPP-connector.cpp @@ -0,0 +1,289 @@ +// $Id$ + +#if !defined (CPP_CONNECTOR_C) +#define CPP_CONNECTOR_C + +#include "CPP-connector.h" +#include "ace/OS_NS_stdio.h" +#include "ace/OS_NS_unistd.h" +#include "ace/Signal.h" + +ACE_RCSID(non_blocking, CPP_connector, "$Id$") + +#define PR_ST_1 ACE_PEER_STREAM_1 +#define PR_ST_2 ACE_PEER_STREAM_2 +#define PR_CO_1 ACE_PEER_CONNECTOR_1 +#define PR_CO_2 ACE_PEER_CONNECTOR_2 +#define PR_AD ACE_PEER_CONNECTOR_ADDR +#define SVH SVC_HANDLER + +template <PR_ST_1> +Peer_Handler<PR_ST_2>::Peer_Handler (ACE_Reactor *r) + : action_ (&Peer_Handler<PR_ST_2>::uninitialized) +{ + this->reactor (r); +} + +template <PR_ST_1> int +Peer_Handler<PR_ST_2>::open (void *) +{ + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("activating %d\n"), + this->peer ().get_handle ())); + this->action_ = &Peer_Handler<PR_ST_2>::connected; + + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("please enter input..: "))); + + if (this->reactor ()) + +#if defined (ACE_WIN32) + // On Win32, the stdin HANDLE must be registered directly (and not + // as a socket). + this->reactor ()->register_handler (this, + ACE_STDIN); +#else + // On non-Win32, the stdin HANDLE must be registered as a normal + // handle with the <READ_Mask>. + this->reactor ()->register_handler (ACE_STDIN, + this, + ACE_Event_Handler::READ_MASK); +#endif /* ACE_WIN32 */ + else + { + while (this->connected () != -1) + continue; + + this->handle_close (ACE_INVALID_HANDLE, + ACE_Event_Handler::READ_MASK); + } + return 0; +} + +template <PR_ST_1> int +Peer_Handler<PR_ST_2>::close (u_long) +{ + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("Connect not successful: ending reactor event loop\n"))); + this->reactor ()->end_reactor_event_loop(); + return 0; +} + +template <PR_ST_1> int +Peer_Handler<PR_ST_2>::uninitialized (void) +{ + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("uninitialized!\n"))); + return 0; +} + +template <PR_ST_1> int +Peer_Handler<PR_ST_2>::connected (void) +{ + char buf[BUFSIZ]; + + ssize_t n = ACE_OS::read (ACE_STDIN, + buf, + sizeof buf); + + if (n > 0 + && this->peer ().send_n (buf, + n) != n) + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("write failed")), + -1); + else if (n == 0) + { + // Explicitly close the connection. + if (this->peer ().close () == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("close")), + 1); + return -1; + } + else + { + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("please enter input..: "))); + return 0; + } +} + +template <PR_ST_1> int +Peer_Handler<PR_ST_2>::stdio (void) +{ + char buf[BUFSIZ]; + + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("in stdio\nplease enter input..: "))); + + ssize_t n = ACE_OS::read (ACE_STDIN, + buf, + sizeof buf); + if (n > 0) + { + if (ACE_OS::write (ACE_STDOUT, + buf, + n) != n) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("write")), + -1); + return 0; + } + else + return -1; +} + +template <PR_ST_1> int +Peer_Handler<PR_ST_2>::handle_timeout (const ACE_Time_Value &, + const void *) +{ + ACE_ERROR ((LM_ERROR, ACE_TEXT ("Connect timedout. "))); + return this->close (); +} + +template <PR_ST_1> int +Peer_Handler<PR_ST_2>::handle_output (ACE_HANDLE) +{ + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("in handle_output\n"))); + + return (this->*action_) (); +} + +template <PR_ST_1> int +Peer_Handler<PR_ST_2>::handle_signal (int signum, + siginfo_t *, + ucontext_t *) +{ + ACE_UNUSED_ARG (signum); + + // @@ Note that this code is not portable to all OS platforms since + // it uses print statements within signal handler context. + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("in handle_signal\n"))); + + return (this->*action_) (); +} + +template <PR_ST_1> int +Peer_Handler<PR_ST_2>::handle_input (ACE_HANDLE) +{ + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("in handle_input\n"))); + + return (this->*action_) (); +} + +template <PR_ST_1> int +Peer_Handler<PR_ST_2>::handle_close (ACE_HANDLE h, + ACE_Reactor_Mask mask) +{ + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("closing down handle %d with mask %d\n"), + h, + mask)); + + if (this->action_ == &Peer_Handler<PR_ST_2>::stdio) + { + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("moving to closed state\n"))); + this->reactor ()->end_reactor_event_loop (); + } + else + { + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("moving to stdio state\n"))); + this->action_ = &Peer_Handler<PR_ST_2>::stdio; + this->peer ().close (); + ACE_OS::rewind (stdin); + + if (this->reactor ()) +#if defined (ACE_WIN32) + // On Win32, the std handle must be registered directly (and not + // as a socket) + return this->reactor ()->register_handler (this, + ACE_STDIN); +#else + // On non-Win32, the std handle must be registered as a normal + // handle with the READ mask + return this->reactor ()->register_handler (ACE_STDIN, + this, + ACE_Event_Handler::READ_MASK); +#endif /* ACE_WIN32 */ + else + delete this; + } + + return 0; +} + +template <class SVH, PR_CO_1> int +IPC_Client<SVH, PR_CO_2>::svc (void) +{ + if (this->reactor ()) + this->reactor ()->run_reactor_event_loop (); + + return 0; +} + +template <class SVH, PR_CO_1> int +IPC_Client<SVH, PR_CO_2>::fini (void) +{ + return 0; +} + +template <class SVH, PR_CO_1> +IPC_Client<SVH, PR_CO_2>::IPC_Client (void) + : done_handler_ (ACE_Sig_Handler_Ex (ACE_Reactor::end_event_loop)) +{ +} + +template <class SVH, PR_CO_1> int +IPC_Client<SVH, PR_CO_2>::init (int argc, ACE_TCHAR *argv[]) +{ + // Call down to the CONNECTOR's open() method to do the + // initialization. + this->inherited::open (ACE_Reactor::instance ()); + + const ACE_TCHAR *r_addr = argc > 1 ? argv[1] : + ACE_SERVER_ADDRESS (ACE_DEFAULT_SERVER_HOST, + ACE_DEFAULT_SERVER_PORT_STR); + ACE_Time_Value timeout (argc > 2 + ? ACE_OS::atoi (argv[2]) + : ACE_DEFAULT_TIMEOUT); + + // Handle signals through the ACE_Reactor. + if (ACE_Reactor::instance ()->register_handler + (SIGINT, + &this->done_handler_) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("register_handler")), + -1); + PR_AD remote_addr (r_addr); + this->options_.set (ACE_Synch_Options::USE_REACTOR, + timeout); + + SVH *sh; + ACE_NEW_RETURN (sh, + SVH (this->reactor ()), + -1); + + // Connect to the peer. + if (this->connect (sh, + remote_addr, + this->options_) == -1 + && errno != EWOULDBLOCK) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("connect")), + -1); + else + return 0; +} + +template <class SVH, PR_CO_1> +IPC_Client<SVH, PR_CO_2>::~IPC_Client (void) +{ +} + +#undef PR_ST_1 +#undef PR_ST_2 +#undef PR_CO_1 +#undef PR_CO_2 +#undef PR_AD +#undef SVH +#endif /* CPP_CONNECTOR_C */ diff --git a/ACE/examples/Connection/non_blocking/CPP-connector.h b/ACE/examples/Connection/non_blocking/CPP-connector.h new file mode 100644 index 00000000000..86ce63493f0 --- /dev/null +++ b/ACE/examples/Connection/non_blocking/CPP-connector.h @@ -0,0 +1,98 @@ +/* -*- C++ -*- */ +// $Id$ + +#ifndef CPP_CONNECTOR_H +#define CPP_CONNECTOR_H + +#include "ace/Service_Config.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Connector.h" +#include "ace/Svc_Handler.h" +#include "ace/Sig_Adapter.h" + +template <ACE_PEER_STREAM_1> +class Peer_Handler : public ACE_Svc_Handler<ACE_PEER_STREAM_2, ACE_SYNCH> +{ + // = TITLE + // Handles communication with the server. + // + // = DESCRIPTION + // This class uses a very clever state machine pattern to keep + // track of how it interacts with the user and the server. +public: + Peer_Handler (ACE_Reactor *r = 0); + + virtual int open (void * = 0); + // Activate the handler when connection is established. + + virtual int close (u_long flags = 0); + // Called on failed connection attempt. + + // = Demultiplexing hooks. + virtual int handle_output (ACE_HANDLE); + virtual int handle_input (ACE_HANDLE); + virtual int handle_close (ACE_HANDLE, + ACE_Reactor_Mask mask); + virtual int handle_signal (int signum, + siginfo_t * = 0, + ucontext_t * = 0); + virtual int handle_timeout (const ACE_Time_Value &time, + const void *); +protected: + // = These methods implement the State pattern. + int uninitialized (void); + int connected (void); + int stdio (void); + + int (Peer_Handler<ACE_PEER_STREAM_2>::*action_) (void); + // Keeps track of which state we are in. +}; + +template <class SVC_HANDLER, ACE_PEER_CONNECTOR_1> +class IPC_Client : public ACE_Connector<SVC_HANDLER, ACE_PEER_CONNECTOR_2> +{ + // = TITLE + // This class illustrates how the <ACE_Connector> works. +public: + // = Initialization and termination methods. + IPC_Client (void); + // Constructor. + + ~IPC_Client (void); + // Destructor. + + // = Dynamic linking hooks. + virtual int init (int argc, ACE_TCHAR *argv[]); + // Initialize the IPC client. + + virtual int fini (void); + // Destroy the IPC client. + + virtual int svc (void); + // Run the svc. + +private: + typedef ACE_Connector<SVC_HANDLER, ACE_PEER_CONNECTOR_2> + inherited; + + ACE_Synch_Options options_; + // Options for the active connection factory. + + ACE_Sig_Adapter done_handler_; + // Keeps track of when we shut down due to receipt of the SIGINT + // signal. +}; + +#if defined (ACE_TEMPLATES_REQUIRE_SOURCE) +#include "CPP-connector.cpp" +#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */ + +#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA) +#pragma implementation ("CPP-connector.cpp") +#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */ + +#endif /* CPP_CONNECTOR_H */ diff --git a/ACE/examples/Connection/non_blocking/Connection_Non_Blocking.mpc b/ACE/examples/Connection/non_blocking/Connection_Non_Blocking.mpc new file mode 100644 index 00000000000..de9ecaea5e0 --- /dev/null +++ b/ACE/examples/Connection/non_blocking/Connection_Non_Blocking.mpc @@ -0,0 +1,68 @@ +// -*- MPC -*- +// $Id$ + +project (*SockClient) : aceexe { + exename = sock_client + Source_Files { + CPP-connector.cpp + test_sock_connector.cpp + } +} + +project (*SockServer) : aceexe { + exename = sock_server + Source_Files { + CPP-acceptor.cpp + test_sock_acceptor.cpp + } +} + +project (*LSockClient) : aceexe { + avoids += ace_for_tao + exename = lsock_client + Source_Files { + CPP-connector.cpp + test_lsock_connector.cpp + } +} + +project (*LSockServer) : aceexe { + avoids += ace_for_tao + exename = lsock_server + Source_Files { + CPP-acceptor.cpp + test_lsock_acceptor.cpp + } +} + +project (*SPipeClient) : aceexe { + exename = spipe_client + Source_Files { + CPP-connector.cpp + test_spipe_connector.cpp + } +} + +project (*SPipeServer) : aceexe { + exename = spipe_server + Source_Files { + CPP-acceptor.cpp + test_spipe_acceptor.cpp + } +} + +project (*TLIClient) : aceexe { + exename = tli_client + Source_Files { + CPP-connector.cpp + test_tli_connector.cpp + } +} + +project (*TLIServer) : aceexe { + exename = tli_server + Source_Files { + CPP-acceptor.cpp + test_tli_acceptor.cpp + } +} diff --git a/ACE/examples/Connection/non_blocking/Makefile.am b/ACE/examples/Connection/non_blocking/Makefile.am new file mode 100644 index 00000000000..8395e3a9fbb --- /dev/null +++ b/ACE/examples/Connection/non_blocking/Makefile.am @@ -0,0 +1,150 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +ACE_BUILDDIR = $(top_builddir) +ACE_ROOT = $(top_srcdir) + +noinst_PROGRAMS = + +## Makefile.Connection_Non_Blocking_LSockClient.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS += lsock_client + +lsock_client_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +lsock_client_SOURCES = \ + CPP-connector.cpp \ + test_lsock_connector.cpp \ + CPP-connector.h + +lsock_client_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Makefile.Connection_Non_Blocking_LSockServer.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS += lsock_server + +lsock_server_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +lsock_server_SOURCES = \ + CPP-acceptor.cpp \ + test_lsock_acceptor.cpp \ + CPP-acceptor.h + +lsock_server_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Makefile.Connection_Non_Blocking_SPipeClient.am +noinst_PROGRAMS += spipe_client + +spipe_client_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +spipe_client_SOURCES = \ + CPP-connector.cpp \ + test_spipe_connector.cpp \ + CPP-connector.h + +spipe_client_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Connection_Non_Blocking_SPipeServer.am +noinst_PROGRAMS += spipe_server + +spipe_server_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +spipe_server_SOURCES = \ + CPP-acceptor.cpp \ + test_spipe_acceptor.cpp \ + CPP-acceptor.h + +spipe_server_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Connection_Non_Blocking_SockClient.am +noinst_PROGRAMS += sock_client + +sock_client_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +sock_client_SOURCES = \ + CPP-connector.cpp \ + test_sock_connector.cpp \ + CPP-connector.h + +sock_client_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Connection_Non_Blocking_SockServer.am +noinst_PROGRAMS += sock_server + +sock_server_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +sock_server_SOURCES = \ + CPP-acceptor.cpp \ + test_sock_acceptor.cpp \ + CPP-acceptor.h + +sock_server_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Connection_Non_Blocking_TLIClient.am +noinst_PROGRAMS += tli_client + +tli_client_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +tli_client_SOURCES = \ + CPP-connector.cpp \ + test_tli_connector.cpp \ + CPP-connector.h + +tli_client_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Connection_Non_Blocking_TLIServer.am +noinst_PROGRAMS += tli_server + +tli_server_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +tli_server_SOURCES = \ + CPP-acceptor.cpp \ + test_tli_acceptor.cpp \ + CPP-acceptor.h + +tli_server_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Clean up template repositories, etc. +clean-local: + -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.* + -rm -f gcctemp.c gcctemp so_locations *.ics + -rm -rf cxx_repository ptrepository ti_files + -rm -rf templateregistry ir.out + -rm -rf ptrepository SunWS_cache Templates.DB diff --git a/ACE/examples/Connection/non_blocking/README b/ACE/examples/Connection/non_blocking/README new file mode 100644 index 00000000000..74c44fe6de7 --- /dev/null +++ b/ACE/examples/Connection/non_blocking/README @@ -0,0 +1,28 @@ +This code illustrates how to write a single set of source code (for a +client and server) and then parameterize in the desired IPC mechanism. +In this case, the IPC mechanisms include sockets, TLI, and STREAM +pipes. The single set of source code is located in CPP-acceptor.cpp +(which is the server) and CPP-connector.cpp (which is the non-blocking +client). + +Here's how I typically run these tests: + +% test_sock_acceptor localhost:10020 & +starting up daemon ./test_sock_acceptor +starting server addr 127.0.0.1:10020 on handle 5 +client addr 127.0.0.1:10003 on handle 6 +hello + +% test_sock_connector localhost:10020 +starting up daemon ./test_sock_connector +activating 5 +in handle_output +please enter input..: hello +in handle_output + +There are a number of other options that you can provide. Please see +the source code for details. + +Note that only the sock tests work on all platforms. The other tests +reply on features (in particular, non-blocking connections and TLI) +that are mostly found on UNIX platforms. diff --git a/ACE/examples/Connection/non_blocking/test_lsock_acceptor.cpp b/ACE/examples/Connection/non_blocking/test_lsock_acceptor.cpp new file mode 100644 index 00000000000..cdfcfe5e65c --- /dev/null +++ b/ACE/examples/Connection/non_blocking/test_lsock_acceptor.cpp @@ -0,0 +1,49 @@ +// $Id$ + +// ACE_LSOCK Server. + +#include "ace/LSOCK_Acceptor.h" +#include "ace/Log_Msg.h" +#include "ace/Service_Config.h" + + +#if defined (ACE_LACKS_UNIX_DOMAIN_SOCKETS) +int +ACE_TMAIN (int, ACE_TCHAR *argv[]) +{ + ACE_ERROR_RETURN ((LM_INFO, + ACE_TEXT ("%s: not supported with ") + ACE_TEXT ("ACE_LACKS_UNIX_DOMAIN_SOCKETS\n"), + argv[0]), + -1); +} + +#else /* ! ACE_LACKS_UNIX_DOMAIN_SOCKETS */ + +#include "ace/UNIX_Addr.h" +#include "CPP-acceptor.h" + +ACE_RCSID (non_blocking, + test_lsock_acceptor, + "$Id$") + +typedef Svc_Handler<ACE_LSOCK_STREAM> SVC_HANDLER; +typedef IPC_Server<SVC_HANDLER, ACE_LSOCK_ACCEPTOR> IPC_SERVER; + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + // Perform Service_Config initializations + ACE_Service_Config daemon (argv[0]); + + IPC_SERVER peer_acceptor; + + if (peer_acceptor.init (argc, argv) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("init")), + -1); + return peer_acceptor.svc (); +} + +#endif /* ! ACE_LACKS_UNIX_DOMAIN_SOCKETS */ diff --git a/ACE/examples/Connection/non_blocking/test_lsock_connector.cpp b/ACE/examples/Connection/non_blocking/test_lsock_connector.cpp new file mode 100644 index 00000000000..486fda797e8 --- /dev/null +++ b/ACE/examples/Connection/non_blocking/test_lsock_connector.cpp @@ -0,0 +1,46 @@ +// $Id$ + +#include "ace/LSOCK_Connector.h" +#include "ace/Log_Msg.h" + +#if defined (ACE_LACKS_UNIX_DOMAIN_SOCKETS) +int +ACE_TMAIN (int, ACE_TCHAR *argv[]) +{ + ACE_ERROR_RETURN ((LM_INFO, + ACE_TEXT ("%s: not supported with ") + ACE_TEXT ("ACE_LACKS_UNIX_DOMAIN_SOCKETS\n"), + argv[0]), + -1); +} + +#else /* ! ACE_LACKS_UNIX_DOMAIN_SOCKETS */ + +#include "ace/UNIX_Addr.h" +#include "CPP-connector.h" + +ACE_RCSID(non_blocking, test_lsock_connector, "$Id$") + +typedef Peer_Handler<ACE_LSOCK_STREAM> PEER_HANDLER; +typedef IPC_Client<PEER_HANDLER, ACE_LSOCK_CONNECTOR> IPC_CLIENT; + +// ACE_LSOCK Client. + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + // Perform Service_Config initializations + ACE_Service_Config daemon (argv[0]); + + IPC_CLIENT peer_connector; + + if (peer_connector.init (argc, argv) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("init")), + -1); + + return peer_connector.svc (); +} + +#endif /* ! ACE_LACKS_UNIX_DOMAIN_SOCKETS */ diff --git a/ACE/examples/Connection/non_blocking/test_sock_acceptor.cpp b/ACE/examples/Connection/non_blocking/test_sock_acceptor.cpp new file mode 100644 index 00000000000..6a9b9fcdcbb --- /dev/null +++ b/ACE/examples/Connection/non_blocking/test_sock_acceptor.cpp @@ -0,0 +1,34 @@ +// $Id$ + +#include "ace/SOCK_Acceptor.h" +#include "ace/INET_Addr.h" +#include "ace/Service_Config.h" + +#include "CPP-acceptor.h" + + +ACE_RCSID (non_blocking, + test_sock_acceptor, + "$Id$") + + +typedef Svc_Handler<ACE_SOCK_STREAM> SVC_HANDLER; +typedef IPC_Server<SVC_HANDLER, ACE_SOCK_ACCEPTOR> IPC_SERVER; + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + // Perform Service_Config initializations + ACE_Service_Config daemon (argv[0]); + + IPC_SERVER peer_acceptor; + + if (peer_acceptor.init (argc, argv) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("init")), + -1); + + return peer_acceptor.svc (); +} + diff --git a/ACE/examples/Connection/non_blocking/test_sock_connector.cpp b/ACE/examples/Connection/non_blocking/test_sock_connector.cpp new file mode 100644 index 00000000000..66d53e1f0b2 --- /dev/null +++ b/ACE/examples/Connection/non_blocking/test_sock_connector.cpp @@ -0,0 +1,49 @@ +// $Id$ + +#include "ace/SOCK_Connector.h" +#include "ace/INET_Addr.h" +#include "ace/Reactor.h" +#include "ace/WFMO_Reactor.h" +#include "CPP-connector.h" + +ACE_RCSID(non_blocking, test_sock_connector, "$Id$") + +typedef Peer_Handler<ACE_SOCK_STREAM> PEER_HANDLER; +typedef IPC_Client<PEER_HANDLER, ACE_SOCK_CONNECTOR> IPC_CLIENT; + +// ACE_SOCK Client. + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + // Since this test waits on the STDIN handle to become ready, we + // have to make sure that the WFMO_Reactor is used on Win32. This is + // necessary since <select> on NT does not support waiting on STDIN. + +#if defined (ACE_WIN32) +# if defined (ACE_HAS_WINSOCK2) && (ACE_HAS_WINSOCK2 != 0) + ACE_WFMO_Reactor wfmo_reactor; + ACE_Reactor reactor (&wfmo_reactor); + ACE_Reactor::instance (&reactor); +# else + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("Non-NT platform (Win95/98?) without Winsock2 ") + ACE_TEXT ("installed.\n") + ACE_TEXT ("This example requires WFMO_Reactor which ") + ACE_TEXT ("requires.\n") + ACE_TEXT ("Winsock2 be installed.\n")), -1); +# endif /* !ACE_HAS_WINSOCK2 && ACE_HAS_WINSOCK2 != 0 */ +#endif /* ACE_WIN32 */ + + // Perform Service_Config initializations + ACE_Service_Config daemon (argv[0]); + + IPC_CLIENT peer_connector; + + if (peer_connector.init (argc, argv) == -1) + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("init")), + -1); + + return peer_connector.svc (); +} + diff --git a/ACE/examples/Connection/non_blocking/test_spipe_acceptor.cpp b/ACE/examples/Connection/non_blocking/test_spipe_acceptor.cpp new file mode 100644 index 00000000000..ed33bb31683 --- /dev/null +++ b/ACE/examples/Connection/non_blocking/test_spipe_acceptor.cpp @@ -0,0 +1,45 @@ +// $Id$ + +#include "ace/SPIPE_Acceptor.h" +#include "ace/SPIPE_Addr.h" +#include "ace/Service_Config.h" + +#include "CPP-acceptor.h" + + +ACE_RCSID (non_blocking, + test_spipe_acceptor, + "$Id$") + + +#if !defined (ACE_WIN32) +typedef Svc_Handler<ACE_SPIPE_STREAM> SVC_HANDLER; +typedef IPC_Server<SVC_HANDLER, ACE_SPIPE_ACCEPTOR> IPC_SERVER; + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + // Perform Service_Config initializations + ACE_Service_Config daemon (argv[0]); + + IPC_SERVER peer_acceptor; + + if (peer_acceptor.init (argc, + argv) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("init")), + -1); + + return peer_acceptor.svc (); +} + +#else +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_ERROR_RETURN ((LM_ERROR, + "This test is not ported to Win32 (yet)\n"), + -1); +} +#endif /* !ACE_WIN32 */ diff --git a/ACE/examples/Connection/non_blocking/test_spipe_connector.cpp b/ACE/examples/Connection/non_blocking/test_spipe_connector.cpp new file mode 100644 index 00000000000..fd5641f482d --- /dev/null +++ b/ACE/examples/Connection/non_blocking/test_spipe_connector.cpp @@ -0,0 +1,40 @@ +// $Id$ + +// ACE_SPIPE Client. + +#include "ace/SPIPE_Connector.h" +#include "ace/SPIPE_Addr.h" +#include "CPP-connector.h" + +ACE_RCSID(non_blocking, test_spipe_connector, "$Id$") + +#if !defined (ACE_WIN32) +typedef Peer_Handler<ACE_SPIPE_STREAM> PEER_HANDLER; +typedef IPC_Client<PEER_HANDLER, ACE_SPIPE_CONNECTOR> IPC_CLIENT; + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + // Perform Service_Config initializations + ACE_Service_Config daemon (argv[0]); + + IPC_CLIENT peer_connector; + + if (peer_connector.init (argc, argv) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("init")), + -1); + + return peer_connector.svc (); +} + +#else +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_ERROR_RETURN ((LM_ERROR, + "This test is not ported to Win32 (yet)\n"), + -1); +} +#endif /* !ACE_WIN32 */ diff --git a/ACE/examples/Connection/non_blocking/test_tli_acceptor.cpp b/ACE/examples/Connection/non_blocking/test_tli_acceptor.cpp new file mode 100644 index 00000000000..04cfb488cbb --- /dev/null +++ b/ACE/examples/Connection/non_blocking/test_tli_acceptor.cpp @@ -0,0 +1,41 @@ +// $Id$ + +// ACE_TLI Server. + +#include "ace/TLI_Acceptor.h" +#include "ace/INET_Addr.h" +#include "ace/Service_Config.h" +#include "CPP-acceptor.h" + +ACE_RCSID (non_blocking, + test_tli_acceptor, + "$Id$") + +#if defined (ACE_HAS_TLI) +typedef Svc_Handler<ACE_TLI_STREAM> SVC_HANDLER; +typedef IPC_Server<SVC_HANDLER, ACE_TLI_ACCEPTOR> IPC_SERVER; + +int ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + // Perform Service_Config initializations + ACE_Service_Config daemon (argv[0]); + + IPC_SERVER peer_acceptor; + + if (peer_acceptor.init (argc, argv) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("init")), + -1); + return peer_acceptor.svc (); +} + +#else +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("your platform does not support TLI\n")), + 1); +} +#endif /* ACE_HAS_TLI */ diff --git a/ACE/examples/Connection/non_blocking/test_tli_connector.cpp b/ACE/examples/Connection/non_blocking/test_tli_connector.cpp new file mode 100644 index 00000000000..0f1a2bd6064 --- /dev/null +++ b/ACE/examples/Connection/non_blocking/test_tli_connector.cpp @@ -0,0 +1,39 @@ +// $Id$ + +// ACE_TLI Client. + +#include "ace/TLI_Connector.h" +#include "ace/INET_Addr.h" +#include "CPP-connector.h" + +ACE_RCSID(non_blocking, test_tli_connector, "$Id$") + +#if defined (ACE_HAS_TLI) + +typedef Peer_Handler<ACE_TLI_STREAM> PEER_HANDLER; +typedef IPC_Client<PEER_HANDLER, ACE_TLI_CONNECTOR> IPC_CLIENT; + +int ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + // Perform Service_Config initializations + ACE_Service_Config daemon (argv[0]); + + IPC_CLIENT peer_connector; + + if (peer_connector.init (argc, argv) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("init")), + -1); + return peer_connector.svc (); +} + +#else +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("your platform does not support TLI\n")), + 1); +} +#endif /* ACE_HAS_TLI */ diff --git a/ACE/examples/DLL/.cvsignore b/ACE/examples/DLL/.cvsignore new file mode 100644 index 00000000000..c2d3a626997 --- /dev/null +++ b/ACE/examples/DLL/.cvsignore @@ -0,0 +1,2 @@ +test_dll +test_dll diff --git a/ACE/examples/DLL/DLL.mpc b/ACE/examples/DLL/DLL.mpc new file mode 100644 index 00000000000..ca8d0a63009 --- /dev/null +++ b/ACE/examples/DLL/DLL.mpc @@ -0,0 +1,22 @@ +// -*- MPC -*- +// $Id$ + +project(*Newsweek) : acelib { + Source_Files { + Newsweek.cpp + } +} + +project(*Today) : acelib { + Source_Files { + Today.cpp + } +} + +project(*Main) : aceexe { + exename = test_dll + after += DLL_Newsweek DLL_Today + Source_Files { + test_dll.cpp + } +} diff --git a/ACE/examples/DLL/Magazine.h b/ACE/examples/DLL/Magazine.h new file mode 100644 index 00000000000..6555974494f --- /dev/null +++ b/ACE/examples/DLL/Magazine.h @@ -0,0 +1,42 @@ +/* -*- C++ -*- */ +// $Id$ + +// =========================================================== +// +// +// = LIBRARY +// ACE_wrappers/examples/DLL +// +// = FILENAME +// Magazine.h +// +// = DESCRIPTION +// Abstract class whose methods are implemented by the derived +// classes. +// +// = AUTHOR +// Kirthika Parameswaran <kirthika@cs.wustl.edu> +// +// =========================================================== + +#ifndef MAGAZINE_H +#define MAGAZINE_H + +class Magazine +{ + // = TITLE + // This is an abstract class used in the DLL example. + // + // = DESCRIPTION + // This class simply is an inetrface which the derived classes + // will exploit. +public: + + virtual ~Magazine (void) {}; + // No-op virtual destructor. + + virtual void title (void) = 0; + // This method gives the title of the magazine. +}; + +#endif /* MAGAZINE_H */ diff --git a/ACE/examples/DLL/Makefile.am b/ACE/examples/DLL/Makefile.am new file mode 100644 index 00000000000..4973af35bf9 --- /dev/null +++ b/ACE/examples/DLL/Makefile.am @@ -0,0 +1,64 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +ACE_BUILDDIR = $(top_builddir) +ACE_ROOT = $(top_srcdir) + +## Makefile.DLL_Today.am + +noinst_LTLIBRARIES = libDLL_Today.la + +libDLL_Today_la_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +libDLL_Today_la_SOURCES = \ + Today.cpp + +noinst_HEADERS = \ + Today.h + +## Makefile.DLL_Newsweek.am + +noinst_LTLIBRARIES += libDLL_Newsweek.la + +libDLL_Newsweek_la_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +libDLL_Newsweek_la_SOURCES = \ + Newsweek.cpp + +noinst_HEADERS += \ + Newsweek.h + +## Makefile.DLL_Main.am +noinst_PROGRAMS = test_dll + +test_dll_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +test_dll_SOURCES = \ + test_dll.cpp \ + Magazine.h \ + Newsweek.h \ + Today.h + +test_dll_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Clean up template repositories, etc. +clean-local: + -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.* + -rm -f gcctemp.c gcctemp so_locations *.ics + -rm -rf cxx_repository ptrepository ti_files + -rm -rf templateregistry ir.out + -rm -rf ptrepository SunWS_cache Templates.DB diff --git a/ACE/examples/DLL/Newsweek.cpp b/ACE/examples/DLL/Newsweek.cpp new file mode 100644 index 00000000000..5a48690b350 --- /dev/null +++ b/ACE/examples/DLL/Newsweek.cpp @@ -0,0 +1,55 @@ +// $Id$ + +#define ACE_BUILD_SVC_DLL + +#include "Newsweek.h" +#include "ace/Log_Msg.h" +#include "ace/svc_export.h" +#include "ace/OS_Memory.h" + +// Implementation of the abstract class method which describes +// the magazine. + +void Newsweek::title (void) +{ + ACE_DEBUG ((LM_DEBUG, + "Newsweek: Vol. 44923 Stardate: 12.3054\n")); +} + +void * +Newsweek::operator new (size_t bytes) +{ + return ::new char[bytes]; +} +#if defined (ACE_HAS_NEW_NOTHROW) +void * +Newsweek::operator new (size_t bytes, const ACE_nothrow_t&) +{ + return ::new (ACE_nothrow) char[bytes]; +} +#if !defined (ACE_LACKS_PLACEMENT_OPERATOR_DELETE) +void +Newsweek::operator delete (void *p, const ACE_nothrow_t&) throw () +{ + delete [] static_cast <char *> (p); +} +#endif /* ACE_LACKS_PLACEMENT_OPERATOR_DELETE */ +#endif +void +Newsweek::operator delete (void *ptr) +{ + delete [] static_cast <char *> (ptr); +} + +// Returns the Newsweek class pointer. +// The ACE_BUILD_SVC_DLL and ACE_Svc_Export directives are necessary to +// take care of exporting the function for Win32 platforms. +extern "C" ACE_Svc_Export Magazine *create_magazine (void); + +Magazine * +create_magazine (void) +{ + Magazine *mag = 0; + ACE_NEW_RETURN (mag, Newsweek, 0); + return mag; +} diff --git a/ACE/examples/DLL/Newsweek.h b/ACE/examples/DLL/Newsweek.h new file mode 100644 index 00000000000..79355e74cbd --- /dev/null +++ b/ACE/examples/DLL/Newsweek.h @@ -0,0 +1,59 @@ +/* -*- C++ -*- */ +// $Id$ + +// =========================================================== +// +// = LIBRARY +// ACE_wrappers/examples/DLL +// +// = FILENAME +// Newsweek.h +// +// = DESCRIPTION +// This is a derived class from Magazine which is a magazine +// pertaining to news and information. +// +// = AUTHOR +// Kirthika Parameswaran <kirthika@cs.wustl.edu> +// +// =========================================================== + +#ifndef NEWSWEEK_H +#define NEWSWEEK_H + +#include "ace/os_include/os_stddef.h" +#include "ace/OS_Memory.h" +#include "Magazine.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +class Newsweek : public Magazine +{ + //= TITLE + // This is an derived class of Magazine. + // + //= DESCRIPTION + // Polymoriphism is exploited and an object pointer + // of Magazine is bound to the Newsweek object at runtime. +public: + + // This is the abstract class method which describes the magazine. + void title (void); + + // Overload the new/delete opertors so the object will be + // created/deleted using the memory allocator associated with the + // DLL/SO. + void *operator new (size_t bytes); +#if defined (ACE_HAS_NEW_NOTHROW) + // Overloaded new operator, nothrow_t variant. + void *operator new (size_t bytes, const ACE_nothrow_t&); +#if !defined (ACE_LACKS_PLACEMENT_OPERATOR_DELETE) + void operator delete (void *p, const ACE_nothrow_t&) throw (); +#endif /* ACE_LACKS_PLACEMENT_OPERATOR_DELETE */ +#endif + void operator delete (void *ptr); +}; + +# endif /* NEWSWEEK_H */ diff --git a/ACE/examples/DLL/README b/ACE/examples/DLL/README new file mode 100644 index 00000000000..716b2c2b628 --- /dev/null +++ b/ACE/examples/DLL/README @@ -0,0 +1,47 @@ +$Id$ + +DLL Test Example +---------------- + +This example deals with dynamically opening objects and accessing +methods from it. + +First, the pointer to the object is obtained by accessing symbol +of the function which can get the object pointer. Then the methods +in that library object is accessed. + +Here, the Magazine class is an abstract class with various magazine +objects like Newsweek and Today deriving form it. The libraries are +dynamically linked on demand. Thus, they can be changed on the fly +and accessed with its new changes. + +The ACE_DLL class used in this example is an helper class for +performing various operations on the library object. + +Compilation and Execution: +------------------------- + +1. On POSIX/UNIX platforms: + + First, build the test program, which you can do on UNIX as follows: + + % make + + Then run the test program: + + % test_dll + + to exercise the test. + + +2. On NT or any Win32 platform: + + Load Dll.dsw which contains Test_dll.dsp, Today.dsp and Newsweek.dsp. + + Build each dsp such that you build Test_dll.dsp last. + This is because the test_dll.exe will be using Today.dll and Newsweek.dll. + + Execute test_dll + + and watch it run! + diff --git a/ACE/examples/DLL/Today.cpp b/ACE/examples/DLL/Today.cpp new file mode 100644 index 00000000000..b80bfff2b0a --- /dev/null +++ b/ACE/examples/DLL/Today.cpp @@ -0,0 +1,55 @@ +// $Id$ + +#define ACE_BUILD_SVC_DLL + +#include "Today.h" +#include "ace/Log_Msg.h" +#include "ace/svc_export.h" +#include "ace/OS_Memory.h" + +// Implementation of the abstract class method which describes the +// magazine. + +void +Today::title (void) +{ + ACE_DEBUG ((LM_DEBUG, + "Today: XML Special Apr 02\n")); +} + +void * +Today::operator new (size_t bytes) +{ + return ::new char[bytes]; +} +#if defined (ACE_HAS_NEW_NOTHROW) +void * +Today::operator new (size_t bytes, const ACE_nothrow_t&) +{ + return ::new (ACE_nothrow) char[bytes]; +} +#if !defined (ACE_LACKS_PLACEMENT_OPERATOR_DELETE) +void +Today::operator delete (void *p, const ACE_nothrow_t&) throw () +{ + delete [] static_cast <char *> (p); +} +#endif /* ACE_LACKS_PLACEMENT_OPERATOR_DELETE */ +#endif +void +Today::operator delete (void *ptr) +{ + delete [] static_cast <char *> (ptr); +} + +// Returns the pointer to the Today class. +// The ACE_BUILD_SVC_DLL and ACE_Svc_Export directives are necessary to +// take care of exporting the function for Win32 platforms. +extern "C" ACE_Svc_Export Magazine *create_magazine (void); + +Magazine *create_magazine (void) +{ + Magazine *mag = 0; + ACE_NEW_RETURN (mag, Today, 0); + return mag; +} diff --git a/ACE/examples/DLL/Today.h b/ACE/examples/DLL/Today.h new file mode 100644 index 00000000000..00c2d4b9c04 --- /dev/null +++ b/ACE/examples/DLL/Today.h @@ -0,0 +1,60 @@ +/* -*- C++ -*- */ +// $Id$ + +// =========================================================== +// +// = LIBRARY +// ACE_wrappers/examples/DLL +// +// = FILENAME +// Today.h +// +// = DESCRIPTION +// This class denotes the Today magazine which is derived from +// Magazine. +// +// = AUTHOR +// Kirthika Parameswaran <kirthika@cs.wustl.edu> +// +// =========================================================== + +#ifndef TODAY_H +#define TODAY_H + +#include "ace/os_include/os_stddef.h" +#include "ace/OS_Memory.h" +#include "Magazine.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +class Today : public Magazine +{ + // = TITLE + // This is an derived class of Magazine. + // + // = DESCRIPTION + // Polymoriphism is exploited and an object pointer of Magazine + // is bound to the Today object at runtime. +public: + + // The virtual abstract class method which returns the title of the + // magazine. + void title (void); + + // Overload the new/delete opertors so the object will be + // created/deleted using the memory allocator associated with the + // DLL/SO. + void *operator new (size_t bytes); +#if defined (ACE_HAS_NEW_NOTHROW) + // Overloaded new operator, nothrow_t variant. + void *operator new (size_t bytes, const ACE_nothrow_t&); +#if !defined (ACE_LACKS_PLACEMENT_OPERATOR_DELETE) + void operator delete (void *p, const ACE_nothrow_t&) throw (); +#endif /* ACE_LACKS_PLACEMENT_OPERATOR_DELETE */ +#endif + void operator delete (void *ptr); +}; + +#endif /* TODAY_H */ diff --git a/ACE/examples/DLL/test_dll.cpp b/ACE/examples/DLL/test_dll.cpp new file mode 100644 index 00000000000..49f385aff98 --- /dev/null +++ b/ACE/examples/DLL/test_dll.cpp @@ -0,0 +1,90 @@ +// $Id$ + +// This program tests out how the various objects can be loaded +// dynamically and method calls made on them. + +#include "Magazine.h" +#include "ace/DLL.h" +#include "ace/Auto_Ptr.h" +#include "ace/Log_Msg.h" + +ACE_RCSID(DLL, test_dll, "$Id$") + +typedef Magazine* (*Magazine_Creator) (void); + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + ACE_UNUSED_ARG (argc); + ACE_UNUSED_ARG (argv); + + ACE_DLL dll; + + int retval = dll.open (ACE_TEXT("./") ACE_DLL_PREFIX ACE_TEXT("DLL_Today")); + + if (retval != 0) + ACE_ERROR_RETURN ((LM_ERROR, + "%p", + "dll.open"), + -1); + Magazine_Creator mc; + + // Cast the void* to non-pointer type first - it's not legal to + // cast a pointer-to-object directly to a pointer-to-function. + void *void_ptr = dll.symbol (ACE_TEXT ("create_magazine")); + ptrdiff_t tmp = reinterpret_cast<ptrdiff_t> (void_ptr); + mc = reinterpret_cast<Magazine_Creator> (tmp); + + if (mc == 0) + { + ACE_ERROR_RETURN ((LM_ERROR, + "%p", + "dll.symbol"), + -1); + } + + { + auto_ptr <Magazine> magazine (mc ()); + + magazine->title (); + } + + dll.close (); + + // The other library is now loaded on demand. + + retval = dll.open (ACE_DLL_PREFIX ACE_TEXT ("DLL_Newsweek")); + + if (retval != 0) + { + ACE_ERROR_RETURN ((LM_ERROR, + "%p", + "dll.open"), + -1); + } + + // Cast the void* to non-pointer type first - it's not legal to + // cast a pointer-to-object directly to a pointer-to-function. + void_ptr = dll.symbol (ACE_TEXT ("create_magazine")); + tmp = reinterpret_cast<ptrdiff_t> (void_ptr); + mc = reinterpret_cast<Magazine_Creator> (tmp); + + if (mc == 0) + { + ACE_ERROR_RETURN ((LM_ERROR, + "%p", + "dll.symbol"), + -1); + } + + { + auto_ptr <Magazine> magazine (mc ()); + + magazine->title (); + } + + dll.close (); + + return 0; +} + diff --git a/ACE/examples/Export/.cvsignore b/ACE/examples/Export/.cvsignore new file mode 100644 index 00000000000..dec2cbe1fa3 --- /dev/null +++ b/ACE/examples/Export/.cvsignore @@ -0,0 +1,2 @@ +test +test diff --git a/ACE/examples/Export/Export.mpc b/ACE/examples/Export/Export.mpc new file mode 100644 index 00000000000..51edc145591 --- /dev/null +++ b/ACE/examples/Export/Export.mpc @@ -0,0 +1,19 @@ +// -*- MPC -*- +// $Id$ + +project(*Lib) : acelib { + sharedname = Export_Lib + dynamicflags += TEST_BUILD_DLL + Source_Files { + dll.cpp + } +} + +project(*test) : aceexe { + exename = test + after += *Lib + libs += Export_Lib + Source_Files { + test.cpp + } +} diff --git a/ACE/examples/Export/Makefile.am b/ACE/examples/Export/Makefile.am new file mode 100644 index 00000000000..74baf4baf66 --- /dev/null +++ b/ACE/examples/Export/Makefile.am @@ -0,0 +1,51 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +ACE_BUILDDIR = $(top_builddir) +ACE_ROOT = $(top_srcdir) + +## Makefile.Export_Lib.am + +noinst_LTLIBRARIES = libExport_Lib.la + +libExport_Lib_la_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) \ + -DTEST_BUILD_DLL + +libExport_Lib_la_SOURCES = \ + dll.cpp + +noinst_HEADERS = \ + dll.h + +## Makefile.Export_Test.am +noinst_PROGRAMS = test + +test_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +test_SOURCES = \ + test.cpp \ + dll.h \ + test_export.h + +test_LDADD = \ + libExport_Lib.la \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Clean up template repositories, etc. +clean-local: + -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.* + -rm -f gcctemp.c gcctemp so_locations *.ics + -rm -rf cxx_repository ptrepository ti_files + -rm -rf templateregistry ir.out + -rm -rf ptrepository SunWS_cache Templates.DB diff --git a/ACE/examples/Export/README b/ACE/examples/Export/README new file mode 100644 index 00000000000..83fc3108d50 --- /dev/null +++ b/ACE/examples/Export/README @@ -0,0 +1,7 @@ +$Id$ + +The Export example is just an example that both shows off and tests +the macros created by generate_export_file.pl (or the earlier +GenExportH.bat). These macros are used to properly export functions +and classes from a Win32 DLL. On other platforms these macros expand +to nothing (since shared objects just export everything). diff --git a/ACE/examples/Export/dll.cpp b/ACE/examples/Export/dll.cpp new file mode 100644 index 00000000000..07705db9d59 --- /dev/null +++ b/ACE/examples/Export/dll.cpp @@ -0,0 +1,27 @@ +// $Id$ +#include "dll.h" + +int test_variable = 0; + +int +test_function () +{ + test_variable = RETVAL; + return RETVAL; +} + +int +test_class::method () +{ + return RETVAL; +} + +test_class * +get_dll_singleton () +{ + return TEST_SINGLETON::instance (); +} + +#if defined (ACE_HAS_EXPLICIT_STATIC_TEMPLATE_MEMBER_INSTANTIATION) +template ACE_Singleton<test_class, ACE_Null_Mutex> *ACE_Singleton<test_class, ACE_Null_Mutex>::singleton_; +#endif /* ACE_HAS_EXPLICIT_STATIC_TEMPLATE_MEMBER_INSTANTIATION */ diff --git a/ACE/examples/Export/dll.h b/ACE/examples/Export/dll.h new file mode 100644 index 00000000000..b07d3fe1cd8 --- /dev/null +++ b/ACE/examples/Export/dll.h @@ -0,0 +1,69 @@ +// $Id$ + +// To use the export macros with a DLL, a file will need to be +// created (see ACE_wrapper/bin/generate_export_file.pl) and +// included. This file defines Test_Export (and the +// TEST_SINGLETON_* macros). +#include "test_export.h" + +#include "ace/Singleton.h" +#include "ace/Null_Mutex.h" + +#define RETVAL 42 + +// To expose a function outside of a DLL, use the *_Export +// at the beginning of the function declaration. + +Test_Export int test_function (); + +// To expose data, put use the *Export at the beginning +// of the variable declaration. The extern is required when +// building static libraries. + +extern Test_Export int test_variable; + +// To expose a class, put the *_Export between "class" +// and the class name. + +class Test_Export test_class +{ +public: + int method (); +}; + +// ACE_Singleton and its relatives are special cases. The problem is +// that ACE_Singleton is a template. If the singleton is used in both +// the DLL and the executable linking the DLL, then two instances of +// the singleton will be used (which defeats the purpose of a Singleton). +// +// This occurs because the ACE_Singleton template is expanded in both +// places because Visual C++ and Borland C++ do this automatically by +// including the template source. This in turn creates two copies of +// the static member variable. +// +// So to get around this problem, the *_SINGLETON_DECLARE macro is +// used to instruct the compiler to not create the second copy in the +// program. This macro solution does not work for Borland C++, so for +// this compiler you must explicitly disable the template instantiation +// using a #pragma (or use the other workaround below). +// +// Another workaround for this is to not to expose the Singleton itself +// to the outside world, but to instead supply a function or static +// member function that returns the singleton to the executable +// (like get_dll_singleton () does below). + +#if defined (__BORLANDC__) +# if !defined (TEST_BUILD_DLL) +# pragma option push -Jgx +# endif +#endif +TEST_SINGLETON_DECLARE (ACE_Singleton, test_class, ACE_Null_Mutex) +#if defined (__BORLANDC__) +# if !defined (TEST_BUILD_DLL) +# pragma option pop +# endif +#endif + +typedef ACE_Singleton<test_class, ACE_Null_Mutex> TEST_SINGLETON; + +Test_Export test_class *get_dll_singleton (); diff --git a/ACE/examples/Export/run_test.pl b/ACE/examples/Export/run_test.pl new file mode 100755 index 00000000000..7c84078d8ff --- /dev/null +++ b/ACE/examples/Export/run_test.pl @@ -0,0 +1,17 @@ +eval '(exit $?0)' && eval 'exec perl -S $0 ${1+"$@"}' + & eval 'exec perl -S $0 $argv:q' + if 0; + +# $Id$ +# -*- perl -*- + +use lib "../../bin"; +use PerlACE::Run_Test; + +$TEST = new PerlACE::Process ("test"); + +$status = $TEST->SpawnWaitKill (20); + +$status = 1 if ($status < 0); + +exit $status; diff --git a/ACE/examples/Export/test.cpp b/ACE/examples/Export/test.cpp new file mode 100644 index 00000000000..c04f2998e66 --- /dev/null +++ b/ACE/examples/Export/test.cpp @@ -0,0 +1,64 @@ +// $Id$ + +#include "dll.h" +#include <ace/streams.h> + +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + int failure_count = 0; + test_class my_test_class; + + // Tet out the export of a class. I don't see + // How this can fail at runtime (rather it would + // probably give link errors), but just in case... + + cout << "Method Test: "; + if (my_test_class.method () != RETVAL) + { + cout << "Failed" << endl; + ++failure_count; + } + else + cout << "Succeeded" << endl; + + // Test out the export of a function. Like above, + // I don't know how this can fail at runtime. + + cout << "Function Test: "; + if (test_function () != RETVAL) + { + cout << "Failed" << endl; + ++failure_count; + } + else + cout << "Succeeded" << endl; + + // Also test out the export of data. + + cout << "Variable Test: "; + if (test_variable != RETVAL) + { + cout << "Failed" << endl; + ++failure_count; + } + else + cout << "Succeeded" << endl; + + + // Test out the ACE_Singleton export by checking to see + // that we have the same instance pointer as the DLL does. + // This can fail at runtime. + + cout << "Singleton Test: "; + if (TEST_SINGLETON::instance () != get_dll_singleton ()) + { + cout << "Failed" << endl; + ++failure_count; + } + else + cout << "Succeeded" << endl; + + // Return the number of failures + return failure_count; +} diff --git a/ACE/examples/Export/test_export.h b/ACE/examples/Export/test_export.h new file mode 100644 index 00000000000..45ee8296d22 --- /dev/null +++ b/ACE/examples/Export/test_export.h @@ -0,0 +1,44 @@ +// -*- C++ -*- +// $Id$ +// Definition for Win32 Export directives. +// This file is generated automatically by +// generate_export_file.pl +// ------------------------------ +#if !defined (TEST_EXPORT_H) +#define TEST_EXPORT_H + +#include "ace/config-all.h" + +#if defined (ACE_AS_STATIC_LIBS) && !defined (TEST_HAS_DLL) +# define TEST_HAS_DLL 0 +#endif /* ACE_AS_STATIC_LIBS && ! TEST_HAS_DLL */ + +#if !defined (TEST_HAS_DLL) +#define TEST_HAS_DLL 1 +#endif /* ! TEST_HAS_DLL */ + +#if defined (TEST_HAS_DLL) +# if (TEST_HAS_DLL == 1) +# if defined (TEST_BUILD_DLL) +# define Test_Export ACE_Proper_Export_Flag +# define TEST_SINGLETON_DECLARATION(T) ACE_EXPORT_SINGLETON_DECLARATION (T) +# define TEST_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) ACE_EXPORT_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) +# else +# define Test_Export ACE_Proper_Import_Flag +# define TEST_SINGLETON_DECLARATION(T) ACE_IMPORT_SINGLETON_DECLARATION (T) +# define TEST_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) ACE_IMPORT_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) +# endif /* TEST_BUILD_DLL */ +# else +# define Test_Export +# define TEST_SINGLETON_DECLARATION(T) +# define TEST_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) +# endif /* ! TEST_HAS_DLL == 1 */ +#else +# define Test_Export +# define TEST_SINGLETON_DECLARATION(T) +# define TEST_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) +#endif /* TEST_HAS_DLL */ + +#endif /* TEST_EXPORT_H */ + +// End of auto generated file. diff --git a/ACE/examples/IOStream/Makefile.am b/ACE/examples/IOStream/Makefile.am new file mode 100644 index 00000000000..0a99932ce34 --- /dev/null +++ b/ACE/examples/IOStream/Makefile.am @@ -0,0 +1,14 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +SUBDIRS = \ + client \ + server + diff --git a/ACE/examples/IOStream/README b/ACE/examples/IOStream/README new file mode 100644 index 00000000000..ab215fc779d --- /dev/null +++ b/ACE/examples/IOStream/README @@ -0,0 +1,22 @@ +This example illustrates the use of the ACE_IOStream and +ACE_Streambuf_T templates to create an object based on ACE_*_Stream +classes. These classes provide C++ iostream functionality across a +socket. + +To run the tests simply build the executables in the client and server +directories and then do the following in separate windows: + +# Window 1 +% server/iostream_server +(10049) starting up daemon + +# Window 2 +% client/iostream_client +(10049) starting handler 456d0 +(10049) Client sent: + (1) (2.3) +(10051) Server sent: + (1) (2.3) +(10049) connection closed +(10049) shutting down handler 456d0 +(10049) shutting down server daemon diff --git a/ACE/examples/IOStream/client/.cvsignore b/ACE/examples/IOStream/client/.cvsignore new file mode 100644 index 00000000000..e5eeb0703df --- /dev/null +++ b/ACE/examples/IOStream/client/.cvsignore @@ -0,0 +1,2 @@ +iostream_client +iostream_client diff --git a/ACE/examples/IOStream/client/IOStream_Client.mpc b/ACE/examples/IOStream/client/IOStream_Client.mpc new file mode 100644 index 00000000000..ca6b8ee6622 --- /dev/null +++ b/ACE/examples/IOStream/client/IOStream_Client.mpc @@ -0,0 +1,5 @@ +// -*- MPC -*- +// $Id$ + +project : aceexe { +}
\ No newline at end of file diff --git a/ACE/examples/IOStream/client/Makefile.am b/ACE/examples/IOStream/client/Makefile.am new file mode 100644 index 00000000000..e1225bbb6d5 --- /dev/null +++ b/ACE/examples/IOStream/client/Makefile.am @@ -0,0 +1,30 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +ACE_BUILDDIR = $(top_builddir) +ACE_ROOT = $(top_srcdir) + +## Makefile.IOStream_Client.am +noinst_LTLIBRARIES = libIOStream_Client.la + +libIOStream_Client_la_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +libIOStream_Client_la_SOURCES = \ + iostream_client.cpp + +## Clean up template repositories, etc. +clean-local: + -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.* + -rm -f gcctemp.c gcctemp so_locations *.ics + -rm -rf cxx_repository ptrepository ti_files + -rm -rf templateregistry ir.out + -rm -rf ptrepository SunWS_cache Templates.DB diff --git a/ACE/examples/IOStream/client/iostream_client.cpp b/ACE/examples/IOStream/client/iostream_client.cpp new file mode 100644 index 00000000000..e8ddedf9b44 --- /dev/null +++ b/ACE/examples/IOStream/client/iostream_client.cpp @@ -0,0 +1,71 @@ +// $Id$ + +#include "ace/SOCK_Connector.h" +#include "ace/IOStream.h" +#include "ace/Log_Msg.h" +#include "ace/OS_NS_stdlib.h" +#include "ace/OS_NS_unistd.h" + +ACE_RCSID (client, + iostream_client, + "$Id$") + +// This client is a simple example of using the ACE_IOStream and +// ACE_Streambuf_T templates to create an object based on ACE_*_Stream +// classes, which mimic a C++ iostream. + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ +#if !defined (ACE_LACKS_ACE_IOSTREAM) + const ACE_TCHAR *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; + + ACE_IOStream<ACE_SOCK_Stream> server; + ACE_SOCK_Connector connector; + ACE_INET_Addr addr (server_port, + server_host); + + if (connector.connect (server, addr) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "open"), + -1); + + // Buffer up some things to send to the server. + server << "1 2.3 testing" << endl; + + int i; + float f; + +#if defined (ACE_HAS_STRING_CLASS) + ACE_IOStream_String s1; + ACE_IOStream_String s2; + server >> s1 >> i >> f >> s2; + + cerr << "Server said:\n\t"; + cerr << s1 << " "; + cerr << i << " "; + cerr << f << " "; + cerr << s2 << endl; +#else + server >> i >> f; + + cerr << "(" << ACE_OS::getpid () << ") Server sent:\n\t"; + cerr << "(" << i << ") "; + cerr << "(" << f << ")" << endl; +#endif /* ACE_HAS_STRING_CLASS */ + + if (server.close () == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "close"), + -1); +#else + ACE_UNUSED_ARG (argc); + ACE_UNUSED_ARG (argv); + ACE_ERROR ((LM_ERROR, "ACE_IOSTREAM not supported on this platform\n")); +#endif /* !ACE_LACKS_ACE_IOSTREAM */ + return 0; +} + diff --git a/ACE/examples/IOStream/server/.cvsignore b/ACE/examples/IOStream/server/.cvsignore new file mode 100644 index 00000000000..e37ecb3f31b --- /dev/null +++ b/ACE/examples/IOStream/server/.cvsignore @@ -0,0 +1,2 @@ +iostream_server +iostream_server diff --git a/ACE/examples/IOStream/server/IOStream_Server.mpc b/ACE/examples/IOStream/server/IOStream_Server.mpc new file mode 100644 index 00000000000..ca6b8ee6622 --- /dev/null +++ b/ACE/examples/IOStream/server/IOStream_Server.mpc @@ -0,0 +1,5 @@ +// -*- MPC -*- +// $Id$ + +project : aceexe { +}
\ No newline at end of file diff --git a/ACE/examples/IOStream/server/Makefile.am b/ACE/examples/IOStream/server/Makefile.am new file mode 100644 index 00000000000..8b72a1adb62 --- /dev/null +++ b/ACE/examples/IOStream/server/Makefile.am @@ -0,0 +1,33 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +ACE_BUILDDIR = $(top_builddir) +ACE_ROOT = $(top_srcdir) + +## Makefile.IOStream_Server.am +noinst_LTLIBRARIES = libIOStream_Server.la + +libIOStream_Server_la_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +libIOStream_Server_la_SOURCES = \ + iostream_server.cpp + +noinst_HEADERS = \ + iostream_server.h + +## Clean up template repositories, etc. +clean-local: + -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.* + -rm -f gcctemp.c gcctemp so_locations *.ics + -rm -rf cxx_repository ptrepository ti_files + -rm -rf templateregistry ir.out + -rm -rf ptrepository SunWS_cache Templates.DB diff --git a/ACE/examples/IOStream/server/iostream_server.cpp b/ACE/examples/IOStream/server/iostream_server.cpp new file mode 100644 index 00000000000..656b432a579 --- /dev/null +++ b/ACE/examples/IOStream/server/iostream_server.cpp @@ -0,0 +1,132 @@ +// $Id$ + +// This is a simple example of using the ACE_IOStream and +// ACE_Streambuf_T templates to create an object based on ACE_*_Stream +// classes, which mimic a C++ iostream. + +#include "ace/Acceptor.h" +#include "ace/SOCK_Acceptor.h" +#include "ace/Service_Config.h" +#include "ace/Signal.h" + +#include "iostream_server.h" +#include "ace/OS_NS_unistd.h" + +ACE_RCSID(server, iostream_server, "$Id$") + +#if !defined (ACE_LACKS_ACE_IOSTREAM) + +int +Handler::open (void *) +{ + if (this->reactor ()->register_handler (this, + ACE_Event_Handler::READ_MASK) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "registering connection handler with ACE_Reactor\n"), + -1); + return 0; +} + +Handler::Handler (void) +{ + ACE_DEBUG ((LM_DEBUG, "(%P) starting handler %x\n", this)); +} + +Handler::~Handler (void) +{ + ACE_DEBUG ((LM_DEBUG, "(%P) shutting down handler %x\n", this)); + ACE_Reactor::end_event_loop (); +} + +int +Handler::handle_input (ACE_HANDLE) +{ + int i; + float f; + + // Check to see if the socket is closed down. + if (this->peer ().eof ()) + ACE_ERROR_RETURN ((LM_ERROR, "(%P) connection closed\n"), -1); + +#if defined (ACE_HAS_STRING_CLASS) + ACE_IOStream_String s; + + if (!(this->peer () >> i >> f >> s)) + ACE_ERROR_RETURN ((LM_ERROR, "(%P) %p\n", "error getting data"), -1); + + cerr << "(" << ACE_OS::getpid () << ") Client sent:\n\t"; + cerr << "(" << i << ") (" << f << ") (" << s << ")" << endl ; + + if (!(this->peer () << "Received: " << i << " " << f << " " << s << endl)) + ACE_ERROR_RETURN ((LM_ERROR, "(%P) %p\n", "error sending data"), -1); + +#else + if (!(this->peer () >> i >> f)) + ACE_ERROR_RETURN ((LM_ERROR, "(%P) %p\n", "error getting data"), -1); + + cerr << "(" << ACE_OS::getpid () << ") Client sent:\n\t"; + cerr << "(" << i << ") (" << f << ")" << endl; + + if (!(this->peer () << i << " " << f << endl)) + ACE_ERROR_RETURN ((LM_ERROR, "(%P) %p\n", "error sending data"), -1); +#endif /* ACE_HAS_STRING_CLASS */ + + // In order to flush the output to the peer, we have to use the sync + // () function. Some iostreams implementations let us use a 'flush' + // function much like the 'endl' function. + + // this->peer ().sync (); + return 0; +} + +// Create a factory object that will accept new connection requests +// and create handler objects for us. + +typedef ACE_Acceptor<Handler, ACE_SOCK_ACCEPTOR> IOStream_Acceptor; +#endif /* !ACE_LACKS_ACE_IOSTREAM */ + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv []) +{ +#if !defined (ACE_LACKS_ACE_IOSTREAM) + ACE_Service_Config daemon; + + // Create an adapter to end the event loop. + ACE_Sig_Adapter sa ((ACE_Sig_Handler_Ex) ACE_Reactor::end_event_loop); + + ACE_Sig_Set sig_set; + sig_set.sig_add (SIGINT); + sig_set.sig_add (SIGQUIT); + + // Register ourselves to receive SIGINT and SIGQUIT so we can shut + // down gracefully via signals. + if (ACE_Reactor::instance ()->register_handler (sig_set, + &sa) == -1) + ACE_ERROR_RETURN ((LM_ERROR, "%p\n"), -1); + + IOStream_Acceptor peer_acceptor; + + ACE_INET_Addr addr (argc > 1 ? ACE_OS::atoi (argv[1]) : ACE_DEFAULT_SERVER_PORT); + + if (peer_acceptor.open (addr) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "open"), + -1); + + ACE_DEBUG ((LM_DEBUG, + "(%P) starting up daemon\n")); + + ACE_Reactor::run_event_loop (); + + ACE_DEBUG ((LM_DEBUG, + "(%P) shutting down server daemon\n")); + +#else + ACE_UNUSED_ARG (argc); + ACE_UNUSED_ARG (argv); + ACE_ERROR ((LM_ERROR, "ACE_IOSTREAM not supported on this platform\n")); +#endif /* !ACE_LACKS_ACE_IOSTREAM */ + return 0; +} + diff --git a/ACE/examples/IOStream/server/iostream_server.h b/ACE/examples/IOStream/server/iostream_server.h new file mode 100644 index 00000000000..e5f4cbd63b9 --- /dev/null +++ b/ACE/examples/IOStream/server/iostream_server.h @@ -0,0 +1,53 @@ +// $Id$ + +// This file defines the class needed for iostream_server.cpp - it's a separate +// file to satisfy IBM's xlC template instantiation. + +#ifndef __IOSTREAM_SERVER_H +#define __IOSTREAM_SERVER_H + +#include "ace/INET_Addr.h" +#include "ace/IOStream.h" +#include "ace/SOCK_Stream.h" +#include "ace/Svc_Handler.h" + +#if !defined (ACE_LACKS_ACE_IOSTREAM) + +// Declare a new type which will case an ACE_SOCK_Stream to behave +// like an iostream. The new ACE_SOCK_IOStream type can be used +// anywhere an ACE_SOCK_Stream is used. + +typedef ACE_IOStream<ACE_SOCK_Stream> ACE_SOCK_IOStream; + +// Need to handle brain-dead C++ compilers. +#if defined (ACE_HAS_TEMPLATE_TYPEDEFS) +#define ACE_SOCK_IOSTREAM ACE_SOCK_IOStream +#else +#define ACE_SOCK_IOSTREAM ACE_SOCK_IOStream, ACE_INET_Addr +#endif /* ACE_HAS_TYPENAME_KEYWORD */ + +class Handler : public ACE_Svc_Handler<ACE_SOCK_IOSTREAM, ACE_NULL_SYNCH> + // = TITLE + // Extend the <ACE_Svc_Handler> template to do our bidding. + // + // = DESCRIPTION + // Create an <ACE_Svc_Handler> object based on our + // iostream/SOCK_Stream hybrid. All of this is fairly standard + // until we get to the <handle_input> where we begin using the + // iostream characteristics of the peer. +{ +public: + // = Initialization and termination methods. + Handler (void); + ~Handler (void); + + // = <Svc_Handler> hooks. + virtual int open (void *); + + // = <Event_Handler> hooks. + virtual int handle_input (ACE_HANDLE); +}; + +#endif /* ACE_LACKS_ACE_IOSTREAM */ + +#endif /* __IOSTREAM_SERVER_H */ diff --git a/ACE/examples/IPC_SAP/ATM_SAP/.cvsignore b/ACE/examples/IPC_SAP/ATM_SAP/.cvsignore new file mode 100644 index 00000000000..955ffdc75d5 --- /dev/null +++ b/ACE/examples/IPC_SAP/ATM_SAP/.cvsignore @@ -0,0 +1,4 @@ +client +client +server +server diff --git a/ACE/examples/IPC_SAP/ATM_SAP/CPP-client.cpp b/ACE/examples/IPC_SAP/ATM_SAP/CPP-client.cpp new file mode 100644 index 00000000000..cbe2c00ae5c --- /dev/null +++ b/ACE/examples/IPC_SAP/ATM_SAP/CPP-client.cpp @@ -0,0 +1,202 @@ +// $Id$ + +#include "ace/OS_main.h" +#include "ace/ATM_Connector.h" +#include "ace/ATM_Addr.h" +#include "ace/High_Res_Timer.h" +#include "ace/Log_Msg.h" + +ACE_RCSID(ATM_SAP, CPP_client, "$Id$") + +#if defined (ACE_HAS_ATM) + +#define MAX_LEAVES 32 + +/* ACE_ATM Client */ + +int ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + if ( argc < 2 ) + ACE_ERROR_RETURN ((LM_ERROR, + "Usage: %s <rate> <PDU> <session> <host> <selector> [ host sel ] ...\n" + "\tUse 0 for default values\n", + argv[0]), + 1); + + int rate = ACE_OS::atoi( argv[ 1 ]); + rate = ( rate != 0 ) ? rate : 170000; + int pdu_size = ACE_OS::atoi( argv[ 2 ]) * 1024; + pdu_size = ( pdu_size != 0 ) ? pdu_size : 8192; + int session = ACE_OS::atoi( argv[ 3 ]); + session = ( session != 0 ) ? session : 100; + + ACE_OS::printf( "ATM_Client: rate: %d c/s, PDU: %dB, session: %d pkts\n", + rate, pdu_size, session ); + + // Record all hosts/selectors + ACE_ATM_Addr hosts[ MAX_LEAVES ]; + int num_leaves = argc / 2 - 2; + + ACE_OS::printf( "ATM_Client: Connecting to ...\n" ); + for ( int i = 0; i < num_leaves; i++ ) { + hosts[ i ].set( argv[ i*2 + 4 ], + ( argv[ i*2 + 5 ] != 0 ) + ? ACE_OS::atoi( argv[ i*2 + 5 ]) : ACE_ATM_Addr::DEFAULT_SELECTOR ); + ACE_OS::printf( "ATM_Client: leaf: %s (%s), sel: %d\n", + argv[ i*2 + 4 ], + hosts[ i ].addr_to_string(), + hosts[ i ].get_selector()); + } + + // The timeout really gets ignored since FORE's drivers don't work when + // ioctl or fcntl calls are made on the transport id/file descriptor + int timeout = ACE_DEFAULT_TIMEOUT; + char buf[BUFSIZ]; + ACE_ATM_Stream atm_stream; + + char hostname[ MAXNAMELEN ]; + ACE_OS::hostname( hostname, MAXNAMELEN ); + ACE_ATM_Addr local_addr( hostname, hosts[ 0 ].get_selector()); + + ACE_OS::printf( "ATM_Client: local host: %s(%s)\n", + hostname, local_addr.addr_to_string()); + + // In order to construct connections options the file handle is + // needed. Therefore, we need to open the ATM_Stream before we + // construct the options. + ACE_OS::printf( "ATM_Client: to open a stream\n" ); + if (atm_stream.open () == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "open failed"), + 1); + + ACE_DEBUG ((LM_DEBUG, + "ATM_Client: starting non-blocking connection\n")); + + // Initiate timed, non-blocking connection with server. + ACE_ATM_Connector con; + + // Construct QoS options - currently FORE only supports bandwidth + ACE_OS::printf( "ATM_Client: specify cell rate at %d c/s\n", rate ); + ACE_ATM_QoS qos; + qos.set_rate(atm_stream.get_handle (), + rate, + ACE_ATM_QoS::OPT_FLAGS_CPID); + + if ( num_leaves == 1 ) { + // Point-to-point connection + // Not sure why but reuse_addr set to true/1 causes problems for + // FORE/XTI/ATM - this is now handled in ACE_ATM_Connector::connect() + ACE_OS::printf( "ATM_Client: to open a connection \n" ); + ACE_ATM_Params params = ACE_ATM_Params(); + if (con.connect (atm_stream, + hosts[ 0 ], + params, + qos, + (ACE_Time_Value *) &ACE_Time_Value::zero, + local_addr, + 0, + 0 ) == -1) { + if (errno != EWOULDBLOCK) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "ATM_Client: connection failed"), + 1); + + ACE_DEBUG ((LM_DEBUG, + "ATM_Client: starting timed connection\n")); + + // Check if non-blocking connection is in progress, and wait up + // to timeout seconds for it to complete. + ACE_Time_Value tv (timeout); + + ACE_OS::printf( "ATM_Client: connection completed\n" ); + if (con.complete (atm_stream, + &hosts[ 0 ], + &tv) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "ATM_Client: connection failed"), + 1); + else + ACE_DEBUG ((LM_DEBUG, + "ATM_Client: connected to %s\n", + hosts[ 0 ].addr_to_string())); + } + } else { + // Point-to-multipoint connection + for ( int i = 0; i < num_leaves; i++ ) { + con.add_leaf( atm_stream, + hosts[ i ], + i, + NULL ); + + } + } /* if num_leaves == 1 */ + + ACE_UINT16 vpi, vci; + atm_stream.get_vpi_vci(vpi, vci); + ACE_DEBUG ((LM_DEBUG, + "ATM_Client: connected to VPI %d VCI %d\n", + vpi, vci)); + + // Send data to server (correctly handles "incomplete writes"). + + int s_bytes; + int total; + int xmit = 0; + ACE_High_Res_Timer timer; + ACE_Time_Value elapsed; + double real_time; + double actual_rate; + + for ( ;; ) { + total = 0; + + timer.start_incr(); + + for ( ;; ) { + s_bytes = atm_stream.send_n( buf, BUFSIZ, 0 ); + if ( s_bytes == -1 ) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "send_n"), + 1); + + total += s_bytes; + + if ( total >= session * pdu_size ) + break; + } + + timer.stop_incr(); + timer.elapsed_time_incr( elapsed ); + real_time = elapsed.sec() * ACE_ONE_SECOND_IN_USECS + elapsed.usec(); + xmit += total; + actual_rate = ( double )xmit * ( double )8 / real_time; + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%t) bytes = %d, usec = %f, rate = %0.00f Mbps\n"), + xmit, + real_time, + actual_rate < 0 ? 0 : actual_rate )); + } + + // Explicitly close the connection. + ACE_OS::printf( "ATM_Client: close connection\n" ); + if (atm_stream.close () == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "close"), + -1); + return 0; +} +#else +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_ERROR_RETURN ((LM_ERROR, + "your platform isn't configured to support ATM\n"), + 1); +} +#endif /* ACE_HAS_ATM */ diff --git a/ACE/examples/IPC_SAP/ATM_SAP/CPP-server.cpp b/ACE/examples/IPC_SAP/ATM_SAP/CPP-server.cpp new file mode 100644 index 00000000000..8cf6e9c9c92 --- /dev/null +++ b/ACE/examples/IPC_SAP/ATM_SAP/CPP-server.cpp @@ -0,0 +1,156 @@ +// $Id$ + +#include "ace/OS_main.h" +#include "ace/ATM_Acceptor.h" +#include "ace/ATM_Addr.h" +#include "ace/High_Res_Timer.h" +#include "ace/Log_Msg.h" + +ACE_RCSID(ATM_SAP, CPP_ATM_server, "$Id$") + +#if defined (ACE_HAS_ATM) +// ACE_ATM Server + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + ACE_Time_Value timeout (ACE_DEFAULT_TIMEOUT); + + //unsigned char selector = ACE_ATM_Addr::DEFAULT_SELECTOR; + //int selector_specified = 0; + + if (argc > 2) + ACE_ERROR_RETURN ((LM_ERROR, + "Usage: %s [selector]\n", + argv[0]), + 1); + + // Create a server address. + ACE_ATM_Addr addr; + //if (selector_specified) + unsigned char selector = ( argc == 2 ) ? ACE_OS::atoi( argv[ 1 ]) : ACE_ATM_Addr::DEFAULT_SELECTOR; + addr.set_selector( selector ); + ACE_OS::printf( "ATM_Server: selector changed to %d\n", addr.get_selector()); + + + // Create a server, reuse the addr. + ACE_ATM_Acceptor peer_acceptor; + ACE_ATM_Params params; + + // Not sure why but reuse_addr set to true/1 causes problems for + // FORE/XTI/ATM - this is now handled in ACE_ATM_Acceptor::open() + + ACE_HANDLE ret = peer_acceptor.open (addr, 5, params); + if ( ret == ACE_INVALID_HANDLE ) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "open"), + -1); + + ACE_ATM_Stream new_stream; + ACE_ATM_Addr local_addr; + + local_addr.set_selector( selector ); + peer_acceptor.get_local_addr( local_addr ); + + ACE_DEBUG ((LM_DEBUG, + "starting server at address %s\n", + local_addr.addr_to_string ())); + + // Performs the iterative server activities + char buf[BUFSIZ]; + ACE_High_Res_Timer timer; + int total; + ACE_Time_Value tv; + double real_time; + double actual_rate; + + for (;;) { + // Create a new ACE_ATM_Stream endpoint (note automatic restart + // if errno == EINTR). + ACE_OS::printf( "ATM_Server: expecting clients\n" ); + + if (peer_acceptor.accept (new_stream, + &addr, + &timeout) == -1) { + ACE_ERROR ((LM_ERROR, + "%p\n", + "accept")); + continue; + } + + ACE_OS::printf( "ATM_Server: got a connection\n" ); + + ACE_UINT16 vpi, vci; + vpi = vci = 0; + // This has problem on PMP connections on NT + //new_stream.get_vpi_vci(vpi, vci); + ACE_DEBUG ((LM_DEBUG, + "connected to VPI %d VCI %d\n", + vpi, vci)); + + ACE_OS::printf( "ATM_Server: connection accepted\n" ); + + ACE_DEBUG ((LM_DEBUG, + "client %s connected\n", + addr.addr_to_string ())); + ACE_DEBUG ((LM_DEBUG, + "client %s connected to host\n", + new_stream.get_peer_name ())); + + // Read data from client (terminate on error). + + int recvd = 0; + + for ( ;; ) { + total = 0; + timer.start_incr(); + + for (int r_bytes; + (r_bytes = new_stream.recv (buf, sizeof buf, 0)) > 0; ) { +// ACE_OS::printf( "ATM_Server: received %dB\n", r_bytes ); + +// if (ACE_OS::write (ACE_STDOUT, +// buf, +// r_bytes) != r_bytes) +// ACE_ERROR ((LM_ERROR, +// "%p\n", +// "ACE::send_n")); + total += r_bytes; + + if ( total > 10000000 ) + break; + + } + + timer.stop_incr(); + timer.elapsed_time_incr( tv ); + real_time = tv.sec() * ACE_ONE_SECOND_IN_USECS + tv.usec(); + recvd += total; + actual_rate = ( double )recvd * ( double )8 / real_time; + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%t) bytes = %d, usec = %f, rate = %0.00f Mbps\n"), + recvd, + real_time, + actual_rate < 0 ? 0 : actual_rate )); + } + + // Close new endpoint (listening endpoint stays open). + if (new_stream.close () == -1) + ACE_ERROR ((LM_ERROR, + "%p\n", + "close")); + } + + /* NOTREACHED */ + return 0; +} +#else +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_ERROR_RETURN ((LM_ERROR, + "your platform isn't configured to support ATM\n"), + 1); +} +#endif /* ACE_HAS_ATM */ diff --git a/ACE/examples/IPC_SAP/ATM_SAP/Makefile.am b/ACE/examples/IPC_SAP/ATM_SAP/Makefile.am new file mode 100644 index 00000000000..e3ee4011b05 --- /dev/null +++ b/ACE/examples/IPC_SAP/ATM_SAP/Makefile.am @@ -0,0 +1,46 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +ACE_BUILDDIR = $(top_builddir) +ACE_ROOT = $(top_srcdir) + +## Makefile.atm_sap_client.am +noinst_PROGRAMS = client + +client_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +client_SOURCES = \ + CPP-client.cpp + +client_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.atm_sap_server.am +noinst_PROGRAMS += server + +server_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +server_SOURCES = \ + CPP-server.cpp + +server_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Clean up template repositories, etc. +clean-local: + -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.* + -rm -f gcctemp.c gcctemp so_locations *.ics + -rm -rf cxx_repository ptrepository ti_files + -rm -rf templateregistry ir.out + -rm -rf ptrepository SunWS_cache Templates.DB diff --git a/ACE/examples/IPC_SAP/ATM_SAP/atm_sap.mpc b/ACE/examples/IPC_SAP/ATM_SAP/atm_sap.mpc new file mode 100644 index 00000000000..d0f716bb764 --- /dev/null +++ b/ACE/examples/IPC_SAP/ATM_SAP/atm_sap.mpc @@ -0,0 +1,16 @@ +// -*- MPC -*- +// $Id$ + +project(*client) : aceexe { + exename = client + Source_Files { + CPP-client.cpp + } +} + +project(*server) : aceexe { + exename = server + Source_Files { + CPP-server.cpp + } +}
\ No newline at end of file diff --git a/ACE/examples/IPC_SAP/DEV_SAP/Makefile.am b/ACE/examples/IPC_SAP/DEV_SAP/Makefile.am new file mode 100644 index 00000000000..bb95a489da6 --- /dev/null +++ b/ACE/examples/IPC_SAP/DEV_SAP/Makefile.am @@ -0,0 +1,14 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +SUBDIRS = \ + reader \ + writer + diff --git a/ACE/examples/IPC_SAP/DEV_SAP/README b/ACE/examples/IPC_SAP/DEV_SAP/README new file mode 100644 index 00000000000..8e47d8c5cec --- /dev/null +++ b/ACE/examples/IPC_SAP/DEV_SAP/README @@ -0,0 +1,23 @@ +This directory contains a test example for the DEV_SAP +class category. It implements a class TTY_IO that is +derived from ACE_DEV_IO and adds a control method +with specific features for a serial line connection +(e.g. /dev/ttya and /dev/ttyb on UNIX systems). + +The reader/reader executable initializes its +device-special file (given as command-line parameter), +reads characters from it (until it recognizes character 'q') +ands sends the characters read to stdout. + +The writer/writer executable also initializes its +device-special file (given as command-line parameter), +reads characters from stdin (until'q') and sends them +to the device. + +To run the tests I connect /dev/ttya and /dev/ttyb (with a +zero modem cable) and start the reader with "reader /dev/ttya" +and the writer (in a different window) with "writer /dev/ttyb". + +Characters typed in the writer window should now appear as output +in the reader window. Note that characters are buffered till EOL. + diff --git a/ACE/examples/IPC_SAP/DEV_SAP/reader/.cvsignore b/ACE/examples/IPC_SAP/DEV_SAP/reader/.cvsignore new file mode 100644 index 00000000000..a8dd7d50c82 --- /dev/null +++ b/ACE/examples/IPC_SAP/DEV_SAP/reader/.cvsignore @@ -0,0 +1,2 @@ +reader +reader diff --git a/ACE/examples/IPC_SAP/DEV_SAP/reader/Makefile.am b/ACE/examples/IPC_SAP/DEV_SAP/reader/Makefile.am new file mode 100644 index 00000000000..bff70f43cd3 --- /dev/null +++ b/ACE/examples/IPC_SAP/DEV_SAP/reader/Makefile.am @@ -0,0 +1,38 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +ACE_BUILDDIR = $(top_builddir) +ACE_ROOT = $(top_srcdir) + + +## Makefile.dev_sap_reader.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS = reader + +reader_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +reader_SOURCES = \ + reader.cpp + +reader_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Clean up template repositories, etc. +clean-local: + -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.* + -rm -f gcctemp.c gcctemp so_locations *.ics + -rm -rf cxx_repository ptrepository ti_files + -rm -rf templateregistry ir.out + -rm -rf ptrepository SunWS_cache Templates.DB diff --git a/ACE/examples/IPC_SAP/DEV_SAP/reader/dev_sap_reader.mpc b/ACE/examples/IPC_SAP/DEV_SAP/reader/dev_sap_reader.mpc new file mode 100644 index 00000000000..a6535c82e82 --- /dev/null +++ b/ACE/examples/IPC_SAP/DEV_SAP/reader/dev_sap_reader.mpc @@ -0,0 +1,11 @@ +// -*- MPC -*- +// $Id$ + +project : aceexe { + avoids += ace_for_tao + exename = reader + Source_Files { + reader.cpp + } +} + diff --git a/ACE/examples/IPC_SAP/DEV_SAP/reader/reader.cpp b/ACE/examples/IPC_SAP/DEV_SAP/reader/reader.cpp new file mode 100644 index 00000000000..348db5e27e7 --- /dev/null +++ b/ACE/examples/IPC_SAP/DEV_SAP/reader/reader.cpp @@ -0,0 +1,69 @@ +// $Id$ + +#include "ace/DEV_Addr.h" +#include "ace/DEV_Connector.h" +#include "ace/TTY_IO.h" + +ACE_RCSID(reader, reader, "$Id$") + +int ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + if (argc < 2) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("usage: %s device-filename\n"), + argv[0]), + 1); + + ACE_TTY_IO read_dev; + ACE_DEV_Connector con; + + if (con.connect (read_dev, + ACE_DEV_Addr (argv[1])) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + argv[1]), + 1); + + ACE_TTY_IO::Serial_Params myparams; + myparams.baudrate = 9600; + myparams.xonlim = 0; + myparams.xofflim = 0; + myparams.readmincharacters = 0; + myparams.readtimeoutmsec = 10000; + myparams.paritymode = "EVEN"; + myparams.ctsenb = false; + myparams.rtsenb = 0; + myparams.xinenb = false; + myparams.xoutenb = false; + myparams.modem = false; + myparams.rcvenb = true; + myparams.dsrenb = false; + myparams.dtrdisable = false; + myparams.databits = 8; + myparams.stopbits = 1; + + if (read_dev.control (ACE_TTY_IO::SETPARAMS, + &myparams) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p control\n"), + argv[1]), + 1); + + // Read till character 'q'. + for (char readback = 'x'; readback != 'q'; ) + { + ssize_t bytes_read = + read_dev.recv ((void *) &readback, 1); + + if (bytes_read == 1) + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("read: %c\n"), + readback)); + else if (bytes_read == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p recv\n"), + argv[1]), 1); + } + + return 0; +} diff --git a/ACE/examples/IPC_SAP/DEV_SAP/writer/.cvsignore b/ACE/examples/IPC_SAP/DEV_SAP/writer/.cvsignore new file mode 100644 index 00000000000..d66df395ab8 --- /dev/null +++ b/ACE/examples/IPC_SAP/DEV_SAP/writer/.cvsignore @@ -0,0 +1,2 @@ +writer +writer diff --git a/ACE/examples/IPC_SAP/DEV_SAP/writer/Makefile.am b/ACE/examples/IPC_SAP/DEV_SAP/writer/Makefile.am new file mode 100644 index 00000000000..613a8d08102 --- /dev/null +++ b/ACE/examples/IPC_SAP/DEV_SAP/writer/Makefile.am @@ -0,0 +1,38 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +ACE_BUILDDIR = $(top_builddir) +ACE_ROOT = $(top_srcdir) + + +## Makefile.dev_sap_writer.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS = writer + +writer_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +writer_SOURCES = \ + writer.cpp + +writer_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Clean up template repositories, etc. +clean-local: + -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.* + -rm -f gcctemp.c gcctemp so_locations *.ics + -rm -rf cxx_repository ptrepository ti_files + -rm -rf templateregistry ir.out + -rm -rf ptrepository SunWS_cache Templates.DB diff --git a/ACE/examples/IPC_SAP/DEV_SAP/writer/dev_sap_writer.mpc b/ACE/examples/IPC_SAP/DEV_SAP/writer/dev_sap_writer.mpc new file mode 100644 index 00000000000..75486584b6d --- /dev/null +++ b/ACE/examples/IPC_SAP/DEV_SAP/writer/dev_sap_writer.mpc @@ -0,0 +1,11 @@ +// -*- MPC -*- +// $Id$ + +project : aceexe { + avoids += ace_for_tao + exename = writer + Source_Files { + writer.cpp + } +} + diff --git a/ACE/examples/IPC_SAP/DEV_SAP/writer/writer.cpp b/ACE/examples/IPC_SAP/DEV_SAP/writer/writer.cpp new file mode 100644 index 00000000000..44fc262ed61 --- /dev/null +++ b/ACE/examples/IPC_SAP/DEV_SAP/writer/writer.cpp @@ -0,0 +1,77 @@ +// $Id$ + +#include "ace/DEV_Connector.h" +#include "ace/TTY_IO.h" +#include "ace/OS_NS_unistd.h" + +ACE_RCSID(writer, writer, "$Id$") + +int ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + if (argc < 2) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("usage: %s device-filename\n"), + argv[0]), 1); + + ACE_TTY_IO write_dev; + ACE_DEV_Connector con; + + if (con.connect (write_dev, + ACE_DEV_Addr (argv[1])) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + argv[1]), + 1); + + ACE_TTY_IO::Serial_Params myparams; + myparams.baudrate = 9600; + myparams.xonlim = 0; + myparams.xofflim = 0; + myparams.readmincharacters = 0; + myparams.readtimeoutmsec = 10000; + myparams.paritymode = "EVEN"; + myparams.ctsenb = false; + myparams.rtsenb = 0; + myparams.xinenb = false; + myparams.xoutenb = false; + myparams.modem = false; + myparams.rcvenb = true; + myparams.dsrenb = false; + myparams.dtrdisable = false; + myparams.databits = 8; + myparams.stopbits = 1; + + if (write_dev.control (ACE_TTY_IO::SETPARAMS, + &myparams) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("control")), + 1); + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("enter character to send, q terminates :\n"))); + + for (char writeto; + ACE_OS::read (ACE_STDIN, &writeto, 1) != -1; + ) + { + ssize_t bytes_written = + write_dev.send_n ((void *) &writeto, + 1); + + if (bytes_written != 1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("send")), + 1); + if (writeto == 'q') + break; + } + + if (write_dev.close () == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("close")), + 1); + return 0; +} diff --git a/ACE/examples/IPC_SAP/FIFO_SAP/.cvsignore b/ACE/examples/IPC_SAP/FIFO_SAP/.cvsignore new file mode 100644 index 00000000000..5d0734ead63 --- /dev/null +++ b/ACE/examples/IPC_SAP/FIFO_SAP/.cvsignore @@ -0,0 +1,10 @@ +FIFO-Msg-client +FIFO-Msg-client +FIFO-Msg-server +FIFO-Msg-server +FIFO-client +FIFO-client +FIFO-server +FIFO-server +FIFO-test +FIFO-test diff --git a/ACE/examples/IPC_SAP/FIFO_SAP/FIFO-Msg-client.cpp b/ACE/examples/IPC_SAP/FIFO_SAP/FIFO-Msg-client.cpp new file mode 100644 index 00000000000..3f267ba66ce --- /dev/null +++ b/ACE/examples/IPC_SAP/FIFO_SAP/FIFO-Msg-client.cpp @@ -0,0 +1,43 @@ +// $Id$ + +#include "ace/FIFO_Send_Msg.h" +#include "ace/OS_NS_stdio.h" +#include "ace/OS_main.h" +#include "ace/OS_NS_stdlib.h" +#include "ace/OS_NS_time.h" +#include "ace/OS_NS_string.h" + +ACE_RCSID(FIFO_SAP, FIFO_Msg_client, "$Id$") + +#if defined (ACE_HAS_STREAM_PIPES) + +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_FIFO_Send_Msg client (ACE_DEFAULT_RENDEZVOUS); + + char buf[BUFSIZ]; + ACE_Str_Buf msg (buf); + + ACE_OS::srand (unsigned (ACE_OS::time (0))); + + while (ACE_OS::fgets (buf, sizeof buf, stdin) != 0) + { + msg.len = ACE_OS::strlen (buf) + 1; + if (client.send (ACE_OS::rand () % 11, &msg) == -1) + ::perror ("send"); + } + + if (client.close () == -1) + ACE_OS::perror ("close"), ACE_OS::exit (1); + + return 0; +} +#else +#include "ace/os_include/os_stdio.h" +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_OS::fprintf (stderr, "This feature is not supported\n"); + return 0; +} +#endif /* ACE_HAS_STREAM_PIPES */ diff --git a/ACE/examples/IPC_SAP/FIFO_SAP/FIFO-Msg-server.cpp b/ACE/examples/IPC_SAP/FIFO_SAP/FIFO-Msg-server.cpp new file mode 100644 index 00000000000..fc96ec71dbb --- /dev/null +++ b/ACE/examples/IPC_SAP/FIFO_SAP/FIFO-Msg-server.cpp @@ -0,0 +1,49 @@ +// $Id$ + +#include "ace/FIFO_Recv_Msg.h" +#include "ace/Log_Msg.h" +#include "ace/OS_NS_stdio.h" +#include "ace/OS_NS_unistd.h" +#include "ace/OS_NS_stdlib.h" +#include "ace/OS_NS_stropts.h" +#include "ace/OS_main.h" + +ACE_RCSID(FIFO_SAP, FIFO_Msg_server, "$Id$") + +#if defined (ACE_HAS_STREAM_PIPES) + +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_OS::unlink (ACE_DEFAULT_RENDEZVOUS); + ACE_FIFO_Recv_Msg server (ACE_DEFAULT_RENDEZVOUS); + char buf[BUFSIZ]; + ACE_Str_Buf msg (buf, 0, sizeof buf); + int flags = MSG_ANY; + int band = 0; + int n; + + while ((n = server.recv (&band, &msg, (ACE_Str_Buf *) 0, &flags)) >= 0) + { + if (msg.len == 0) + break; + else + ACE_DEBUG ((LM_DEBUG, "%4d (%4d): %*s", + msg.len, band, msg.len, msg.buf)); + flags = MSG_ANY; + band = 0; + } + + if (n == -1) + ACE_OS::perror ("recv"), ACE_OS::exit (1); + + return 0; +} +#else +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_ERROR ((LM_INFO, + ACE_TEXT ("This feature is not supported\n"))); + return 0; +} +#endif /* ACE_HAS_STREAM_PIPES */ diff --git a/ACE/examples/IPC_SAP/FIFO_SAP/FIFO-client.cpp b/ACE/examples/IPC_SAP/FIFO_SAP/FIFO-client.cpp new file mode 100644 index 00000000000..8c80809f380 --- /dev/null +++ b/ACE/examples/IPC_SAP/FIFO_SAP/FIFO-client.cpp @@ -0,0 +1,29 @@ +// $Id$ + +#include "ace/FIFO_Send.h" +#include "ace/Log_Msg.h" +#include "ace/OS_NS_string.h" +#include "ace/OS_NS_stdio.h" +#include "ace/OS_main.h" + +ACE_RCSID(FIFO_SAP, FIFO_client, "$Id$") + +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_FIFO_Send client (ACE_DEFAULT_RENDEZVOUS); + ACE_TCHAR buf[BUFSIZ]; + + while (ACE_OS::fgets (buf, sizeof buf, stdin) != 0) + { + ssize_t n = ACE_OS::strlen (buf); + + if (client.send (buf, n) != n) + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "send"), 1); + } + + if (client.close () == -1) + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "close"), 1); + + return 0; +} diff --git a/ACE/examples/IPC_SAP/FIFO_SAP/FIFO-server.cpp b/ACE/examples/IPC_SAP/FIFO_SAP/FIFO-server.cpp new file mode 100644 index 00000000000..4cd32c03449 --- /dev/null +++ b/ACE/examples/IPC_SAP/FIFO_SAP/FIFO-server.cpp @@ -0,0 +1,30 @@ +// $Id$ + +#include "ace/FIFO_Recv.h" +#include "ace/Log_Msg.h" +#include "ace/OS_NS_stdio.h" +#include "ace/OS_NS_unistd.h" +#include "ace/OS_main.h" + +ACE_RCSID(FIFO_SAP, FIFO_server, "$Id$") + +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_OS::unlink (ACE_DEFAULT_RENDEZVOUS); + ACE_FIFO_Recv server (ACE_DEFAULT_RENDEZVOUS); + char buf[BUFSIZ]; + int n; + + while ((n = server.recv (buf, sizeof buf)) > 0) + { + ACE_OS::printf ("%4d: ", n); + ACE_OS::fflush (stdout); + ACE_OS::write (ACE_STDOUT, buf, n); + } + + if (n == -1) + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "recv"), 1); + + return 0; +} diff --git a/ACE/examples/IPC_SAP/FIFO_SAP/FIFO-test.cpp b/ACE/examples/IPC_SAP/FIFO_SAP/FIFO-test.cpp new file mode 100644 index 00000000000..d6911908658 --- /dev/null +++ b/ACE/examples/IPC_SAP/FIFO_SAP/FIFO-test.cpp @@ -0,0 +1,122 @@ +// $Id$ + +// Purpose: This program uses ACE_FIFO wrappers to perform +// interprocess communication between a parent process and a child +// process. The parents reads from an input file and writes it into +// the fifo. The child reads from the ACE_FIFO and executes the more +// command. + +#include "ace/FIFO_Recv.h" +#include "ace/FIFO_Send.h" +#include "ace/Log_Msg.h" +#include "ace/OS_NS_sys_wait.h" +#include "ace/OS_NS_unistd.h" +#include "ace/OS_NS_stdlib.h" +#include "ace/OS_NS_fcntl.h" + +ACE_RCSID(FIFO_SAP, FIFO_test, "$Id$") + +#define PERMS 0666 +#define EXEC_NAME "more" +#define EXEC_COMMAND_ARG "more" + +static const ACE_TCHAR *FIFO_NAME = ACE_TEXT ("/tmp/fifo"); + +static int +do_child (ACE_FIFO_Recv &fifo_reader) +{ + // Set child's stdin to read from the fifo. + if (ACE_OS::close (ACE_STDIN) == -1 + || ACE_OS::dup (fifo_reader.get_handle ()) == ACE_INVALID_HANDLE) + return -1; + + char *argv[2]; + argv[0] = const_cast<char *> (EXEC_COMMAND_ARG); + argv[1] = 0; + + if (ACE_OS::execvp (EXEC_NAME, argv) == -1) + return -1; + return 0; +} + +static int +do_parent (const ACE_TCHAR fifo_name[], + ACE_TCHAR input_filename[]) +{ + ACE_FIFO_Send fifo_sender (fifo_name, O_WRONLY | O_CREAT); + ssize_t len; + char buf[BUFSIZ]; + + if (fifo_sender.get_handle () == ACE_INVALID_HANDLE) + return -1; + + ACE_HANDLE inputfd = + ACE_OS::open (input_filename, O_RDONLY); + + if (inputfd == ACE_INVALID_HANDLE) + return -1; + + // Read from input file and write into input end of the fifo. + + while ((len = ACE_OS::read (inputfd, buf, sizeof buf)) > 0) + if (fifo_sender.send (buf, len) != len) + return -1; + + if (len == -1) + return -1; + + if (fifo_sender.remove () == -1) + return -1; + return 0; +} + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + ACE_LOG_MSG->open (argv[0]); + + if (argc != 2) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("usage: %n input-file\n"), + 1)); + ACE_OS::exit (1); + } + + ACE_FIFO_Recv fifo_reader (FIFO_NAME, O_RDONLY | O_CREAT, PERMS, 0); + + if (fifo_reader.get_handle () == ACE_INVALID_HANDLE) + return -1; + + pid_t child_pid = ACE_OS::fork (); + + switch (child_pid) + { + case -1: + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("%n: %p\n%a"), + ACE_TEXT ("fork"), + 1)); + case 0: + if (do_child (fifo_reader) == -1) + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("%n: %p\n%a"), + ACE_TEXT ("do_child"), + 1)); + default: + if (do_parent (FIFO_NAME, argv[1]) == -1) + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("%n: %p\n%a"), + ACE_TEXT ("do_parent"), + 1)); + + // wait for child to ACE_OS::exit. + if (ACE_OS::waitpid (child_pid, (ACE_exitcode *) 0, 0) == -1) + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("%n: %p\n%a"), + ACE_TEXT ("waitpid"), + 1)); + } + + return 0; +} diff --git a/ACE/examples/IPC_SAP/FIFO_SAP/Makefile.am b/ACE/examples/IPC_SAP/FIFO_SAP/Makefile.am new file mode 100644 index 00000000000..9a9cba4b837 --- /dev/null +++ b/ACE/examples/IPC_SAP/FIFO_SAP/Makefile.am @@ -0,0 +1,98 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +ACE_BUILDDIR = $(top_builddir) +ACE_ROOT = $(top_srcdir) + + +## Makefile.Fifo_Sap_Msg_Client.am +noinst_PROGRAMS = FIFO-Msg-client + +FIFO_Msg_client_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +FIFO_Msg_client_SOURCES = \ + FIFO-Msg-client.cpp + +FIFO_Msg_client_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Fifo_Sap_Msg_Server.am +noinst_PROGRAMS += FIFO-Msg-server + +FIFO_Msg_server_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +FIFO_Msg_server_SOURCES = \ + FIFO-Msg-server.cpp + +FIFO_Msg_server_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.fifo_sap_client.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS += FIFO-client + +FIFO_client_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +FIFO_client_SOURCES = \ + FIFO-client.cpp + +FIFO_client_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Makefile.fifo_sap_server.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS += FIFO-server + +FIFO_server_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +FIFO_server_SOURCES = \ + FIFO-server.cpp + +FIFO_server_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Makefile.fifo_sap_test.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS += FIFO-test + +FIFO_test_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +FIFO_test_SOURCES = \ + FIFO-test.cpp + +FIFO_test_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Clean up template repositories, etc. +clean-local: + -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.* + -rm -f gcctemp.c gcctemp so_locations *.ics + -rm -rf cxx_repository ptrepository ti_files + -rm -rf templateregistry ir.out + -rm -rf ptrepository SunWS_cache Templates.DB diff --git a/ACE/examples/IPC_SAP/FIFO_SAP/fifo_sap.mpc b/ACE/examples/IPC_SAP/FIFO_SAP/fifo_sap.mpc new file mode 100644 index 00000000000..1e6d04447e5 --- /dev/null +++ b/ACE/examples/IPC_SAP/FIFO_SAP/fifo_sap.mpc @@ -0,0 +1,42 @@ +// -*- MPC -*- +// $Id$ + +project(*client) : aceexe { + avoids += ace_for_tao + exename = FIFO-client + Source_Files { + FIFO-client.cpp + } +} + +project(*server) : aceexe { + avoids += ace_for_tao + exename = FIFO-server + Source_Files { + FIFO-server.cpp + } +} + +project(*Msg_Client) : aceexe { + exename = FIFO-Msg-client + Source_Files { + FIFO-Msg-client.cpp + } +} + +project(*Msg_Server) : aceexe { + exename = FIFO-Msg-server + Source_Files { + FIFO-Msg-server.cpp + } +} + +project(*test) : aceexe { + avoids += ace_for_tao + exename = FIFO-test + Source_Files { + FIFO-test.cpp + } +} + + diff --git a/ACE/examples/IPC_SAP/FILE_SAP/.cvsignore b/ACE/examples/IPC_SAP/FILE_SAP/.cvsignore new file mode 100644 index 00000000000..db648aa002d --- /dev/null +++ b/ACE/examples/IPC_SAP/FILE_SAP/.cvsignore @@ -0,0 +1,2 @@ +client +client diff --git a/ACE/examples/IPC_SAP/FILE_SAP/Makefile.am b/ACE/examples/IPC_SAP/FILE_SAP/Makefile.am new file mode 100644 index 00000000000..e39aa964edf --- /dev/null +++ b/ACE/examples/IPC_SAP/FILE_SAP/Makefile.am @@ -0,0 +1,38 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +ACE_BUILDDIR = $(top_builddir) +ACE_ROOT = $(top_srcdir) + + +## Makefile.file_sap_client.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS = client + +client_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +client_SOURCES = \ + client.cpp + +client_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Clean up template repositories, etc. +clean-local: + -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.* + -rm -f gcctemp.c gcctemp so_locations *.ics + -rm -rf cxx_repository ptrepository ti_files + -rm -rf templateregistry ir.out + -rm -rf ptrepository SunWS_cache Templates.DB diff --git a/ACE/examples/IPC_SAP/FILE_SAP/client.cpp b/ACE/examples/IPC_SAP/FILE_SAP/client.cpp new file mode 100644 index 00000000000..f26302f3b57 --- /dev/null +++ b/ACE/examples/IPC_SAP/FILE_SAP/client.cpp @@ -0,0 +1,90 @@ +// $Id$ + +#include "ace/OS_main.h" +#include "ace/FILE_Addr.h" +#include "ace/FILE_Connector.h" +#include "ace/FILE_IO.h" +#include "ace/OS_NS_string.h" +#include "ace/OS_NS_stdio.h" + +ACE_RCSID(FILE_SAP, client, "$Id$") + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + if (argc < 3 || argc > 3) + ACE_ERROR_RETURN ((LM_ERROR, + "usage: %s filename string\n", + argv[0]), + 1); + + ACE_TCHAR *readback = new ACE_TCHAR[ACE_OS::strlen (argv[1]) + 1]; + + ACE_FILE_Info fileinfo; + ACE_FILE_IO cli_file; + ACE_FILE_Connector con; + + if (con.connect (cli_file, + ACE_FILE_Addr (argv[1]), + 0, + ACE_Addr::sap_any, 0, + O_RDWR|O_APPEND|O_CREAT, + ACE_DEFAULT_FILE_PERMS) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n to %s", + "connect", + argv[1]), + -1); + + ssize_t len = ACE_OS::strlen (argv[2]) + 1; + + if (cli_file.send (argv[2], len) != len) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "send"), + 1); + + if (cli_file.get_info (&fileinfo) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "get_info"), + 1); + else + ACE_OS::printf ("fileinfo : mode = %o\nno of links = %lu\nsize = %lu\n", + (u_int) fileinfo.mode_ & 0777, + static_cast<u_long > (fileinfo.nlink_), + (u_long) fileinfo.size_); + + off_t fpos = cli_file.tell (); + + if (fpos == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "tell"), + 1); + else + ACE_OS::printf ("current filepointer is at %ld\n", + (long int) fpos); + + if (cli_file.seek (0, + SEEK_SET) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "seek"), + 1); + if (cli_file.recv (readback, len) != len) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "recv"), + 1); + + ACE_OS::printf ("read back :%s\n", + readback); + + if (cli_file.close () == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "close"), + 1); + return 0; +} diff --git a/ACE/examples/IPC_SAP/FILE_SAP/file_sap_client.mpc b/ACE/examples/IPC_SAP/FILE_SAP/file_sap_client.mpc new file mode 100644 index 00000000000..24f9a2b3a61 --- /dev/null +++ b/ACE/examples/IPC_SAP/FILE_SAP/file_sap_client.mpc @@ -0,0 +1,11 @@ +// -*- MPC -*- +// $Id$ + +project : aceexe { + avoids += ace_for_tao + exename = client + Source_Files { + client.cpp + } +} + diff --git a/ACE/examples/IPC_SAP/FILE_SAP/testfile b/ACE/examples/IPC_SAP/FILE_SAP/testfile new file mode 100644 index 00000000000..e7cbb71a0d5 --- /dev/null +++ b/ACE/examples/IPC_SAP/FILE_SAP/testfile @@ -0,0 +1 @@ +testfile
\ No newline at end of file diff --git a/ACE/examples/IPC_SAP/Makefile.am b/ACE/examples/IPC_SAP/Makefile.am new file mode 100644 index 00000000000..87f2a00844b --- /dev/null +++ b/ACE/examples/IPC_SAP/Makefile.am @@ -0,0 +1,21 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +SUBDIRS = \ + ATM_SAP \ + DEV_SAP \ + FIFO_SAP \ + FILE_SAP \ + SOCK_SAP \ + SPIPE_SAP \ + SSL_SAP \ + TLI_SAP \ + UPIPE_SAP + diff --git a/ACE/examples/IPC_SAP/SOCK_SAP/.cvsignore b/ACE/examples/IPC_SAP/SOCK_SAP/.cvsignore new file mode 100644 index 00000000000..07a07ab2d27 --- /dev/null +++ b/ACE/examples/IPC_SAP/SOCK_SAP/.cvsignore @@ -0,0 +1,18 @@ +C-inclient +C-inclient +C-inserver +C-inserver +CPP-inclient +CPP-inclient +CPP-inserver +CPP-inserver +CPP-memclient +CPP-memclient +CPP-memserver +CPP-memserver +CPP-unclient +CPP-unclient +CPP-unserver +CPP-unserver +FD-unclient +FD-unclient diff --git a/ACE/examples/IPC_SAP/SOCK_SAP/C-inclient.cpp b/ACE/examples/IPC_SAP/SOCK_SAP/C-inclient.cpp new file mode 100644 index 00000000000..e4cf8997857 --- /dev/null +++ b/ACE/examples/IPC_SAP/SOCK_SAP/C-inclient.cpp @@ -0,0 +1,84 @@ +// $Id$ + +#include "ace/OS_main.h" +#include "ace/OS_NS_string.h" +#include "ace/OS_NS_sys_socket.h" +#include "ace/OS_NS_unistd.h" +#include "ace/OS_NS_stdlib.h" +#include "ace/OS_NS_stdio.h" +#include "ace/OS_NS_netdb.h" +#include "ace/Default_Constants.h" + +ACE_RCSID(SOCK_SAP, C_inclient, "$Id$") + +/* BSD socket client */ + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + // Initialize WinSock DLL on Win32... + ACE_OS::socket_init (ACE_WSOCK_VERSION); + + struct sockaddr_in saddr; + struct hostent *hp; + const ACE_TCHAR *host = argc > 1 ? argv[1] : ACE_DEFAULT_SERVER_HOST; + u_short port_num = + htons (argc > 2 ? ACE_OS::atoi (argv[2]) : ACE_DEFAULT_SERVER_PORT); + int sockbufsize = argc > 3 ? ACE_OS::atoi (argv[3]) : 0; + char buf[BUFSIZ]; + ACE_HANDLE s_handle; + int w_bytes; + int r_bytes; + int n; + + // Create a local endpoint of communication. + if ((s_handle = ACE_OS::socket (PF_INET, SOCK_STREAM, 0)) == ACE_INVALID_HANDLE) + ACE_OS::perror (ACE_TEXT("socket")), ACE_OS::exit (1); + + // If a sockbufsize was specified, set it for both send and receive. + if (sockbufsize > 0) + { + if (ACE_OS::setsockopt (s_handle, SOL_SOCKET, SO_SNDBUF, + (const char *) &sockbufsize, + sizeof (sockbufsize)) != 0) + ACE_OS::perror (ACE_TEXT("SO_SNDBUF")), ACE_OS::exit (1); + if (ACE_OS::setsockopt (s_handle, SOL_SOCKET, SO_RCVBUF, + (const char *) &sockbufsize, + sizeof (sockbufsize)) != 0) + ACE_OS::perror (ACE_TEXT("SO_RCVBUF")), ACE_OS::exit (1); + } + + // Determine IP address of the server. + if ((hp = ACE_OS::gethostbyname (ACE_TEXT_ALWAYS_CHAR(host))) == 0) + ACE_OS::perror (ACE_TEXT("gethostbyname")), ACE_OS::exit (1); + + // Set up the address information to contact the server. + ACE_OS::memset ((void *) &saddr, 0, sizeof saddr); + saddr.sin_family = AF_INET; + saddr.sin_port = port_num; + ACE_OS::memcpy (&saddr.sin_addr, hp->h_addr, hp->h_length); + + // Establish connection with remote server. + if (ACE_OS::connect (s_handle, + reinterpret_cast<sockaddr *> (&saddr), + sizeof saddr) == -1) + ACE_OS::perror (ACE_TEXT("connect")), ACE_OS::exit (1); + + // Send data to server (correctly handles "incomplete writes" due to + // flow control). + + while ((r_bytes = ACE_OS::read (ACE_STDIN, buf, sizeof buf)) > 0) + for (w_bytes = 0; w_bytes < r_bytes; w_bytes += n) + if ((n = ACE_OS::send (s_handle, buf + w_bytes, + r_bytes - w_bytes)) < 0) + ACE_OS::perror (ACE_TEXT("write")), ACE_OS::exit (1); + + if (ACE_OS::recv (s_handle, buf, 1) == 1) + ACE_OS::write (ACE_STDOUT, buf, 1); + + // Explicitly close the connection. + if (ACE_OS::closesocket (s_handle) == -1) + ACE_OS::perror (ACE_TEXT("close")), ACE_OS::exit (1); + + return 0; +} diff --git a/ACE/examples/IPC_SAP/SOCK_SAP/C-inserver.cpp b/ACE/examples/IPC_SAP/SOCK_SAP/C-inserver.cpp new file mode 100644 index 00000000000..0a6915cc463 --- /dev/null +++ b/ACE/examples/IPC_SAP/SOCK_SAP/C-inserver.cpp @@ -0,0 +1,116 @@ +// $Id$ + +#include "ace/OS_main.h" +#include "ace/OS_NS_string.h" +#include "ace/OS_NS_sys_socket.h" +#include "ace/OS_NS_unistd.h" +#include "ace/OS_NS_stdlib.h" +#include "ace/OS_NS_stdio.h" +#include "ace/OS_NS_netdb.h" +#include "ace/OS_NS_errno.h" +#include "ace/Default_Constants.h" + +ACE_RCSID(SOCK_SAP, C_inserver, "$Id$") + +/* BSD socket server. */ + +int ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + // Initialize WinSock DLL on Win32... + ACE_OS::socket_init (ACE_WSOCK_VERSION); + + u_short port_num = + htons (argc > 1 ? ACE_OS::atoi (argv[1]) : ACE_DEFAULT_SERVER_PORT); + int sockbufsize = argc > 2 ? ACE_OS::atoi (argv[2]) : 0; + struct sockaddr_in saddr; + ACE_HANDLE s_handle, n_handle; + + /* Create a local endpoint of communication */ + if ((s_handle = ACE_OS::socket (PF_INET, SOCK_STREAM, 0)) == ACE_INVALID_HANDLE) + ACE_OS::perror (ACE_TEXT("socket")), ACE_OS::exit (1); + + // If a sockbufsize was specified, set it for both send and receive. + if (sockbufsize > 0) + { + if (ACE_OS::setsockopt (s_handle, SOL_SOCKET, SO_SNDBUF, + (const char *) &sockbufsize, + sizeof (sockbufsize)) != 0) + ACE_OS::perror (ACE_TEXT("SO_SNDBUF")), ACE_OS::exit (1); + if (ACE_OS::setsockopt (s_handle, SOL_SOCKET, SO_RCVBUF, + (const char *) &sockbufsize, + sizeof (sockbufsize)) != 0) + ACE_OS::perror (ACE_TEXT("SO_RCVBUF")), ACE_OS::exit (1); + } + + /* Set up the address information to become a server */ + ACE_OS::memset ((void *) &saddr, 0, sizeof saddr); + saddr.sin_family = AF_INET; + saddr.sin_port = port_num; + saddr.sin_addr.s_addr = INADDR_ANY; + + /* Associate address with endpoint */ + if (ACE_OS::bind (s_handle, + reinterpret_cast<struct sockaddr *> (&saddr), + sizeof saddr) == -1) + ACE_OS::perror (ACE_TEXT("bind")), ACE_OS::exit (1); + + /* Make endpoint listen for service requests */ + if (ACE_OS::listen (s_handle, 5) == -1) + ACE_OS::perror (ACE_TEXT("listen")), ACE_OS::exit (1); + + /* Performs the iterative server activities */ + + for (;;) + { + char buf[BUFSIZ]; + int r_bytes; + struct sockaddr_in cli_addr; + int cli_addr_len = sizeof cli_addr; + struct hostent *hp; + + /* Create a new endpoint of communication */ + do + n_handle = + ACE_OS::accept (s_handle, + reinterpret_cast<struct sockaddr *> (&cli_addr), + &cli_addr_len); + while (n_handle == ACE_INVALID_HANDLE && errno == EINTR); + + if (n_handle == ACE_INVALID_HANDLE) + { + ACE_OS::perror (ACE_TEXT("accept")); + continue; + } + +#if !defined(_UNICOS) + int addr_len = sizeof cli_addr.sin_addr.s_addr; +#else /* ! _UNICOS */ + // sizeof on bitfield fails + int addr_len = sizeof cli_addr.sin_addr; // 32 bit biffield in UNICOS +#endif /* ! _UNICOS */ + hp = ACE_OS::gethostbyaddr ((char *) &cli_addr.sin_addr, + addr_len, AF_INET); + + if (hp != 0) + ACE_OS::printf ("client %s\n", hp->h_name), ACE_OS::fflush (stdout); + else + ACE_OS::perror (ACE_TEXT("gethostbyaddr")); + + /* Read data from client (terminate on error) */ + + while ((r_bytes = ACE_OS::recv (n_handle, buf, sizeof buf)) > 0) + if (ACE_OS::write (ACE_STDOUT, buf, r_bytes) != r_bytes) + ACE_OS::perror (ACE_TEXT("write")), ACE_OS::exit (1); + + if (ACE_OS::send (n_handle, "", 1) != 1) + ::perror ("write"), ACE_OS::exit (1); + + /* Close the new endpoint + (listening endpoint remains open) */ + if (ACE_OS::closesocket (n_handle) == -1) + ACE_OS::perror (ACE_TEXT("close")), ACE_OS::exit (1); + ACE_OS::exit (0); + } + + ACE_NOTREACHED (return 0;) +} diff --git a/ACE/examples/IPC_SAP/SOCK_SAP/CPP-inclient.cpp b/ACE/examples/IPC_SAP/SOCK_SAP/CPP-inclient.cpp new file mode 100644 index 00000000000..3428b02cd12 --- /dev/null +++ b/ACE/examples/IPC_SAP/SOCK_SAP/CPP-inclient.cpp @@ -0,0 +1,424 @@ +// $Id$ + +// This tests the features of the <ACE_SOCK_Connector> and +// <ACE_SOCK_Stream> classes. In addition, it can be used to test the +// oneway and twoway latency and throughput at the socket-level. This +// is useful as a baseline to compare against ORB-level performance +// for the same types of data. + +#include "CPP-inclient.h" + +#include "ace/SOCK_Connector.h" +#include "ace/INET_Addr.h" +#include "ace/Thread_Manager.h" +#include "ace/Singleton.h" +#include "ace/Get_Opt.h" +#include "ace/High_Res_Timer.h" +#include "ace/OS_NS_string.h" +#include "ace/OS_NS_unistd.h" +#include "ace/OS_main.h" + +ACE_RCSID(SOCK_SAP, CPP_inclient, "$Id$") + +Options::Options (void) + : host_ (ACE_DEFAULT_SERVER_HOST), + port_ (ACE_DEFAULT_SERVER_PORT), + sleep_time_ (0, 0), // By default, don't sleep between calls. + threads_ (10), + quit_string_ (ACE_TEXT("q")), + message_len_ (0), + message_buf_ (0), + io_source_ (ACE_INVALID_HANDLE), // Defaults to using the generator. + iterations_ (10000), + oneway_ (1) // Make oneway calls the default. +#if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0) + , barrier_ (0) +#endif /* ACE_MT_SAFE */ +{ +} + +Options::~Options (void) +{ + ACE_MT (delete this->barrier_); + delete [] this->message_buf_; +} + +// Options Singleton. +typedef ACE_Singleton<Options, ACE_SYNCH_RECURSIVE_MUTEX> OPTIONS; + +int +Options::init (void) +{ + + ACE_DEBUG((LM_DEBUG,"Options::init, len = %d\n",this->message_len_)); + + // Check for default case. + if (this->message_len_ == 0) + this->message_len_ = ACE_OS::strlen ("TAO"); + ACE_DEBUG((LM_DEBUG,"Options::init, len = %d\n",this->message_len_)); + + this->message_len_ += sizeof (ACE_UINT32); + ACE_DEBUG((LM_DEBUG,"Options::init, len = %d\n",this->message_len_)); + + ACE_NEW_RETURN (this->message_buf_, + char[this->message_len_], + -1); + + // Copy the length into the beginning of the message. + ACE_UINT32 length = ntohl (this->message_len_); + ACE_OS::memcpy ((void *) this->message_buf_, + (void *) &length, + sizeof length); + + ACE_OS::memset ((void *) (this->message_buf_ + sizeof (ACE_UINT32)), + 'a', + this->message_len_ - sizeof (ACE_UINT32)); + + // Allocate the barrier with the correct count. + ACE_MT (ACE_NEW_RETURN (this->barrier_, + ACE_Barrier (this->threads_), + -1)); + return 0; +} + +size_t +Options::message_len (void) const +{ + return this->message_len_; +} + +const void * +Options::message_buf (void) const +{ + return this->message_buf_; +} + +ssize_t +Options::read (void *buf, size_t len, size_t &iteration) +{ + ACE_UNUSED_ARG (len); + + if (this->io_source_ == ACE_STDIN) + return ACE_OS::read (ACE_STDIN, buf, len); + else if (iteration >= this->iterations_) + return 0; + else + { + ACE_OS::memcpy (buf, + this->message_buf (), + len); + iteration++; + return len; + } +} + +int +Options::parse_args (int argc, ACE_TCHAR *argv[]) +{ + ACE_Get_Opt getopt (argc, argv, ACE_TEXT("2h:i:m:p:q:st:T:"), 1); + + for (int c; (c = getopt ()) != -1; ) + switch (c) + { + case '2': // Disable the oneway client. + this->oneway_ = 0; + break; + case 'h': + this->host_ = getopt.opt_arg (); + break; + case 'i': + this->iterations_ = ACE_OS::atoi (getopt.opt_arg ()); + break; + case 'm': + this->message_len_ = ACE_OS::atoi (getopt.opt_arg ()); + break; + case 'p': + this->port_ = ACE_OS::atoi (getopt.opt_arg ()); + break; + case 'q': + this->quit_string_ = getopt.opt_arg (); + break; + case 's': + this->io_source_ = ACE_STDIN; + break; + case 't': + this->threads_ = (size_t) ACE_OS::atoi (getopt.opt_arg ()); + break; + case 'T': + this->sleep_time_.set (0, ACE_OS::atoi (getopt.opt_arg ())); + break; + default: + ACE_ERROR_RETURN ((LM_ERROR, + "(%P|%t) usage: %n [-2] [-h <host>] [-i iterations] [-m message-size] [-p <port>] [-q <quit string>] [-s] [-t <threads>] [-T <sleep_time>]\n"), + -1); + } + + return this->init (); +} + +u_short +Options::port (void) const +{ + return this->port_; +} + +const ACE_TCHAR * +Options::host (void) const +{ + return this->host_; +} + +const ACE_TCHAR * +Options::quit_string (void) const +{ + return this->quit_string_; +} + +size_t +Options::threads (void) const +{ + return this->threads_; +} + +const ACE_Time_Value & +Options::sleep_time (void) const +{ + return this->sleep_time_; +} + +char * +Options::shared_client_test (u_short port, + ACE_SOCK_Stream &cli_stream) +{ + ACE_INET_Addr remote_addr (port, this->host_); + + ACE_SOCK_Connector con; + + if (con.connect (cli_stream, + remote_addr) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "(%P|%t) %p\n", + "connection failed"), + 0); + else + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) connected to %s at port %d\n", + remote_addr.get_host_name (), + remote_addr.get_port_number ())); + + ACE_INT32 len = htonl (this->message_len ()); + + // Allocate the transmit buffer. + char *buf; + ACE_DEBUG((LM_DEBUG,"(%P|%t) allocating buffer, len = %d msglen = %d\n", + len, message_len_)); + + ACE_NEW_RETURN (buf, + char[this->message_len()], + 0); + + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) waiting...\n")); + + // Wait for all other threads to finish initialization. + ACE_MT (this->barrier_->wait ()); + return buf; +} +// Static function entry point to the oneway client service. + +void * +Options::oneway_client_test (void *) +{ + Options *options = OPTIONS::instance (); + ACE_SOCK_Stream cli_stream; + + ACE_DEBUG((LM_DEBUG,"options = %d, len = %d\n",options,options->message_len())); + + // Add 1 to the port to trigger the oneway test! + char *request = options->shared_client_test (options->port () + 1, + cli_stream); + if (request == 0) + return 0; + + // This variable is allocated off the stack to obviate the need for + // locking. + size_t iteration = 0; + + // Keep track of return value. + int result = 0; + ACE_INT32 len = options->message_len (); + + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) starting oneway transmission\n")); + + // Perform oneway transmission of data to server (correctly handles + // "incomplete writes"). + + for (ssize_t r_bytes; + (r_bytes = options->read (request, len, iteration)) > 0; + // Transmit at the proper rate. + ACE_OS::sleep (options->sleep_time ())) + if (ACE_OS::memcmp (request, + options->quit_string (), + ACE_OS::strlen (options->quit_string ())) == 0) + break; + else if (cli_stream.send_n (request, r_bytes) == -1) + { + ACE_ERROR ((LM_ERROR, + "(%P|%t) %p\n", + "send_n")); + result = -1; + break; + } + + // Close the connection. + cli_stream.close (); + + delete [] request; + return reinterpret_cast<void *> (result); +} + +// Static function entry point to the twoway client service. + +void * +Options::twoway_client_test (void *) +{ + Options *options = OPTIONS::instance (); + + ACE_SOCK_Stream cli_stream; + + char *request = options->shared_client_test (options->port (), + cli_stream); + if (request == 0) + return 0; + + // This variable is allocated off the stack to obviate the need for + // locking. + size_t iteration = 0; + + // Keep track of return value. + int result = 0; + + // Timer business. + ACE_High_Res_Timer timer; + + ACE_INT32 len = options->message_len (); + + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) starting twoway transmission\n")); + + // Perform twoway transmission of data to server (correctly handles + // "incomplete writes"). + + for (ssize_t r_bytes; + (r_bytes = options->read (request, len, iteration)) > 0; + // Transmit at the proper rate. + ACE_OS::sleep (options->sleep_time ())) + if (ACE_OS::memcmp (request, + options->quit_string (), + ACE_OS::strlen (options->quit_string ())) == 0) + break; + + // Transmit <request> to the server. + else + { + // Note that we use the incremental feature of the + // <ACE_High_Res_Timer> so that we don't get "charged" for the + // <ACE_OS::sleep> used to control the rate at which requests + // are sent. + timer.start_incr (); + + if (cli_stream.send_n (request, r_bytes) == -1) + { + ACE_ERROR ((LM_ERROR, + "(%P|%t) %p\n", + "send_n")); + result = -1; + break; + } + // Receive the reply from the server. Normally, it just sends + // back 24 bytes, which is typical for an IIOP reply. + else if (cli_stream.recv (request, r_bytes) <= 0) + { + ACE_ERROR ((LM_ERROR, + "(%P|%t) %p\n", + "recv")); + result = -1; + break; + } + + timer.stop_incr (); + } + + ACE_Time_Value tv; + + timer.elapsed_time_incr (tv); + double real_time = tv.sec () * ACE_ONE_SECOND_IN_USECS + tv.usec (); + double messages_per_sec = iteration * double (ACE_ONE_SECOND_IN_USECS) / real_time; + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%t) messages = %d\n(%t) usec-per-message = %f\n(%t) messages-per-second = %0.00f\n"), + iteration, + real_time / double (iteration), + messages_per_sec < 0 ? 0 : messages_per_sec)); + + // Close the connection. + cli_stream.close (); + + delete [] request; + return reinterpret_cast<void *> (result); +} + +ACE_THR_FUNC +Options::thr_func (void) +{ + ACE_DEBUG((LM_DEBUG,"(%P|%t) in thread func, mesg len = %d\n",this->message_len())); + if (this->oneway_ == 0) + return ACE_THR_FUNC (&Options::twoway_client_test); + else + return ACE_THR_FUNC (&Options::oneway_client_test); +} + +static int +run_client (void) +{ + // Raise the socket handle limit to the maximum. + ACE::set_handle_limit (); + +#if defined (ACE_HAS_THREADS) + ACE_DEBUG((LM_DEBUG,"(%P|%t) spawning client test thread options = %d\n", + OPTIONS::instance())); + + if (ACE_Thread_Manager::instance ()->spawn_n (OPTIONS::instance ()->threads (), + OPTIONS::instance ()->thr_func ()) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "(%P|%t) %p\n", + "spawn_n"), + 1); + else + ACE_Thread_Manager::instance ()->wait (); +#else + *(OPTIONS::instance ()->thr_func) (); +#endif /* ACE_HAS_THREADS */ + return 0; +} + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + // Initialize the logger. + ACE_LOG_MSG->open (argv[0]); + + if (OPTIONS::instance ()->parse_args (argc, argv) == -1) + return -1; + + // Run the client + run_client (); + + return 0; +} + +#if defined (ACE_HAS_EXPLICIT_STATIC_TEMPLATE_MEMBER_INSTANTIATION) +template ACE_Singleton<Options, ACE_SYNCH_RECURSIVE_MUTEX> * + ACE_Singleton<Options, ACE_SYNCH_RECURSIVE_MUTEX>::singleton_; +#endif /* ACE_HAS_EXPLICIT_STATIC_TEMPLATE_MEMBER_INSTANTIATION */ diff --git a/ACE/examples/IPC_SAP/SOCK_SAP/CPP-inclient.h b/ACE/examples/IPC_SAP/SOCK_SAP/CPP-inclient.h new file mode 100644 index 00000000000..7486c70b749 --- /dev/null +++ b/ACE/examples/IPC_SAP/SOCK_SAP/CPP-inclient.h @@ -0,0 +1,108 @@ +// $Id$ + +// This file defines the Options class for CPP-inclient. IBM C++ compiler'd +// template auto-instantiator needs this in a separate file. + +#ifndef __CPP_INCLIENT_H +#define __CPP_INCLIENT_H + +#include "ace/SOCK_Stream.h" +#include "ace/Barrier.h" +#include "ace/Time_Value.h" + +class Options + // = TITLE + // Define the options for this test. +{ +public: + Options (void); + // Constructor. + + ~Options (void); + // Destructor. + + int parse_args (int argc, ACE_TCHAR *argv[]); + // Parse the command-line arguments. + + const ACE_Time_Value &sleep_time (void) const; + // Return the amount of time to sleep in order to implement the + // proper transmission rates. + + u_short port (void) const; + // Port of the server. + + const ACE_TCHAR *host (void) const; + // Host of the server. + + size_t threads (void) const; + // Number of threads. + + const ACE_TCHAR *quit_string (void) const; + // String that shuts down the client/server. + + ssize_t read (void *buf, size_t len, size_t &iterations); + // Read from the appropriate location. + + size_t message_len (void) const; + // Returns the length of the message to send. + + const void *message_buf (void) const; + // Returns a pointer to the message. + + ACE_THR_FUNC thr_func (void); + // Returns a pointer to the entry point into the thread that runs + // the client test function. + +private: + int init (void); + // Initialize the message we're sending to the user and set up the + // barrier. + + char *shared_client_test (u_short port, + ACE_SOCK_Stream &cli_stream); + // Performs the shared behavior of the oneway and twoway client + // tests. + + static void *twoway_client_test (void *); + // Performs the twoway test. + + static void *oneway_client_test (void *); + // Performs the oneway test. + + const ACE_TCHAR *host_; + // Host of the server. + + u_short port_; + // Port of the server. + + ACE_Time_Value sleep_time_; + // Sleep_Time value. + + size_t threads_; + // Number of threads. + + const ACE_TCHAR *quit_string_; + // String that shuts down the client/server. + + size_t message_len_; + // Size of the message we send to the server. + + char *message_buf_; + // Pointer to the message we send to the server. + + ACE_HANDLE io_source_; + // Are we reading I/O from ACE_STDIN or from our generator? + + size_t iterations_; + // Number of iterations. + + char oneway_; + // Are we running oneway or twoway? + + // Please leave the ; inside the parenthesis to avoid Green Hills + // (and probably other) compiler warning about extra ;. + ACE_MT (ACE_Barrier *barrier_;) + // Barrier used to synchronize the start of all the threads. +}; + +#endif /* __CPP_INCLIENT_H */ diff --git a/ACE/examples/IPC_SAP/SOCK_SAP/CPP-inserver-fancy.cpp b/ACE/examples/IPC_SAP/SOCK_SAP/CPP-inserver-fancy.cpp new file mode 100644 index 00000000000..43df0572f74 --- /dev/null +++ b/ACE/examples/IPC_SAP/SOCK_SAP/CPP-inserver-fancy.cpp @@ -0,0 +1,582 @@ + // $Id$ + +// This example tests the features of the <ACE_SOCK_Acceptor>, +// <ACE_SOCK_Stream>, and <ACE_Svc_Handler> classes. If the platform +// supports threads it uses a thread-per-connection concurrency model. +// Otherwise, it uses a single-threaded iterative server model. + +#include "ace/OS_main.h" +#include "ace/SOCK_Acceptor.h" +#include "ace/Svc_Handler.h" +#include "ace/Singleton.h" +#include "ace/Profile_Timer.h" +#include "ace/Get_Opt.h" +#include "ace/OS_NS_sys_select.h" + +#include "CPP-inserver-fancy.h" + +ACE_RCSID(SOCK_SAP, CPP_inserver_fancy, "$Id$") + +// Forward declaration. +class Handler; + +class Handler_Factory +{ + // = TITLE + // Creates the oneway or twoway handlers. +public: + Handler_Factory (void); + // Constructor. + + ~Handler_Factory (void); + // Destructor. + + int handle_events (void); + // Run the main event loop. + +private: + int init_acceptors (void); + // Initialize the acceptors. + + int create_handler (ACE_SOCK_Acceptor &acceptor, + Handler *(*handler_factory) (ACE_HANDLE), + const char *handler_type); + // Factory that creates the right kind of <Handler>. + + // = Factory functions. + static Handler *make_twoway_handler (ACE_HANDLE); + // Create a twoway handler. + + static Handler *make_oneway_handler (ACE_HANDLE); + // Create a oneway handler. + + ACE_SOCK_Acceptor twoway_acceptor_; + // Twoway acceptor factory. + + ACE_SOCK_Acceptor oneway_acceptor_; + // Oneway acceptor factory. +}; + +class Handler : public ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH> +{ + // = TITLE + // Base class for the oneway and twoway handlers. + + friend class Handler_Factory; + // The factory has special permission. (to access svc ()). + +public: + virtual int open (void * = 0); + // Generic initialization method. + + virtual int close (u_long); + // Close down and delete this. + +protected: + Handler (ACE_HANDLE handle); + // Constructor. + + int parse_header_and_allocate_buffer (char *&buf, + ACE_INT32 *len); + // Implement the generic code that's called from any of the subclass + // <run> methods to get the header and the buffer to read the data. + // This method factors out common code. + + virtual int run (void) = 0; + // Hook method called by the <svc> template method to do the actual + // protocol. Must be overridden by the subclass. + + virtual int svc (void); + // Template method entry point into the handler task. + + virtual void print_results (void); + // Print the results. + + size_t total_bytes_; + // Total number of bytes received. + + size_t message_count_; + // Number of messages received. + + ACE_Profile_Timer timer_; + // Keeps track of how much time we're using. +}; + +class Twoway_Handler : public Handler +{ + // = TITLE + // Performs the twoway protocol. +public: + Twoway_Handler (ACE_HANDLE handle); + // Constructor. + +private: + virtual int run (void); + // Template Method hook called by <svc>. +}; + +class Oneway_Handler : public Handler +{ + // = TITLE +public: + Oneway_Handler (ACE_HANDLE handle); + // Constructor. + +private: + virtual int run (void); + // Template Method hook called by <svc>. + + virtual void print_results (void); + // Print the results. +}; + +u_short +Options::port (void) const +{ + return this->port_; +} + +int +Options::verbose (void) const +{ + return this->verbose_; +} + +int +Options::reply_message_len (void) const +{ + return this->reply_message_len_; +} + +Options::~Options (void) +{ +} + +Options::Options (void) + : verbose_ (0), + port_ (ACE_DEFAULT_SERVER_PORT), + reply_message_len_ (24) // Default to the approximate size of an + // GIOP reply message. +{ +} + +int +Options::parse_args (int argc, ACE_TCHAR *argv[]) +{ + ACE_Get_Opt getopt (argc, argv, ACE_TEXT("p:r:v"), 1); + + for (int c; (c = getopt ()) != -1; ) + switch (c) + { + case 'p': + this->port_ = ACE_OS::atoi (getopt.opt_arg ()); + break; + case 'r': + this->reply_message_len_ = ACE_OS::atoi (getopt.opt_arg ()); + break; + case 'v': + this->verbose_ = 1; + break; + default: + ACE_ERROR_RETURN ((LM_ERROR, + "(%P|%t) usage: %n [-p <port>] [-v]"), + -1); + } + + return 0; +} + +// Options Singleton. +typedef ACE_Singleton<Options, ACE_SYNCH_RECURSIVE_MUTEX> OPTIONS; + +Handler::Handler (ACE_HANDLE handle) + : total_bytes_ (0), + message_count_ (0) +{ + this->peer ().set_handle (handle); +} + +int +Handler::open (void *) +{ + ACE_INET_Addr cli_addr; + + // Make sure we're not in non-blocking mode. + if (this->peer ().disable (ACE_NONBLOCK) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "disable"), + 0); + + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) client %s connected from %d on handle %d\n", + cli_addr.get_host_name (), + cli_addr.get_port_number (), + this->peer ().get_handle ())); + return 0; +} + +int +Handler::close (u_long) +{ + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) closing down %x\n", + this)); + delete this; + return 0; +} + +int +Handler::svc (void) +{ + // Timer logic. + this->timer_.start (); + + // Invoke the hook method to run the specific test. + int result = this->run (); + + this->timer_.stop (); + + this->print_results (); + + return result; +} + +int +Handler::parse_header_and_allocate_buffer (char *&request, + ACE_INT32 *len) +{ + ssize_t result = this->peer ().recv_n ((void *) len, + sizeof (ACE_INT32)); + if (result == 0) + { + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) connected closed\n")); + return -1; + } + else if (result == -1 || result != sizeof (ACE_INT32)) + ACE_ERROR_RETURN ((LM_ERROR, + "(%P|%t) %p\n", + "recv_n failed"), + -1); + else + { + *len = ntohl (*len); + ACE_NEW_RETURN (request, + char[*len], + -1); + } + + return 0; +} + +void +Handler::print_results (void) +{ +} + +Twoway_Handler::Twoway_Handler (ACE_HANDLE handle) + : Handler (handle) +{ +} + +// Function entry point into the twoway server task. + +int +Twoway_Handler::run (void) +{ + // Read data from client (terminate on error). + + char *request = 0; + + for (;;) + { + ACE_INT32 len = 0; + + if (parse_header_and_allocate_buffer (request, + &len) == -1) + return -1; + + // Subtract off the sizeof the length prefix. + ssize_t r_bytes = this->peer ().recv_n (request, + len - sizeof (ACE_UINT32)); + + if (r_bytes == -1) + { + ACE_ERROR ((LM_ERROR, + "%p\n", + "recv")); + break; + } + else if (r_bytes == 0) + { + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) reached end of input, connection closed by client\n")); + break; + } + else if (OPTIONS::instance ()->verbose () + && ACE::write_n (ACE_STDOUT, + request, + r_bytes) != r_bytes) + ACE_ERROR ((LM_ERROR, + "%p\n", + "ACE::write_n")); + else + { + ssize_t s_bytes = (ssize_t) OPTIONS::instance ()->reply_message_len (); + + // Don't try to send more than is in the request buffer! + if (s_bytes > r_bytes) + s_bytes = r_bytes; + + if (this->peer ().send_n (request, + s_bytes) != s_bytes) + ACE_ERROR ((LM_ERROR, + "%p\n", + "send_n")); + } + this->total_bytes_ += size_t (r_bytes); + this->message_count_++; + + delete [] request; + request = 0; + } + + delete [] request; + return 0; +} + +Oneway_Handler::Oneway_Handler (ACE_HANDLE handle) + : Handler (handle) +{ +} + +void +Oneway_Handler::print_results (void) +{ + ACE_Profile_Timer::ACE_Elapsed_Time et; + this->timer_.elapsed_time (et); + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("\t\treal time = %f secs \n\t\tuser time = %f secs \n\t\tsystem time = %f secs\n"), + et.real_time, + et.user_time, + et.system_time)); + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("\t\tmessages = %d\n\t\ttotal bytes = %d\n\t\tmbits/sec = %f\n\t\tusec-per-message = %f\n"), + this->message_count_, + this->total_bytes_, + (((double) this->total_bytes_ * 8) / et.real_time) / (double) (1024 * 1024), + ((et.user_time + et.system_time) / (double) this->message_count_) * ACE_ONE_SECOND_IN_USECS)); +} + +// Function entry point into the oneway server task. + +int +Oneway_Handler::run (void) +{ + // Read data from client (terminate on error). + + char *request = 0; + + for (;;) + { + ACE_INT32 len = 0; + + if (parse_header_and_allocate_buffer (request, + &len) == -1) + return -1; + + // Subtract off the sizeof the length prefix. + ssize_t r_bytes = this->peer ().recv_n (request, + len - sizeof (ACE_UINT32)); + + if (r_bytes == -1) + { + ACE_ERROR ((LM_ERROR, + "%p\n", + "recv")); + break; + } + else if (r_bytes == 0) + { + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) reached end of input, connection closed by client\n")); + break; + } + else if (OPTIONS::instance ()->verbose () + && ACE::write_n (ACE_STDOUT, + request, + r_bytes) != r_bytes) + ACE_ERROR ((LM_ERROR, + "%p\n", + "ACE::write_n")); + + this->total_bytes_ += size_t (r_bytes); + this->message_count_++; + delete [] request; + request = 0; + } + + delete [] request; + return 0; +} + +// Create a twoway handler. + +Handler * +Handler_Factory::make_twoway_handler (ACE_HANDLE handle) +{ + return new Twoway_Handler (handle); +} + +// Create a oneway handler. + +Handler * +Handler_Factory::make_oneway_handler (ACE_HANDLE handle) +{ + return new Oneway_Handler (handle); +} + +int +Handler_Factory::init_acceptors (void) +{ + // Create the oneway and twoway server addresses. + ACE_INET_Addr twoway_server_addr (OPTIONS::instance ()->port ()); + ACE_INET_Addr oneway_server_addr (OPTIONS::instance ()->port () + 1); + + // Create acceptors, reuse the address. + if (this->twoway_acceptor_.open (twoway_server_addr, 1) == -1 + || this->oneway_acceptor_.open (oneway_server_addr, 1) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "open"), + -1); + else if (this->twoway_acceptor_.get_local_addr (twoway_server_addr) == -1 + || this->oneway_acceptor_.get_local_addr (oneway_server_addr) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "get_local_addr"), + -1); + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) starting twoway server at port %d and oneway server at port %d\n", + twoway_server_addr.get_port_number (), + oneway_server_addr.get_port_number ())); + return 0; +} + +int +Handler_Factory::create_handler (ACE_SOCK_Acceptor &acceptor, + Handler * (*handler_factory) (ACE_HANDLE), + const char *handler_type) +{ + ACE_SOCK_Stream new_stream; + + if (acceptor.accept (new_stream) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "accept"), + -1); + + Handler *handler; + + ACE_ALLOCATOR_RETURN (handler, + (*handler_factory) (new_stream.get_handle ()), + -1); + + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) spawning %s handler\n", + handler_type)); + + if (handler->open () == -1) + return -1; + +#if defined (ACE_MT_SAFE) + // Spawn a new thread and run the new connection in that thread of + // control using the <server> function as the entry point. + return handler->activate (); +#else + handler->svc (); + handler->close (0); + return 0; +#endif /* ACE_HAS_THREADS */ +} + +Handler_Factory::Handler_Factory (void) +{ +} + +Handler_Factory::~Handler_Factory (void) +{ + this->twoway_acceptor_.close (); + this->oneway_acceptor_.close (); +} + +// Run the main event loop. + +int +Handler_Factory::handle_events (void) +{ + if (this->init_acceptors () == -1) + return -1; + + fd_set handles; + + FD_ZERO (&handles); + FD_SET ((ACE_SOCKET) this->twoway_acceptor_.get_handle (), + &handles); + FD_SET ((ACE_SOCKET) this->oneway_acceptor_.get_handle (), + &handles); + + // Performs the iterative server activities. + + for (;;) + { + ACE_Time_Value timeout (ACE_DEFAULT_TIMEOUT); + fd_set temp = handles; + + int result = ACE_OS::select (int (this->oneway_acceptor_.get_handle ()) + 1, + (fd_set *) &temp, + 0, + 0, + timeout); + if (result == -1) + ACE_ERROR ((LM_ERROR, + "(%P|%t) %p\n", + "select")); + else if (result == 0 && OPTIONS::instance ()->verbose ()) + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) select timed out\n")); + else + { + if (FD_ISSET ((ACE_SOCKET) this->twoway_acceptor_.get_handle (), + &temp)) + this->create_handler (this->twoway_acceptor_, + &Handler_Factory::make_twoway_handler, + "twoway"); + if (FD_ISSET ((ACE_SOCKET) this->oneway_acceptor_.get_handle (), + &temp)) + this->create_handler (this->oneway_acceptor_, + &Handler_Factory::make_oneway_handler, + "oneway"); + } + } + + ACE_NOTREACHED (return 0;) +} + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + OPTIONS::instance ()->parse_args (argc, argv); + + Handler_Factory server; + + return server.handle_events (); +} + +#if defined (ACE_HAS_EXPLICIT_STATIC_TEMPLATE_MEMBER_INSTANTIATION) +template ACE_Singleton<Options, ACE_SYNCH_RECURSIVE_MUTEX> * + ACE_Singleton<Options, ACE_SYNCH_RECURSIVE_MUTEX>::singleton_; +#endif /* ACE_HAS_EXPLICIT_STATIC_TEMPLATE_MEMBER_INSTANTIATION */ diff --git a/ACE/examples/IPC_SAP/SOCK_SAP/CPP-inserver-fancy.h b/ACE/examples/IPC_SAP/SOCK_SAP/CPP-inserver-fancy.h new file mode 100644 index 00000000000..9901bcc0b20 --- /dev/null +++ b/ACE/examples/IPC_SAP/SOCK_SAP/CPP-inserver-fancy.h @@ -0,0 +1,43 @@ +// $Id$ + +// This file defines the Options class for CPP-inserver-fancy. +// IBM C++ compiler'd template auto-instantiator needs this in a separate file. + +#ifndef __CPP_INSERVER_FANCY_H +#define __CPP_INSERVER_FANCY_H + +class Options + // = TITLE + // Define the options for this test. +{ +public: + Options (void); + // Constructor. + + ~Options (void); + // Destructor. + + int parse_args (int argc, ACE_TCHAR *argv[]); + // Parse the command-line arguments. + + int verbose (void) const; + // Are we running in verbose mode? + + u_short port (void) const; + // Port number that we are listening at. + + int reply_message_len (void) const; + // Size of the reply message. + +private: + int verbose_; + // Are we running in verbose mode? + + u_short port_; + // Port number we listen at. + + size_t reply_message_len_; + // Size of the reply message. +}; + +#endif /* __CPP_INSERVER_FANCY_H */ diff --git a/ACE/examples/IPC_SAP/SOCK_SAP/CPP-inserver-poll.cpp b/ACE/examples/IPC_SAP/SOCK_SAP/CPP-inserver-poll.cpp new file mode 100644 index 00000000000..a281d2e380d --- /dev/null +++ b/ACE/examples/IPC_SAP/SOCK_SAP/CPP-inserver-poll.cpp @@ -0,0 +1,207 @@ +// $Id$ + +// IPC_SAP/poll server, which illustrates how to integrate the ACE +// socket wrappers with the SVR4 <poll> system call to create a +// single-threaded concurrent server. This server program can be +// driven by the oneway test mode of CPP-inclient.cpp. + +#include "ace/OS_main.h" +#include "ace/SOCK_Acceptor.h" +#include "ace/SOCK_Stream.h" +#include "ace/INET_Addr.h" +#include "ace/Log_Msg.h" +#include "ace/OS_NS_poll.h" +#include "ace/OS_NS_stdio.h" + +ACE_RCSID(SOCK_SAP, CPP_inserver_poll, "$Id$") + +#if defined (ACE_HAS_POLL) + +// Should we be verbose? +static int verbose = 0; + +// Max number of open handles. +static const int MAX_HANDLES = 200; + +struct Buffer_Info +{ + void *buf_; + // Pointer to the buffer. + + size_t len_; + // Length of the buffer. +}; + +// Array of <pollfd>'s. +static struct pollfd poll_array[MAX_HANDLES]; + +// Array of <Buffer_Info>. +static Buffer_Info buffer_array[MAX_HANDLES]; + +static void +init_poll_array (void) +{ + int i; + + for (i = 0; i < MAX_HANDLES; i++) + { + poll_array[i].fd = ACE_INVALID_HANDLE; + poll_array[i].events = POLLIN; + } +} + +static int +init_buffer (size_t index) +{ + ACE_INT32 len; + + if (ACE::recv_n (poll_array[index].fd, + (void *) &len, + sizeof (ACE_INT32)) != sizeof (ACE_INT32)) + ACE_ERROR_RETURN ((LM_ERROR, + "(%P|%t) %p\n", + "recv_n failed"), + -1); + else + { + len = ntohl (len); + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) reading messages of size %d from handle %d\n", + len, + poll_array[index].fd)); + + ACE_ALLOCATOR_RETURN (buffer_array[index].buf_, + ACE_OS::malloc (len), + -1); + buffer_array[index].len_ = len; + } + return 0; +} + +static void +handle_data (size_t &n_handles) +{ + // Handle pending logging messages first (s_handle + 1 is guaranteed + // to be lowest client descriptor). + + for (size_t index = 1; index < n_handles; index++) + { + if (ACE_BIT_ENABLED (poll_array[index].revents, POLLIN)) + { + // First time in, we need to initialize the buffer. + if (buffer_array[index].buf_ == 0 + && init_buffer (index) == -1) + { + ACE_ERROR ((LM_ERROR, + "(%P|%t) %p\n", + "init_buffer")); + continue; + } + + // Read data from client (terminate on error). + + ssize_t n = ACE::recv (poll_array[index].fd, + buffer_array[index].buf_, + buffer_array[index].len_); + // <recv> will not block in this case! + + if (n == -1) + ACE_ERROR ((LM_ERROR, + "%p\n", + "read failed")); + else if (n == 0) + { + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) closing oneway server at handle %d\n", + poll_array[index].fd)); + + // Handle client connection shutdown. + ACE_OS::close (poll_array[index].fd); + poll_array[index].fd = poll_array[--n_handles].fd; + + ACE_OS::free ((void *) buffer_array[index].buf_); + buffer_array[index].buf_ = 0; + buffer_array[index].len_ = 0; + } + else if (verbose) + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) %*s", + n, + buffer_array[index].buf_)); + } + } +} + +static void +handle_connections (ACE_SOCK_Acceptor &peer_acceptor, + size_t &n_handles) +{ + if (ACE_BIT_ENABLED (poll_array[0].revents, POLLIN)) + { + ACE_SOCK_Stream new_stream; + + ACE_INET_Addr client; + ACE_Time_Value nonblock (0, 0); + + // Handle all pending connection requests (note use of "polling" + // feature that doesn't block). + + while (ACE_OS::poll (poll_array, 1, nonblock) > 0) + if (peer_acceptor.accept (new_stream, &client) == -1) + ACE_OS::perror ("accept"); + else + { + const char *s = client.get_host_name (); + + ACE_ASSERT (s != 0); + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) client %s\n", + s)); + poll_array[n_handles++].fd = new_stream.get_handle (); + } + } +} + +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + u_short port = ACE_DEFAULT_SERVER_PORT + 1; + + // Create a server end-point. + ACE_INET_Addr addr (port); + ACE_SOCK_Acceptor peer_acceptor (addr); + + ACE_HANDLE s_handle = peer_acceptor.get_handle (); + + init_poll_array (); + + poll_array[0].fd = s_handle; + + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) starting oneway server at port %d\n", + port)); + + for (size_t n_handles = 1;;) + { + ACE_ENDLESS_LOOP + + // Wait for client I/O events (handle interrupts). + while (ACE_OS::poll (poll_array, n_handles) == -1 + && errno == EINTR) + continue; + + handle_data (n_handles); + handle_connections (peer_acceptor, n_handles); + } + + /* NOTREACHED */ + return 0; +} +#else +#include <stdio.h> +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_OS::fprintf (stderr, "This feature is not supported\n"); + return 0; +} +#endif /* ACE_HAS_POLL */ diff --git a/ACE/examples/IPC_SAP/SOCK_SAP/CPP-inserver.cpp b/ACE/examples/IPC_SAP/SOCK_SAP/CPP-inserver.cpp new file mode 100644 index 00000000000..b978bb5f989 --- /dev/null +++ b/ACE/examples/IPC_SAP/SOCK_SAP/CPP-inserver.cpp @@ -0,0 +1,391 @@ +// $Id$ + +// This example tests the features of the <ACE_SOCK_Acceptor>, +// <ACE_SOCK_Stream>, and <ACE_Svc_Handler> classes. If the platform +// supports threads it uses a thread-per-connection concurrency model. +// Otherwise, it uses a single-threaded iterative server model. + +#include "ace/SOCK_Acceptor.h" +#include "ace/Thread_Manager.h" +#include "ace/Handle_Set.h" +#include "ace/Profile_Timer.h" +#include "ace/OS_NS_sys_select.h" +#include "ace/OS_main.h" + +ACE_RCSID(SOCK_SAP, CPP_inserver, "$Id$") + +// Are we running verbosely? +static int verbose = 0; + +static void +run_server (ACE_THR_FUNC server, + ACE_HANDLE handle) +{ +#if defined (ACE_HAS_THREADS) + // Spawn a new thread and run the new connection in that thread of + // control using the <server> function as the entry point. + if (ACE_Thread_Manager::instance ()->spawn (server, + reinterpret_cast<void *> (handle), + THR_DETACHED) == -1) + ACE_ERROR ((LM_ERROR, + "(%P|%t) %p\n", + "spawn")); +#else + (*server) (reinterpret_cast<void *> (handle)); +#endif /* ACE_HAS_THREADS */ +} + +// Function entry point into the twoway server task. + +static ACE_THR_FUNC_RETURN +twoway_server (void *arg) +{ + ACE_INET_Addr cli_addr; + ACE_SOCK_Stream new_stream; + ACE_HANDLE handle = (ACE_HANDLE) (long) arg; + + new_stream.set_handle (handle); + + // Make sure we're not in non-blocking mode. + if (new_stream.disable (ACE_NONBLOCK) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "disable"), + 0); + else if (new_stream.get_remote_addr (cli_addr) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "get_remote_addr"), + 0); + + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) client %s connected from %d\n", + cli_addr.get_host_name (), + cli_addr.get_port_number ())); + + size_t total_bytes = 0; + size_t message_count = 0; + + char *request = 0; + + // Read data from client (terminate on error). + + for (;;) + { + ACE_INT32 len; + + ssize_t r_bytes = new_stream.recv_n ((void *) &len, + sizeof (ACE_INT32)); + if (r_bytes == -1) + { + ACE_ERROR ((LM_ERROR, + "%p\n", + "recv")); + break; + } + else if (r_bytes == 0) + { + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) reached end of input, connection closed by client\n")); + break; + } + else if (r_bytes != sizeof (ACE_INT32)) + { + ACE_ERROR ((LM_ERROR, + "(%P|%t) %p\n", + "recv_n failed")); + break; + } + else + { + len = ntohl (len); + ACE_NEW_RETURN (request, + char [len], + 0); + } + + // Subtract off the sizeof the length prefix. + r_bytes = new_stream.recv_n (request, + len - sizeof (ACE_UINT32)); + if (r_bytes == -1) + { + ACE_ERROR ((LM_ERROR, + "%p\n", + "recv")); + break; + } + else if (r_bytes == 0) + { + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) reached end of input, connection closed by client\n")); + break; + } + else if (verbose + && ACE::write_n (ACE_STDOUT, + request, + r_bytes) != r_bytes) + ACE_ERROR ((LM_ERROR, + "%p\n", + "ACE::write_n")); + else if (new_stream.send_n (request, + r_bytes) != r_bytes) + ACE_ERROR ((LM_ERROR, + "%p\n", + "send_n")); + + total_bytes += size_t (r_bytes); + message_count++; + + delete [] request; + request = 0; + } + + // Close new endpoint (listening endpoint stays open). + new_stream.close (); + + delete [] request; + return 0; +} + +// Function entry point into the oneway server task. + +static ACE_THR_FUNC_RETURN +oneway_server (void *arg) +{ + ACE_INET_Addr cli_addr; + ACE_SOCK_Stream new_stream; + ACE_HANDLE handle = (ACE_HANDLE) (long) arg; + + new_stream.set_handle (handle); + + // Make sure we're not in non-blocking mode. + if (new_stream.disable (ACE_NONBLOCK) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "disable"), + 0); + else if (new_stream.get_remote_addr (cli_addr) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "get_remote_addr"), + 0); + + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) client %s connected from %d\n", + cli_addr.get_host_name (), + cli_addr.get_port_number ())); + + // Timer business + ACE_Profile_Timer timer; + timer.start (); + + size_t total_bytes = 0; + size_t message_count = 0; + + char *request = 0; + + // Read data from client (terminate on error). + + for (;;) + { + ACE_INT32 len; + + ssize_t r_bytes = new_stream.recv_n ((void *) &len, + sizeof (ACE_INT32)); + if (r_bytes == -1) + { + ACE_ERROR ((LM_ERROR, + "%p\n", + "recv")); + break; + } + else if (r_bytes == 0) + { + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) reached end of input, connection closed by client\n")); + break; + } + else if (r_bytes != sizeof (ACE_INT32)) + { + ACE_ERROR ((LM_ERROR, + "(%P|%t) %p\n", + "recv_n failed")); + break; + } + else + { + len = ntohl (len); + ACE_NEW_RETURN (request, + char [len], + 0); + } + + // Subtract off the sizeof the length prefix. + r_bytes = new_stream.recv_n (request, + len - sizeof (ACE_UINT32)); + + if (r_bytes == -1) + { + ACE_ERROR ((LM_ERROR, + "%p\n", + "recv")); + break; + } + else if (r_bytes == 0) + { + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) reached end of input, connection closed by client\n")); + break; + } + else if (verbose + && ACE::write_n (ACE_STDOUT, request, r_bytes) != r_bytes) + ACE_ERROR ((LM_ERROR, + "%p\n", + "ACE::write_n")); + + total_bytes += size_t (r_bytes); + message_count++; + + delete [] request; + request = 0; + } + + timer.stop (); + + ACE_Profile_Timer::ACE_Elapsed_Time et; + timer.elapsed_time (et); + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("\t\treal time = %f secs \n\t\tuser time = %f secs \n\t\tsystem time = %f secs\n"), + et.real_time, + et.user_time, + et.system_time)); + + double messages_per_sec = double (message_count) / et.real_time; + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("\t\tmessages = %d\n\t\ttotal bytes = %d\n\t\tmbits/sec = %f\n\t\tusec-per-message = %f\n\t\tmessages-per-second = %0.00f\n"), + message_count, + total_bytes, + (((double) total_bytes * 8) / et.real_time) / (double) (1024 * 1024), + (et.real_time / (double) message_count) * 1000000, + messages_per_sec < 0 ? 0 : messages_per_sec)); + + // Close new endpoint (listening endpoint stays open). + new_stream.close (); + + delete [] request; + return 0; +} + +static int +run_event_loop (u_short port) +{ + // Raise the socket handle limit to the maximum. + ACE::set_handle_limit (); + + // Create the oneway and twoway acceptors. + ACE_SOCK_Acceptor twoway_acceptor; + ACE_SOCK_Acceptor oneway_acceptor; + + // Create the oneway and twoway server addresses. + ACE_INET_Addr twoway_server_addr (port); + ACE_INET_Addr oneway_server_addr (port + 1); + + // Create acceptors, reuse the address. + if (twoway_acceptor.open (twoway_server_addr, 1) == -1 + || oneway_acceptor.open (oneway_server_addr, 1) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "open"), + 1); + // Check to see what addresses we actually got bound to! + else if (twoway_acceptor.get_local_addr (twoway_server_addr) == -1 + || oneway_acceptor.get_local_addr (oneway_server_addr) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "get_local_addr"), + 1); + + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) starting twoway server at port %d and oneway server at port %d\n", + twoway_server_addr.get_port_number (), + oneway_server_addr.get_port_number ())); + + // Keep these objects out here to prevent excessive constructor + // calls within the loop. + ACE_SOCK_Stream new_stream; + + ACE_Handle_Set handle_set; + handle_set.set_bit (twoway_acceptor.get_handle ()); + handle_set.set_bit (oneway_acceptor.get_handle ()); + + // Performs the iterative server activities. + + for (;;) + { + ACE_Time_Value timeout (ACE_DEFAULT_TIMEOUT); + ACE_Handle_Set temp = handle_set; + + int result = ACE_OS::select (int (oneway_acceptor.get_handle ()) + 1, + (fd_set *) temp, + 0, + 0, + timeout); + if (result == -1) + ACE_ERROR ((LM_ERROR, + "(%P|%t) %p\n", + "select")); + else if (result == 0 && verbose) + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) select timed out\n")); + else + { + if (temp.is_set (twoway_acceptor.get_handle ())) + { + if (twoway_acceptor.accept (new_stream) == -1) + { + ACE_ERROR ((LM_ERROR, + "%p\n", + "accept")); + continue; + } + else + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) spawning twoway server\n")); + + // Run the twoway server. + run_server (twoway_server, + new_stream.get_handle ()); + } + if (temp.is_set (oneway_acceptor.get_handle ())) + { + if (oneway_acceptor.accept (new_stream) == -1) + { + ACE_ERROR ((LM_ERROR, "%p\n", "accept")); + continue; + } + else + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) spawning oneway server\n")); + + // Run the oneway server. + run_server (oneway_server, + new_stream.get_handle ()); + } + } + } + + /* NOTREACHED */ +} + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + u_short port = ACE_DEFAULT_SERVER_PORT; + + if (argc > 1) + port = ACE_OS::atoi (argv[1]); + + return run_event_loop (port); +} diff --git a/ACE/examples/IPC_SAP/SOCK_SAP/CPP-memclient.cpp b/ACE/examples/IPC_SAP/SOCK_SAP/CPP-memclient.cpp new file mode 100644 index 00000000000..59c4beaa487 --- /dev/null +++ b/ACE/examples/IPC_SAP/SOCK_SAP/CPP-memclient.cpp @@ -0,0 +1,53 @@ +// $Id$ + +// This tests the features of the <ACE_MEM_Connector> and +// <ACE_MEM_Stream> classes. In addition, it can be used to test the +// oneway and twoway latency and throughput at the socket-level. This +// is useful as a baseline to compare against ORB-level performance +// for the same types of data. + +#include "ace/OS_NS_string.h" +#include "ace/MEM_Connector.h" +#include "ace/INET_Addr.h" +#include "ace/Thread_Manager.h" +#include "ace/Singleton.h" +#include "ace/Get_Opt.h" +#include "ace/High_Res_Timer.h" + + +ACE_RCSID(SOCK_SAP, CPP_inclient, "$Id$") + +static int +run_client (void) +{ + ACE_MEM_Connector connector; + ACE_MEM_Stream stream; + ACE_MEM_Addr server_addr (ACE_DEFAULT_SERVER_PORT); + + if (connector.connect (stream, server_addr.get_remote_addr ()) == -1) + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), + ACE_TEXT ("connect")), -1); + + char buf [MAXPATHLEN]; + while (fgets (buf, MAXPATHLEN, stdin) >0) + { + stream.send (buf, ACE_OS::strlen (buf)+1); + stream.recv (buf, MAXPATHLEN); + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Echo: %C\n"), buf)); + } + + return 0; +} + +int ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + ACE_UNUSED_ARG(argc); + // Initialize the logger. + ACE_LOG_MSG->open (argv[0]); + + // Run the client + run_client (); + + return 0; +} + diff --git a/ACE/examples/IPC_SAP/SOCK_SAP/CPP-memserver.cpp b/ACE/examples/IPC_SAP/SOCK_SAP/CPP-memserver.cpp new file mode 100644 index 00000000000..4ef76e51b38 --- /dev/null +++ b/ACE/examples/IPC_SAP/SOCK_SAP/CPP-memserver.cpp @@ -0,0 +1,70 @@ +// $Id$ + +// This example tests the features of the <ACE_MEM_Acceptor>, +// <ACE_MEM_Stream>, and <ACE_Svc_Handler> classes. If the platform +// supports threads it uses a thread-per-connection concurrency model. +// Otherwise, it uses a single-threaded iterative server model. + +#include "ace/MEM_Acceptor.h" +#include "ace/Thread_Manager.h" +#include "ace/Handle_Set.h" +#include "ace/Profile_Timer.h" + +ACE_RCSID(SOCK_SAP, CPP_inserver, "$Id$") + +static int +run_event_loop (u_short port) +{ + // Create the acceptors. + ACE_MEM_Acceptor acceptor; + + ACE_MEM_Addr server_addr (port); + + // Create acceptors, reuse the address. + if (acceptor.open (server_addr, 1) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "open"), + 1); + else if (acceptor.get_local_addr (server_addr) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "get_local_addr"), + 1); + + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) starting server at port %d\n", + server_addr.get_port_number ())); + + // Keep these objects out here to prevent excessive constructor + // calls within the loop. + ACE_MEM_Stream new_stream; + + // blocking wait on accept. + if (acceptor.accept (new_stream) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "accept"), + -1); + + char buf[MAXPATHLEN]; + int len = 0; + while ((len = new_stream.recv (buf, MAXPATHLEN)) != -1) + { + ACE_DEBUG ((LM_DEBUG, "%s\n", buf)); + new_stream.send (buf, len); + } + + return new_stream.fini (); +} + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + u_short port = ACE_DEFAULT_SERVER_PORT; + + if (argc > 1) + port = ACE_OS::atoi (argv[1]); + + return run_event_loop (port); +} diff --git a/ACE/examples/IPC_SAP/SOCK_SAP/CPP-unclient.cpp b/ACE/examples/IPC_SAP/SOCK_SAP/CPP-unclient.cpp new file mode 100644 index 00000000000..9f3fdec22b9 --- /dev/null +++ b/ACE/examples/IPC_SAP/SOCK_SAP/CPP-unclient.cpp @@ -0,0 +1,71 @@ +// $Id$ + +// ACE_LSOCK Client. + +#include "ace/LSOCK_Connector.h" +#include "ace/UNIX_Addr.h" +#include "ace/Log_Msg.h" +#include "ace/OS_main.h" +#include "ace/OS_NS_unistd.h" + +ACE_RCSID(SOCK_SAP, CPP_unclient, "$Id$") + +#if !defined (ACE_LACKS_UNIX_DOMAIN_SOCKETS) +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + const ACE_TCHAR *rendezvous = argc > 1 ? argv[1] : ACE_DEFAULT_RENDEZVOUS; + char buf[BUFSIZ]; + + ACE_LSOCK_Stream cli_stream; + ACE_LSOCK_Connector con; + ACE_UNIX_Addr remote_addr (rendezvous); + + // Establish the connection with server. + if (con.connect (cli_stream, remote_addr) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("connect")), + 1); + + // Send data to server (correctly handles "incomplete writes"). + + for (int r_bytes; + (r_bytes = ACE_OS::read (ACE_STDIN, buf, sizeof buf)) > 0; + ) + if (cli_stream.send_n (buf, r_bytes) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("send_n")), + 1); + + // Explicitly close the writer-side of the connection. + if (cli_stream.close_writer () == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("close_writer")), + 1); + + // Wait for handshake with server. + if (cli_stream.recv_n (buf, 1) != 1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("recv_n")), + 1); + + // Close the connection completely. + if (cli_stream.close () == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("close")), + 1); + return 0; +} +#else +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_ERROR_RETURN ((LM_ERROR, + "this platform does not support UNIX-domain sockets\n"), -1); +} +#endif /* ACE_LACKS_UNIX_DOMAIN_SOCKETS */ diff --git a/ACE/examples/IPC_SAP/SOCK_SAP/CPP-unserver.cpp b/ACE/examples/IPC_SAP/SOCK_SAP/CPP-unserver.cpp new file mode 100644 index 00000000000..cddfe787d92 --- /dev/null +++ b/ACE/examples/IPC_SAP/SOCK_SAP/CPP-unserver.cpp @@ -0,0 +1,159 @@ +// $Id$ + +// This example tests the features of the ACE_LSOCK_Acceptor and +// ACE_LSOCK_Stream classes. If the platform supports threads it uses +// a thread-per-request concurrency model. + +#include "ace/LSOCK_Acceptor.h" +#include "ace/Thread_Manager.h" +#include "ace/OS_main.h" +#include "ace/OS_NS_unistd.h" + +ACE_RCSID(SOCK_SAP, CPP_unserver, "$Id$") + +#if !defined (ACE_LACKS_UNIX_DOMAIN_SOCKETS) + +// Are we running verbosely? +static int verbose = 1; + +// Entry point into the server task. + +static void * +server (void *arg) +{ + ACE_UNIX_Addr cli_addr; + ACE_LSOCK_Stream new_stream; + ACE_HANDLE handle = (ACE_HANDLE) (long) arg; + + new_stream.set_handle (handle); + + // Make sure we're not in non-blocking mode. + if (new_stream.disable (ACE_NONBLOCK) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("disable")), + 0); + + if (new_stream.get_remote_addr (cli_addr) == -1) + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("get_remote_addr"))); + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) client connected from %C\n"), + cli_addr.get_path_name ())); + + // Read data from client (terminate on error). + + for (;;) + { + char buf[BUFSIZ]; + + ssize_t r_bytes = new_stream.recv (buf, sizeof buf); + + if (r_bytes == -1) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("recv"))); + break; + + } + else if (r_bytes == 0) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) reached end of input, connection closed by client\n"))); + break; + } + else if (verbose && ACE::write_n (ACE_STDOUT, buf, r_bytes) != r_bytes) + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("ACE::write_n"))); + else if (new_stream.send_n (buf, r_bytes) != r_bytes) + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("send_n"))); + } + + // Close new endpoint (listening endpoint stays open). + if (new_stream.close () == -1) + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("close"))); + + return 0; +} + +static int +run_event_loop (const ACE_TCHAR rendezvous[]) +{ + ACE_LSOCK_Acceptor peer_acceptor; + + // Create a server address. + ACE_UNIX_Addr server_addr (rendezvous); + + ACE_OS::unlink (rendezvous); + + // Create a server. + + if (peer_acceptor.open (server_addr) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("open")), + 1); + else if (peer_acceptor.get_local_addr (server_addr) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("get_local_addr")), + -1); + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("starting server %C\n"), + server_addr.get_path_name ())); + + // Keep these guys out here to prevent excessive constructor + // calls... + ACE_LSOCK_Stream new_stream; + + // Performs the iterative server activities. + + for (;;) + { + ACE_Time_Value timeout (ACE_DEFAULT_TIMEOUT); + + if (peer_acceptor.accept (new_stream, 0, &timeout) == -1) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("accept"))); + continue; + } + +#if defined (ACE_HAS_THREADS) + if (ACE_Thread_Manager::instance ()->spawn ((ACE_THR_FUNC) server, + reinterpret_cast<void *> (new_stream.get_handle ()), + THR_DETACHED) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("(%P|%t) %p\n"), + ACE_TEXT ("spawn")), + 1); +#else + server (reinterpret_cast<void *> (new_stream.get_handle ())); +#endif /* ACE_HAS_THREADS */ + } + + ACE_NOTREACHED (return 0;) +} + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + return run_event_loop (argc > 1 ? argv[1] : ACE_DEFAULT_RENDEZVOUS); +} +#else +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_ERROR_RETURN ((LM_ERROR, + "this platform does not support UNIX-domain sockets\n"), -1); +} +#endif /* ACE_LACKS_UNIX_DOMAIN_SOCKETS */ diff --git a/ACE/examples/IPC_SAP/SOCK_SAP/FD-unclient.cpp b/ACE/examples/IPC_SAP/SOCK_SAP/FD-unclient.cpp new file mode 100644 index 00000000000..1c21aeb74c0 --- /dev/null +++ b/ACE/examples/IPC_SAP/SOCK_SAP/FD-unclient.cpp @@ -0,0 +1,60 @@ +// $Id$ + +#include "ace/OS_NS_fcntl.h" +#include "ace/LSOCK_Connector.h" +#include "ace/UNIX_Addr.h" +#include "ace/Log_Msg.h" +#include "ace/OS_main.h" + +ACE_RCSID(SOCK_SAP, FD_unclient, "$Id$") + +#if defined (ACE_HAS_MSG) && !defined (ACE_LACKS_UNIX_DOMAIN_SOCKETS) +// ACE_LSOCK Client. + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + const ACE_TCHAR *file_name = argc > 1 ? argv[1] : ACE_TEXT ("./local_data"); + const ACE_TCHAR *rendezvous = argc > 2 ? argv[2] : ACE_DEFAULT_RENDEZVOUS; + + ACE_LSOCK_Stream cli_stream; + ACE_UNIX_Addr addr (rendezvous); + + // Establish the connection with server. + ACE_LSOCK_Connector connector; + + if (connector.connect (cli_stream, addr) == -1) + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p"), ACE_TEXT ("connect")), -1); + + ACE_HANDLE handle = ACE_OS::open (file_name, O_RDONLY); + + if (handle == ACE_INVALID_HANDLE) + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p"), ACE_TEXT ("open")), -1); + + // Send handle to server (correctly handles incomplete writes). + if (cli_stream.send_handle (handle) == -1) + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p"), ACE_TEXT ("send")), -1); + + char buf[BUFSIZ]; + ssize_t n = cli_stream.recv (buf, sizeof buf); + + if (n == -1) + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p"), ACE_TEXT ("recv")), -1); + else if (n == 0) + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("server shutdown (bug in kernel?)\n"))); + else + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("server %*C shutdown\n"), n, buf)); + + // Explicitly close the connection. + if (cli_stream.close () == -1) + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p"), ACE_TEXT ("close")), -1); + + return 0; +} +#else +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("your platform must support sendmsg/recvmsg to run this test\n")), -1); +} +#endif /* ACE_HAS_MSG */ diff --git a/ACE/examples/IPC_SAP/SOCK_SAP/FD-unserver.cpp b/ACE/examples/IPC_SAP/SOCK_SAP/FD-unserver.cpp new file mode 100644 index 00000000000..b629b9f0dd8 --- /dev/null +++ b/ACE/examples/IPC_SAP/SOCK_SAP/FD-unserver.cpp @@ -0,0 +1,100 @@ +// $Id$ + +#include "ace/LSOCK_Acceptor.h" +#include "ace/LSOCK_Stream.h" +#include "ace/UNIX_Addr.h" +#include "ace/Log_Msg.h" +#include "ace/OS_main.h" +#include "ace/OS_NS_string.h" +#include "ace/OS_NS_stdio.h" +#include "ace/OS_NS_unistd.h" +#include "ace/OS_NS_stdlib.h" + +ACE_RCSID(SOCK_SAP, FD_unserver, "$Id$") + +#if !defined (ACE_LACKS_UNIX_DOMAIN_SOCKETS) + +// ACE_LSOCK Server + +void +handle_client (ACE_LSOCK_Stream &stream) +{ + char buf[BUFSIZ]; + ACE_HANDLE handle; + + // Retrieve the socket descriptor passed from the client. + + if (stream.recv_handle (handle) == -1) + ACE_ERROR ((LM_ERROR, "%p", "recv_handle")); + + ACE_DEBUG ((LM_DEBUG, "(%P|%t) ----------------------------------------\n")); + + // Read data from client (correctly handles incomplete reads due to + // flow control). + + for (ssize_t n; + (n = ACE_OS::read (handle, buf, sizeof buf)) > 0; + ) + ACE_DEBUG ((LM_DEBUG, "%*s", n, buf)); + + ACE_OS::sprintf (buf, "%d", static_cast<int> (ACE_OS::getpid ())); + + ACE_DEBUG ((LM_DEBUG, "(%s, %d) ----------------------------------------\n", buf, ACE_OS::strlen (buf))); + + // Tell the client to shut down. + if (stream.send_n (buf, ACE_OS::strlen (buf)) == -1) + ACE_ERROR ((LM_ERROR, "%p", "send")); + + // Close new endpoint (listening endpoint stays open). + if (stream.close () == -1) + ACE_ERROR ((LM_ERROR, "%p", "close")); +} + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + const ACE_TCHAR *rendezvous = argc > 1 ? argv[1] : ACE_DEFAULT_RENDEZVOUS; + // Create a server. + ACE_OS::unlink (rendezvous); + ACE_UNIX_Addr addr (rendezvous); + ACE_LSOCK_Acceptor peer_acceptor (addr); + ACE_LSOCK_Stream stream; + + // Performs the concurrent server activities. + + for (;;) + { + // Create a new ACE_SOCK_Stream endpoint. + if (peer_acceptor.accept (stream) == -1) + ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) %p\n", "accept"), -1); + + ACE_DEBUG ((LM_DEBUG, "(%P|%t) accepted new connection\n")); + +#if defined (VXWORKS) + handle_client (stream); +#else + switch (ACE_OS::fork (argv[0])) + { + case -1: + ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) %p\n", "fork"), -1); + /* NOTREACHED */ + case 0: + ACE_LOG_MSG->sync (argv[0]); + handle_client (stream); + ACE_OS::exit (0); + /* NOTREACHED */ + default: + stream.close (); + } +#endif /* VXWORKS */ + } + + ACE_NOTREACHED (return 0;) +} +#else +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_ERROR_RETURN ((LM_ERROR, "your platform doesn't not support UNIX domain sockets\n"), -1); +} +#endif /* ACE_LACKS_UNIX_DOMAIN_SOCKETS */ diff --git a/ACE/examples/IPC_SAP/SOCK_SAP/Makefile.am b/ACE/examples/IPC_SAP/SOCK_SAP/Makefile.am new file mode 100644 index 00000000000..50260dc7343 --- /dev/null +++ b/ACE/examples/IPC_SAP/SOCK_SAP/Makefile.am @@ -0,0 +1,179 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +ACE_BUILDDIR = $(top_builddir) +ACE_ROOT = $(top_srcdir) + + +## Makefile.Sock_Sap_CPP_Inclient.am +noinst_PROGRAMS = CPP-inclient + +CPP_inclient_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +CPP_inclient_SOURCES = \ + CPP-inclient.cpp \ + CPP-inclient.h + +CPP_inclient_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Sock_Sap_CPP_Inserver.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS += CPP-inserver + +CPP_inserver_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +CPP_inserver_SOURCES = \ + CPP-inserver.cpp \ + CPP-inclient.h \ + CPP-inserver-fancy.h + +CPP_inserver_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Makefile.Sock_Sap_CPP_Memclient.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS += CPP-memclient + +CPP_memclient_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +CPP_memclient_SOURCES = \ + CPP-memclient.cpp \ + CPP-inclient.h \ + CPP-inserver-fancy.h + +CPP_memclient_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Makefile.Sock_Sap_CPP_Memserver.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS += CPP-memserver + +CPP_memserver_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +CPP_memserver_SOURCES = \ + CPP-memserver.cpp \ + CPP-inclient.h \ + CPP-inserver-fancy.h + +CPP_memserver_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Makefile.Sock_Sap_CPP_Unclient.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS += CPP-unclient + +CPP_unclient_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +CPP_unclient_SOURCES = \ + CPP-unclient.cpp \ + CPP-inclient.h \ + CPP-inserver-fancy.h + +CPP_unclient_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Makefile.Sock_Sap_CPP_Unserver.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS += CPP-unserver + +CPP_unserver_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +CPP_unserver_SOURCES = \ + CPP-unserver.cpp \ + CPP-inclient.h \ + CPP-inserver-fancy.h + +CPP_unserver_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Makefile.Sock_Sap_C_Inclient.am +noinst_PROGRAMS += C-inclient + +C_inclient_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +C_inclient_SOURCES = \ + C-inclient.cpp \ + CPP-inclient.h \ + CPP-inserver-fancy.h + +C_inclient_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Sock_Sap_C_Inserver.am +noinst_PROGRAMS += C-inserver + +C_inserver_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +C_inserver_SOURCES = \ + C-inserver.cpp \ + CPP-inclient.h \ + CPP-inserver-fancy.h + +C_inserver_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Sock_Sap_FD_Unclient.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS += FD-unclient + +FD_unclient_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +FD_unclient_SOURCES = \ + FD-unclient.cpp \ + CPP-inclient.h \ + CPP-inserver-fancy.h + +FD_unclient_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Clean up template repositories, etc. +clean-local: + -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.* + -rm -f gcctemp.c gcctemp so_locations *.ics + -rm -rf cxx_repository ptrepository ti_files + -rm -rf templateregistry ir.out + -rm -rf ptrepository SunWS_cache Templates.DB diff --git a/ACE/examples/IPC_SAP/SOCK_SAP/README b/ACE/examples/IPC_SAP/SOCK_SAP/README new file mode 100644 index 00000000000..bbe0f20ce5a --- /dev/null +++ b/ACE/examples/IPC_SAP/SOCK_SAP/README @@ -0,0 +1,46 @@ +This directory contains groups of client and server test programs that +exercise the various C++ wrappers for sockets. In general, the test +programs do more or less the same thing -- the client establishes a +connection with the server and then transfers data to the server, +which keeps printing the data until EOF is reached (e.g., user types +^D). + +Unless noted differently, the server is implemented as an "iterative +server," i.e., it only deals with one client at a time. The following +describes each set of tests in more detail: + + . C-{inclient,inserver}.cpp -- This is basically a C code + implementation that opens a connection to the server and + sends all the data from the stdin using Internet domain + sockets (i.e., TCP). + + . CPP-{inclient,inserver}.cpp -- This test is + a more sophisticated C++ wrapper version of the preceeding + "C" test using Internet domain sockets (i.e., TCP). + It allows you to test oneway and twoway socket communication + latency and throughput between two processes on the same + machine or on different machines. + + . CPP-inserver-fancy.cpp -- This program is a more glitzy + version of CPP-inserver.cpp that illustrates additional + features of ACE, such as ACE_Svc_Handler. + + . CPP-inserver-poll.cpp -- This test illustrates how to + write single-threaded concurrent servers using UNIX SVR4 + poll(). You can run this test using the CPP-inclient.cpp + program as the oneway client. + + . CPP-{unclient,unserver}.cpp -- This test is basically + a C++ wrapper version of the preceeding "C++" test using + UNIX domain sockets. Note that this test only works + between a client and server process on the same machine. + + . FD-{unclient,inclient}.cpp -- This test illustrates + how to pass file descriptors between a client and a + concurrent server process on the same machine using the ACE + C++ wrappers for UNIX domain sockets. + +For examples of the ACE SOCK_{Dgram,CODgram} and +SOCK_Dgram_{Mcast,Bcast} wrappers, please take a look in the +./examples/Reactor/{Dgram,Multicast,Ntalker} directories. + diff --git a/ACE/examples/IPC_SAP/SOCK_SAP/local_data b/ACE/examples/IPC_SAP/SOCK_SAP/local_data new file mode 100644 index 00000000000..c0119859a28 --- /dev/null +++ b/ACE/examples/IPC_SAP/SOCK_SAP/local_data @@ -0,0 +1 @@ +I am Iron man! diff --git a/ACE/examples/IPC_SAP/SOCK_SAP/run_test b/ACE/examples/IPC_SAP/SOCK_SAP/run_test new file mode 100755 index 00000000000..7f0a4dbdaa7 --- /dev/null +++ b/ACE/examples/IPC_SAP/SOCK_SAP/run_test @@ -0,0 +1,36 @@ +#! /bin/sh +# $Id$ +# +# Spawns CPP-inserver-fancy and CPP-inclient executables on a single host. + +usage="usage: $0 #client_threads" + +user=`whoami` +iterations=1000 + +if [ $# -ne 1 ]; then + echo $usage; + exit 1 +fi +threads=$1; + + +######## +######## Enable signal handler. +######## +trap 'kill -1 $server_pid; ' 0 1 2 15 + + +######## +######## Start CPP-inserver-fancy and save its pid. +######## +./CPP-inserver-fancy > \ + ${tmp}server.log 2>&1 & +server_pid=$! + +sleep 2; + +######## +######## Start CPP-inclient. +######## +./CPP-inclient -2 -T 100000 -m 69 -t $threads -i 100 > ${tmp}client-${threads}.log 2>&1 diff --git a/ACE/examples/IPC_SAP/SOCK_SAP/sock_sap.mpc b/ACE/examples/IPC_SAP/SOCK_SAP/sock_sap.mpc new file mode 100644 index 00000000000..814280a515c --- /dev/null +++ b/ACE/examples/IPC_SAP/SOCK_SAP/sock_sap.mpc @@ -0,0 +1,72 @@ +// -*- MPC -*- +// $Id$ + +project(*C_inclient) : aceexe { + exename = C-inclient + Source_Files { + C-inclient.cpp + } +} + +project(*C_inserver) : aceexe { + exename = C-inserver + Source_Files { + C-inserver.cpp + } +} + +project(*CPP_inclient) : aceexe { + exename = CPP-inclient + Source_Files { + CPP-inclient.cpp + } +} + +project(*CPP_inserver) : aceexe { + avoids += ace_for_tao + exename = CPP-inserver + Source_Files { + CPP-inserver.cpp + } +} + +project(*CPP_memclient) : aceexe { + avoids += ace_for_tao + exename = CPP-memclient + Source_Files { + CPP-memclient.cpp + } +} + +project(*CPP_memserver) : aceexe { + avoids += ace_for_tao + exename = CPP-memserver + Source_Files { + CPP-memserver.cpp + } +} + +project(*FD_unclient) : aceexe { + avoids += ace_for_tao + exename = FD-unclient + Source_Files { + FD-unclient.cpp + } +} + +project(*CPP_unclient) : aceexe { + avoids += ace_for_tao + exename = CPP-unclient + Source_Files { + CPP-unclient.cpp + } +} + +project(*CPP_unserver) : aceexe { + avoids += ace_for_tao + exename = CPP-unserver + Source_Files { + CPP-unserver.cpp + } +} + diff --git a/ACE/examples/IPC_SAP/SOCK_SAP/summarize b/ACE/examples/IPC_SAP/SOCK_SAP/summarize new file mode 100755 index 00000000000..ee8ffd2df25 --- /dev/null +++ b/ACE/examples/IPC_SAP/SOCK_SAP/summarize @@ -0,0 +1,45 @@ +eval '(exit $?0)' && eval 'exec perl -w -S $0 ${1+"$@"}' + & eval 'exec perl -w -S $0 $argv:q' + if 0; + +# $Id$ +# +# Summarizes results from a series of runs of run_test, with +# different numbers of clients. Example usage: +# +# $ for i in 1 2 5 10 15 20 25 30 35 40 45 50; do ./run_test $i; done +# $ ./summarize +# +# The first three lines above let this script run without specifying the +# full path to perl, as long as it is in the user's PATH. +# Taken from perlrun man page. + +@files = glob 'client-*.log'; +@total_threads = (); + +foreach $file (@files) { + my ($i); + ($i = $file) =~ s/client-(\d+).log/$1/; + push @total_threads, $i; +} + +print "No.of threads\t\tAverage Latency\n\n"; + +foreach $total_threads (sort {$a <=> $b} @total_threads) { + undef $high_latency; + + $high_latency = 0; + open (FILE, "client-${total_threads}.log") || + die "$0: unable to open \"client-${total_threads}.log\"\n"; + while ($line = <FILE>) { + if ($line =~ /.*usec-per-message = ([\d\.]+)/) + { + $high_latency += $1 ; + $number++; + } + } + close FILE; + + printf "%3d\t\t\t%8f\n", + $total_threads, $high_latency/$number; +} diff --git a/ACE/examples/IPC_SAP/SPIPE_SAP/.cvsignore b/ACE/examples/IPC_SAP/SPIPE_SAP/.cvsignore new file mode 100644 index 00000000000..46bf34bbdfd --- /dev/null +++ b/ACE/examples/IPC_SAP/SPIPE_SAP/.cvsignore @@ -0,0 +1,16 @@ +NPClient +NPClient +NPServer +NPServer +client +client +consumer_msg +consumer_msg +consumer_read +consumer_read +producer_msg +producer_msg +producer_read +producer_read +server +server diff --git a/ACE/examples/IPC_SAP/SPIPE_SAP/Makefile.am b/ACE/examples/IPC_SAP/SPIPE_SAP/Makefile.am new file mode 100644 index 00000000000..662c99fc452 --- /dev/null +++ b/ACE/examples/IPC_SAP/SPIPE_SAP/Makefile.am @@ -0,0 +1,132 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +ACE_BUILDDIR = $(top_builddir) +ACE_ROOT = $(top_srcdir) + +## Makefile.SPIPE_SAP_Client.am +noinst_PROGRAMS = client + +client_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +client_SOURCES = \ + client.cpp \ + shared.h + +client_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.SPIPE_SAP_Consumer_Msg.am +noinst_PROGRAMS += consumer_msg + +consumer_msg_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +consumer_msg_SOURCES = \ + consumer_msg.cpp \ + shared.h + +consumer_msg_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.SPIPE_SAP_Consumer_Read.am +noinst_PROGRAMS += consumer_read + +consumer_read_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +consumer_read_SOURCES = \ + consumer_read.cpp \ + shared.h + +consumer_read_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.SPIPE_SAP_NPClient.am +noinst_PROGRAMS += NPClient + +NPClient_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +NPClient_SOURCES = \ + NPClient.cpp \ + shared.h + +NPClient_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.SPIPE_SAP_NPServer.am +noinst_PROGRAMS += NPServer + +NPServer_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +NPServer_SOURCES = \ + NPServer.cpp \ + shared.h + +NPServer_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.SPIPE_SAP_Producer_Msg.am +noinst_PROGRAMS += producer_msg + +producer_msg_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +producer_msg_SOURCES = \ + producer_msg.cpp \ + shared.h + +producer_msg_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.SPIPE_SAP_Producer_Read.am +noinst_PROGRAMS += producer_read + +producer_read_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +producer_read_SOURCES = \ + producer_read.cpp \ + shared.h + +producer_read_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.SPIPE_SAP_Server.am +noinst_PROGRAMS += server + +server_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +server_SOURCES = \ + server.cpp \ + shared.h + +server_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Clean up template repositories, etc. +clean-local: + -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.* + -rm -f gcctemp.c gcctemp so_locations *.ics + -rm -rf cxx_repository ptrepository ti_files + -rm -rf templateregistry ir.out + -rm -rf ptrepository SunWS_cache Templates.DB diff --git a/ACE/examples/IPC_SAP/SPIPE_SAP/NPClient.cpp b/ACE/examples/IPC_SAP/SPIPE_SAP/NPClient.cpp new file mode 100644 index 00000000000..e7c6c5904aa --- /dev/null +++ b/ACE/examples/IPC_SAP/SPIPE_SAP/NPClient.cpp @@ -0,0 +1,62 @@ +// $Id$ + +#include "ace/OS_main.h" +#include "ace/SPIPE_Addr.h" +#include "ace/SPIPE_Connector.h" +#include "ace/Log_Msg.h" +#include "ace/OS_NS_string.h" +#include "ace/OS_NS_stdlib.h" +#include "ace/OS_Memory.h" + +ACE_RCSID(SPIPE_SAP, NPClient, "$Id$") + +#if defined (ACE_WIN32) +#define MAKE_PIPE_NAME(X) ACE_TEXT ("\\\\.\\pipe\\") ACE_TEXT (X) +#else +#define MAKE_PIPE_NAME(X) ACE_TEXT (X) +#endif + +const int DEFAULT_SIZE = 8; +const int DEFAULT_COUNT = 10000; + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + int size = argc > 1 ? ACE_OS::atoi (argv[1]) : DEFAULT_SIZE; + int iterations = argc > 2 ? ACE_OS::atoi (argv[2]) : DEFAULT_COUNT; + char *buf; + + ACE_NEW_RETURN (buf, + char[size], + 1); + + const ACE_TCHAR *rendezvous = MAKE_PIPE_NAME ("acepipe"); + + ACE_SPIPE_Stream cli_stream; + ACE_SPIPE_Connector con; + int i; + + if (con.connect (cli_stream, + ACE_SPIPE_Addr (rendezvous)) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + rendezvous), + -1); + + ACE_OS::strcpy (buf, "hello"); + size = ACE_OS::strlen (buf) + 1; + + for (i = 0; i < iterations; i++) + if (cli_stream.send (buf, size) != size) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("putmsg")), + -1); + + if (cli_stream.close () == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("close")), + -1); + return 0; +} diff --git a/ACE/examples/IPC_SAP/SPIPE_SAP/NPServer.cpp b/ACE/examples/IPC_SAP/SPIPE_SAP/NPServer.cpp new file mode 100644 index 00000000000..4055a2cc02d --- /dev/null +++ b/ACE/examples/IPC_SAP/SPIPE_SAP/NPServer.cpp @@ -0,0 +1,67 @@ +// $Id$ + +#include "ace/SPIPE_Addr.h" +#include "ace/SPIPE_Acceptor.h" +#include "ace/Log_Msg.h" +#include "ace/OS_NS_stdio.h" +#include "ace/OS_NS_unistd.h" + +ACE_RCSID(SPIPE_SAP, NPServer, "$Id$") + +#if defined (ACE_WIN32) +#define MAKE_PIPE_NAME(X) ACE_TEXT ("\\\\.\\pipe\\") ACE_TEXT (X) +#else +#define MAKE_PIPE_NAME(X) ACE_TEXT (X) +#endif + +int +ACE_TMAIN (int /* argc */, ACE_TCHAR * /* argv */ []) +{ + ACE_SPIPE_Acceptor acceptor; + ACE_SPIPE_Stream new_stream; + char buf[BUFSIZ]; + int n; + const ACE_TCHAR *rendezvous = MAKE_PIPE_NAME ("acepipe"); + + // Initialize named pipe listener. + + if (acceptor.open (ACE_SPIPE_Addr (rendezvous)) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("open")), 1); + + for (;;) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("waiting for connection\n"))); + + // Accept a client connection. + if (acceptor.accept (new_stream, 0) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("accept")), + 1); + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("Accepted connection\n"))); + + while ((n = new_stream.recv (buf, sizeof buf)) > 0) + { + ACE_OS::fprintf (stderr, + "%s\n", + buf); + ACE_OS::write (ACE_STDOUT, + buf, + n); + } + + if (n == -1) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("End of connection. Closing handle\n"))); + new_stream.close (); + } + } + + ACE_NOTREACHED(return 0); +} diff --git a/ACE/examples/IPC_SAP/SPIPE_SAP/SPIPE_SAP.mpc b/ACE/examples/IPC_SAP/SPIPE_SAP/SPIPE_SAP.mpc new file mode 100644 index 00000000000..3f0d7318b3e --- /dev/null +++ b/ACE/examples/IPC_SAP/SPIPE_SAP/SPIPE_SAP.mpc @@ -0,0 +1,58 @@ +// -*- MPC -*- +// $Id$ + +project(*client) : aceexe { + exename = client + Source_Files { + client.cpp + } +} + +project(*consumer_msg) : aceexe { + exename = consumer_msg + Source_Files { + consumer_msg.cpp + } +} + +project(*consumer_read) : aceexe { + exename = consumer_read + Source_Files { + consumer_read.cpp + } +} + +project(*NPClient) : aceexe { + exename = NPClient + Source_Files { + NPClient.cpp + } +} + +project(*NPServer) : aceexe { + exename = NPServer + Source_Files { + NPServer.cpp + } +} + +project(*producer_msg) : aceexe { + exename = producer_msg + Source_Files { + producer_msg.cpp + } +} + +project(*producer_read) : aceexe { + exename = producer_read + Source_Files { + producer_read.cpp + } +} + +project(*server) : aceexe { + exename = server + Source_Files { + server.cpp + } +} diff --git a/ACE/examples/IPC_SAP/SPIPE_SAP/client.cpp b/ACE/examples/IPC_SAP/SPIPE_SAP/client.cpp new file mode 100644 index 00000000000..ad0ee029dbd --- /dev/null +++ b/ACE/examples/IPC_SAP/SPIPE_SAP/client.cpp @@ -0,0 +1,48 @@ +// $Id$ + +#include "ace/OS_main.h" +#include "ace/SPIPE_Addr.h" +#include "ace/SPIPE_Connector.h" +#include "ace/Log_Msg.h" +#include "ace/OS_NS_stdio.h" +#include "ace/OS_NS_string.h" + +ACE_RCSID(SPIPE_SAP, client, "$Id$") + +#if defined (ACE_HAS_STREAM_PIPES) + +#include "shared.h" + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + if (argc < 2) + ACE_ERROR_RETURN ((LM_ERROR, "usage: %s string [rendezvous]\n", argv[0]), 1); + + if (argc > 2) + rendezvous = argv[2]; + + ACE_SPIPE_Stream cli_stream; + ACE_SPIPE_Connector con; + + if (con.connect (cli_stream, ACE_SPIPE_Addr (rendezvous)) == -1) + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", rendezvous), 1); + + ssize_t len = ACE_OS::strlen (argv[1]) + 1; + + if (cli_stream.send (argv[1], len) != len) + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "send"), 1); + + if (cli_stream.close () == -1) + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "close"), 1); + + return 0; +} +#else +#include <stdio.h> +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_OS::fprintf (stderr, "This feature is not supported\n"); + return 0; +} +#endif /* ACE_HAS_STREAM_PIPES */ diff --git a/ACE/examples/IPC_SAP/SPIPE_SAP/consumer_msg.cpp b/ACE/examples/IPC_SAP/SPIPE_SAP/consumer_msg.cpp new file mode 100644 index 00000000000..daadc20fdf0 --- /dev/null +++ b/ACE/examples/IPC_SAP/SPIPE_SAP/consumer_msg.cpp @@ -0,0 +1,59 @@ +// $Id$ + +#include "ace/OS_main.h" +#include "ace/SPIPE_Addr.h" +#include "ace/SPIPE_Acceptor.h" +#include "ace/Log_Msg.h" +#include "ace/OS_NS_stdio.h" +#include "ace/OS_NS_unistd.h" +#include "ace/Time_Value.h" + +ACE_RCSID(SPIPE_SAP, consumer_msg, "$Id$") + +#if defined (ACE_HAS_STREAM_PIPES) + +#include "shared.h" + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + ACE_SPIPE_Acceptor peer_acceptor; + ACE_SPIPE_Stream new_stream; + char buf[BUFSIZ]; + ACE_Str_Buf buffer (buf, 0, sizeof buf); + int flags = 0; + + if (argc > 1) + rendezvous = argv[1]; + + ACE_OS::unlink (rendezvous); + ACE_OS::fdetach (ACE_TEXT_ALWAYS_CHAR (rendezvous)); + + ACE_SPIPE_Addr addr (rendezvous); + ACE_Time_Value timeout (ACE_DEFAULT_TIMEOUT); + + if (peer_acceptor.open (addr) == -1) + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "open"), 1); + + ACE_DEBUG ((LM_DEBUG, "waiting for connection\n")); + + if (peer_acceptor.accept (new_stream, 0, &timeout) == -1) + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "accept"), 1); + + ACE_DEBUG ((LM_DEBUG, "accepted\n")); + + while (new_stream.recv ((ACE_Str_Buf *) 0, &buffer, &flags) >= 0) + if (buffer.len == 0) + break; + else + ACE_OS::write (ACE_STDOUT, buffer.buf, buffer.len); + return 0; +} +#else +#include <stdio.h> +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_OS::fprintf (stderr, "This feature is not supported\n"); + return 0; +} +#endif /* ACE_HAS_STREAM_PIPES */ diff --git a/ACE/examples/IPC_SAP/SPIPE_SAP/consumer_read.cpp b/ACE/examples/IPC_SAP/SPIPE_SAP/consumer_read.cpp new file mode 100644 index 00000000000..f16c0683680 --- /dev/null +++ b/ACE/examples/IPC_SAP/SPIPE_SAP/consumer_read.cpp @@ -0,0 +1,56 @@ +// $Id$ + +#include "ace/OS_main.h" +#include "ace/SPIPE_Addr.h" +#include "ace/SPIPE_Acceptor.h" +#include "ace/Log_Msg.h" +#include "ace/OS_NS_stdio.h" +#include "ace/OS_NS_unistd.h" +#include "ace/Time_Value.h" + +ACE_RCSID(SPIPE_SAP, consumer_read, "$Id$") + +#if defined (ACE_HAS_STREAM_PIPES) + +#include "shared.h" + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + ACE_SPIPE_Acceptor peer_acceptor; + ACE_SPIPE_Stream new_stream; + char buf[BUFSIZ]; + int n; + + // Wait up to ACE_DEFAULT_TIMEOUT seconds to accept connection. + ACE_Time_Value timeout (ACE_DEFAULT_TIMEOUT); + + if (argc > 1) + rendezvous = argv[1]; + + ACE_OS::unlink (rendezvous); + ACE_OS::fdetach (ACE_TEXT_ALWAYS_CHAR (rendezvous)); + + if (peer_acceptor.open (ACE_SPIPE_Addr (rendezvous)) == -1) + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "open"), 1); + + ACE_DEBUG ((LM_DEBUG, "waiting for connection\n")); + + if (peer_acceptor.accept (new_stream, 0, &timeout) == -1) + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "accept"), 1); + + ACE_DEBUG ((LM_DEBUG, "accepted\n")); + + while ((n = new_stream.recv (buf, sizeof buf)) > 0) + ACE_OS::write (ACE_STDOUT, buf, n); + + return 0; +} +#else +#include <stdio.h> +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_OS::fprintf (stderr, "This feature is not supported\n"); + return 0; +} +#endif /* ACE_HAS_STREAM_PIPES */ diff --git a/ACE/examples/IPC_SAP/SPIPE_SAP/producer_msg.cpp b/ACE/examples/IPC_SAP/SPIPE_SAP/producer_msg.cpp new file mode 100644 index 00000000000..619a44f1e71 --- /dev/null +++ b/ACE/examples/IPC_SAP/SPIPE_SAP/producer_msg.cpp @@ -0,0 +1,66 @@ +// $Id$ + +#include "ace/OS_main.h" +#include "ace/OS_Memory.h" +#include "ace/SPIPE_Addr.h" +#include "ace/SPIPE_Connector.h" +#include "ace/Log_Msg.h" +#include "ace/OS_NS_stdio.h" +#include "ace/OS_NS_stdlib.h" +#include "ace/OS_NS_unistd.h" +#include "ace/Time_Value.h" + +ACE_RCSID(SPIPE_SAP, producer_msg, "$Id$") + +#if defined (ACE_HAS_STREAM_PIPES) + +#include "shared.h" + +const int DEFAULT_SIZE = 4 * 1024; +const int DEFAULT_COUNT = 100; + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + int size = argc > 1 ? ACE_OS::atoi (argv[1]) : DEFAULT_SIZE; + int iterations = argc > 2 ? ACE_OS::atoi (argv[2]) : DEFAULT_COUNT; + char *buf; + + ACE_NEW_RETURN (buf, char[size], -1); + + if (argc > 3) + rendezvous = argv[3]; + + ACE_SPIPE_Stream cli_stream; + ACE_SPIPE_Connector con; + int i; + + if (con.connect (cli_stream, ACE_SPIPE_Addr (rendezvous)) == -1) + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", rendezvous), 1); + + for (i = 0; i < size; i++) + buf[i] = 'a'; + + ACE_Str_Buf buffer (buf, size); + + for (i = 0; i < iterations; i++) + if (cli_stream.send ((ACE_Str_Buf *) 0, + &buffer, + 1, + MSG_BAND) == -1) + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "send"), 1); + + if (cli_stream.close () == -1) + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "close"), 1); + + delete buf; + return 0; +} +#else +#include <stdio.h> +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_OS::fprintf (stderr, "This feature is not supported\n"); + return 0; +} +#endif /* ACE_HAS_STREAM_PIPES */ diff --git a/ACE/examples/IPC_SAP/SPIPE_SAP/producer_read.cpp b/ACE/examples/IPC_SAP/SPIPE_SAP/producer_read.cpp new file mode 100644 index 00000000000..f04f7961818 --- /dev/null +++ b/ACE/examples/IPC_SAP/SPIPE_SAP/producer_read.cpp @@ -0,0 +1,54 @@ +// $Id$ + +#include "ace/OS_main.h" +#include "ace/SPIPE_Addr.h" +#include "ace/SPIPE_Connector.h" +#include "ace/Log_Msg.h" +#include "ace/OS_NS_stdlib.h" + + +ACE_RCSID(SPIPE_SAP, producer_read, "$Id$") + +#if defined (ACE_HAS_STREAM_PIPES) + +#include "shared.h" + +const int DEFAULT_SIZE = 8 * 1024; +const int DEFAULT_COUNT = 100; + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + int size = argc > 1 ? ACE_OS::atoi (argv[1]) : DEFAULT_SIZE; + int iterations = argc > 2 ? ACE_OS::atoi (argv[2]) : DEFAULT_COUNT; + char *buf = new char[size]; + + if (argc > 3) + rendezvous = argv[3]; + + ACE_SPIPE_Stream cli_stream; + ACE_SPIPE_Connector con; + int i; + + if (con.connect (cli_stream, ACE_SPIPE_Addr (rendezvous)) == -1) + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", rendezvous), -1); + + for (i = 0; i < size; i++) + buf[i] = 'a'; + + for (i = 0; i < iterations; i++) + if (cli_stream.send (buf, size) != size) + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "putmsg"), -1); + + if (cli_stream.close () == -1) + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "close"), -1); + + return 0; +} +#else +#include <stdio.h> +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_ERROR_RETURN ((LM_ERROR, "this feature is not supported"), -1); +} +#endif /* ACE_HAS_STREAM_PIPES */ diff --git a/ACE/examples/IPC_SAP/SPIPE_SAP/server.cpp b/ACE/examples/IPC_SAP/SPIPE_SAP/server.cpp new file mode 100644 index 00000000000..bc582f177eb --- /dev/null +++ b/ACE/examples/IPC_SAP/SPIPE_SAP/server.cpp @@ -0,0 +1,124 @@ +// $Id$ + +#include "ace/OS_main.h" +#include "ace/SPIPE_Addr.h" +#include "ace/SPIPE_Acceptor.h" +#include "ace/Log_Msg.h" +#include "ace/OS_NS_stdio.h" +#include "ace/OS_NS_poll.h" +#include "ace/OS_NS_unistd.h" + +ACE_RCSID(SPIPE_SAP, server, "$Id$") + +#if defined (ACE_HAS_STREAM_PIPES) + +#include "shared.h" + +// Maximum per-process open I/O descriptors. +const int MAX_HANDLES = 200; + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + ACE_SPIPE_Acceptor peer_acceptor; + ACE_SPIPE_Stream new_stream; + struct pollfd poll_array[MAX_HANDLES]; + ACE_HANDLE handle; + + for (handle = 0; handle < MAX_HANDLES; handle++) + { + poll_array[handle].fd = -1; + poll_array[handle].events = POLLIN; + } + + if (argc > 1) + rendezvous = argv[1]; + + ACE_OS::fdetach (ACE_TEXT_ALWAYS_CHAR (rendezvous)); + ACE_SPIPE_Addr addr (rendezvous); + + ACE_HANDLE s_handle = peer_acceptor.open (addr); + + if (s_handle == -1) + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "peer_acceptor.open"), -1); + + poll_array[0].fd = s_handle; + + for (int width = 1;;) + { + // Block waiting for client I/O events (handle interrupts). + while (ACE_OS::poll (poll_array, width) == -1 && errno == EINTR) + continue; + + // Handle pending logging messages first (s_handle + 1 is + // guaranteed to be lowest client descriptor). + + for (handle = s_handle + 1; handle < width; handle++) + if (ACE_BIT_ENABLED (poll_array[handle].revents, POLLIN) + || ACE_BIT_ENABLED (poll_array[handle].revents, POLLHUP)) + { + char buf[BUFSIZ]; + ssize_t n = ACE_OS::read (handle, buf, sizeof buf); + + // recv will not block in this case! + if (n == -1) + ACE_DEBUG ((LM_DEBUG, "%p\n", "read failed")); + else if (n == 0) + { + // Handle client connection shutdown. + if (ACE_OS::close (poll_array[handle].fd) == -1) + ACE_DEBUG ((LM_DEBUG, "%p\n", "close")); + poll_array[handle].fd = -1; + + if (handle + 1 == width) + { + while (poll_array[handle].fd == -1) + handle--; + width = handle + 1; + } + } + else + ACE_DEBUG ((LM_DEBUG, "%*s\n", n, buf)); + } + + if (ACE_BIT_ENABLED (poll_array[0].revents, POLLIN)) + { + if (peer_acceptor.accept (new_stream) == -1) + ACE_DEBUG ((LM_DEBUG, "%p\n", "accept failed")); + + ACE_SPIPE_Addr client; + ACE_HANDLE n_handle = new_stream.get_handle (); + + if (new_stream.get_remote_addr (client) == -1) + ACE_DEBUG ((LM_DEBUG, "%p\n", + "get_remote_addr failed")); + + ACE_DEBUG ((LM_DEBUG, + "n_handle = %d, uid = %d, gid = %d\n", + n_handle, + client.user_id (), + client.group_id ())); + + int arg = RMSGN | RPROTDAT; + + if (ACE_OS::ioctl (n_handle, + I_SRDOPT, (void *) arg) == -1) + ACE_DEBUG ((LM_DEBUG, "%p\n", "ioctl failed")); + + poll_array[n_handle].fd = n_handle; + + if (n_handle >= width) + width = n_handle + 1; + } + } + + ACE_NOTREACHED (return 0;) +} +#else +#include <stdio.h> +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_OS::fprintf (stderr, "This feature is not supported\n"); + return 0; +} +#endif /* ACE_HAS_STREAM_PIPES */ diff --git a/ACE/examples/IPC_SAP/SPIPE_SAP/shared.h b/ACE/examples/IPC_SAP/SPIPE_SAP/shared.h new file mode 100644 index 00000000000..47f2e8db6bc --- /dev/null +++ b/ACE/examples/IPC_SAP/SPIPE_SAP/shared.h @@ -0,0 +1,10 @@ +/* -*- C++ -*- */ +// $Id$ + +#include "ace/config-all.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +static const ACE_TCHAR *rendezvous = ACE_DEFAULT_RENDEZVOUS; diff --git a/ACE/examples/IPC_SAP/SSL_SAP/Makefile.am b/ACE/examples/IPC_SAP/SSL_SAP/Makefile.am new file mode 100644 index 00000000000..3df4d11db5b --- /dev/null +++ b/ACE/examples/IPC_SAP/SSL_SAP/Makefile.am @@ -0,0 +1,196 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +ACE_BUILDDIR = $(top_builddir) +ACE_ROOT = $(top_srcdir) + +noinst_PROGRAMS = + +## Makefile.SSL_SAP_Client.am + +if BUILD_SSL +if !BUILD_ACE_FOR_TAO + +noinst_PROGRAMS += client + +client_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) \ + -DACE_HAS_SSL=1 \ + @ACE_TLS_CPPFLAGS@ + +client_SOURCES = \ + SSL-client.cpp \ + SSL-client.h + +client_LDFLAGS = \ + @ACE_TLS_LDFLAGS@ + +client_LDADD = \ + $(ACE_BUILDDIR)/ace/SSL/libACE_SSL.la \ + $(ACE_BUILDDIR)/ace/libACE.la \ + @ACE_TLS_LIBS@ + +endif !BUILD_ACE_FOR_TAO +endif BUILD_SSL + +## Makefile.SSL_SAP_Client_Simple.am + +if BUILD_SSL +if !BUILD_ACE_FOR_TAO + +noinst_PROGRAMS += client-simple + +client_simple_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) \ + -DACE_HAS_SSL=1 \ + @ACE_TLS_CPPFLAGS@ + +client_simple_SOURCES = \ + SSL-client-simple.cpp \ + SSL-client-simple.h + +client_simple_LDFLAGS = \ + @ACE_TLS_LDFLAGS@ + +client_simple_LDADD = \ + $(ACE_BUILDDIR)/ace/SSL/libACE_SSL.la \ + $(ACE_BUILDDIR)/ace/libACE.la \ + @ACE_TLS_LIBS@ + +endif !BUILD_ACE_FOR_TAO +endif BUILD_SSL + +## Makefile.SSL_SAP_Server.am + +if BUILD_SSL +if !BUILD_ACE_FOR_TAO + +noinst_PROGRAMS += server + +server_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) \ + -DACE_HAS_SSL=1 \ + @ACE_TLS_CPPFLAGS@ + +server_SOURCES = \ + SSL-server.cpp \ + SSL-client-simple.h \ + SSL-client.h \ + SSL-server-fancy.h + +server_LDFLAGS = \ + @ACE_TLS_LDFLAGS@ + +server_LDADD = \ + $(ACE_BUILDDIR)/ace/SSL/libACE_SSL.la \ + $(ACE_BUILDDIR)/ace/libACE.la \ + @ACE_TLS_LIBS@ + +endif !BUILD_ACE_FOR_TAO +endif BUILD_SSL + +## Makefile.SSL_SAP_Server_Fancy.am + +if BUILD_SSL +if !BUILD_ACE_FOR_TAO + +noinst_PROGRAMS += server-fancy + +server_fancy_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) \ + -DACE_HAS_SSL=1 \ + @ACE_TLS_CPPFLAGS@ + +server_fancy_SOURCES = \ + SSL-server-fancy.cpp \ + SSL-server-fancy.h + +server_fancy_LDFLAGS = \ + @ACE_TLS_LDFLAGS@ + +server_fancy_LDADD = \ + $(ACE_BUILDDIR)/ace/SSL/libACE_SSL.la \ + $(ACE_BUILDDIR)/ace/libACE.la \ + @ACE_TLS_LIBS@ + +endif !BUILD_ACE_FOR_TAO +endif BUILD_SSL + +## Makefile.SSL_SAP_Server_Poll.am + +if BUILD_SSL +if !BUILD_ACE_FOR_TAO + +noinst_PROGRAMS += server-poll + +server_poll_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) \ + -DACE_HAS_SSL=1 \ + @ACE_TLS_CPPFLAGS@ + +server_poll_SOURCES = \ + SSL-server-poll.cpp \ + SSL-client-simple.h \ + SSL-client.h \ + SSL-server-fancy.h + +server_poll_LDFLAGS = \ + @ACE_TLS_LDFLAGS@ + +server_poll_LDADD = \ + $(ACE_BUILDDIR)/ace/SSL/libACE_SSL.la \ + $(ACE_BUILDDIR)/ace/libACE.la \ + @ACE_TLS_LIBS@ + +endif !BUILD_ACE_FOR_TAO +endif BUILD_SSL + +## Makefile.SSL_SAP_Server_Simple.am + +if BUILD_SSL +if !BUILD_ACE_FOR_TAO + +noinst_PROGRAMS += server-simple + +server_simple_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) \ + -DACE_HAS_SSL=1 \ + @ACE_TLS_CPPFLAGS@ + +server_simple_SOURCES = \ + SSL-server-simple.cpp \ + SSL-client-simple.h \ + SSL-client.h \ + SSL-server-fancy.h + +server_simple_LDFLAGS = \ + @ACE_TLS_LDFLAGS@ + +server_simple_LDADD = \ + $(ACE_BUILDDIR)/ace/SSL/libACE_SSL.la \ + $(ACE_BUILDDIR)/ace/libACE.la \ + @ACE_TLS_LIBS@ + +endif !BUILD_ACE_FOR_TAO +endif BUILD_SSL + +## Clean up template repositories, etc. +clean-local: + -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.* + -rm -f gcctemp.c gcctemp so_locations *.ics + -rm -rf cxx_repository ptrepository ti_files + -rm -rf templateregistry ir.out + -rm -rf ptrepository SunWS_cache Templates.DB diff --git a/ACE/examples/IPC_SAP/SSL_SAP/README b/ACE/examples/IPC_SAP/SSL_SAP/README new file mode 100644 index 00000000000..43f4640e75a --- /dev/null +++ b/ACE/examples/IPC_SAP/SSL_SAP/README @@ -0,0 +1,17 @@ +# $Id$ + +This directory contains groups of client and server test programs that +exercise the various C++ wrappers for SSL sockets. In general, the +test programs do more or less the same thing -- the client establishes +a connection with the server and then transfers data to the server, +which keeps printing the data until EOF is reached (e.g., user types +^D). + +Unless noted differently, the server is implemented as an "iterative +server," i.e., it only deals with one client at a time. The following +describes each set of tests in more detail: + + . SSL-{client,server}.cpp -- This test allows you to test + oneway and twoway socket communication latency and + throughput over SSL between two processes on the same + machine or on different machines. diff --git a/ACE/examples/IPC_SAP/SSL_SAP/SSL-client-simple.cpp b/ACE/examples/IPC_SAP/SSL_SAP/SSL-client-simple.cpp new file mode 100644 index 00000000000..31f76d4826a --- /dev/null +++ b/ACE/examples/IPC_SAP/SSL_SAP/SSL-client-simple.cpp @@ -0,0 +1,377 @@ +// $Id$ + +// This tests the features of the <ACE_SSL_SOCK_Connector> and +// <ACE_SSL_SOCK_Stream> classes. In addition, it can be used to test the +// oneway and twoway latency and throughput at the socket-level. This +// is useful as a baseline to compare against ORB-level performance +// for the same types of data. + +#include "ace/OS_NS_string.h" +#include "ace/OS_NS_unistd.h" +#include "ace/INET_Addr.h" +#include "ace/Log_Msg.h" +#include "ace/Singleton.h" +#include "ace/Get_Opt.h" +#include "ace/High_Res_Timer.h" +#include "ace/Null_Mutex.h" + +#include "ace/SSL/SSL_SOCK_Connector.h" + +#include "SSL-client-simple.h" + +ACE_RCSID (SSL_SAP, + SSL_client_simple, + "$Id$") + + +Options::Options (void) + : host_ (ACE_DEFAULT_SERVER_HOST), + port_ (ACE_DEFAULT_SERVER_PORT), + sleep_time_ (0, 0), // By default, don't sleep between calls. + message_len_ (0), + message_buf_ (0), + io_source_ (ACE_INVALID_HANDLE), // Defaults to using the generator. + iterations_ (10000), + oneway_ (1) // Make oneway calls the default. +{ + ACE_OS::strcpy (quit_string_, "q"); +} + +Options::~Options (void) +{ + delete [] this->message_buf_; +} + +// Options Singleton. +typedef ACE_Singleton<Options, ACE_Null_Mutex> OPTIONS; + +int +Options::init (void) +{ + // Check for default case. + if (this->message_len_ == 0) + this->message_len_ = ACE_OS::strlen ("TAO"); + + this->message_len_ += sizeof (ACE_UINT32); + + ACE_NEW_RETURN (this->message_buf_, + char[this->message_len_], + -1); + + // Copy the length into the beginning of the message. + ACE_UINT32 length = ntohl (this->message_len_); + ACE_OS::memcpy ((void *) this->message_buf_, + (void *) &length, + sizeof length); + + ACE_OS::memset ((void *) (this->message_buf_ + sizeof (ACE_UINT32)), + 'a', + this->message_len_ - sizeof (ACE_UINT32)); + + return 0; +} + +size_t +Options::message_len (void) const +{ + return this->message_len_; +} + +const void * +Options::message_buf (void) const +{ + return this->message_buf_; +} + +ssize_t +Options::read (void *buf, size_t len, size_t &iteration) +{ + ACE_UNUSED_ARG (len); + + if (this->io_source_ == ACE_STDIN) + return ACE_OS::read (ACE_STDIN, buf, len); + else if (iteration >= this->iterations_) + return 0; + else + { + ACE_OS::memcpy (buf, + this->message_buf (), + len); + iteration++; + return len; + } +} + +int +Options::parse_args (int argc, ACE_TCHAR *argv[]) +{ + ACE_Get_Opt getopt (argc, argv, ACE_TEXT ("2h:i:m:p:q:sT:"), 1); + + for (int c; (c = getopt ()) != -1; ) + switch (c) + { + case '2': // Disable the oneway client. + this->oneway_ = 0; + break; + case 'h': + this->host_ = getopt.opt_arg (); + break; + case 'i': + this->iterations_ = ACE_OS::atoi (getopt.opt_arg ()); + break; + case 'm': + this->message_len_ = ACE_OS::atoi (getopt.opt_arg ()); + break; + case 'p': + this->port_ = ACE_OS::atoi (getopt.opt_arg ()); + break; + case 'q': + ACE_OS::strncpy (this->quit_string_, + ACE_TEXT_ALWAYS_CHAR (getopt.opt_arg ()), + QUIT_STRING_SIZE); + break; + case 's': + this->io_source_ = ACE_STDIN; + break; + case 'T': + this->sleep_time_.set (0, ACE_OS::atoi (getopt.opt_arg ())); + break; + default: + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("(%P|%t) usage: %n [-2] [-h <host>] ") + ACE_TEXT ("[-i iterations] [-m message-size] ") + ACE_TEXT ("[-p <port>] [-q <quit string>] ") + ACE_TEXT ("[-s] [-T <sleep_time>]\n")), + -1); + } + + return this->init (); +} + +u_short +Options::port (void) const +{ + return this->port_; +} + +const ACE_TCHAR * +Options::host (void) const +{ + return this->host_; +} + +const char * +Options::quit_string (void) const +{ + return this->quit_string_; +} + +const ACE_Time_Value & +Options::sleep_time (void) const +{ + return this->sleep_time_; +} + +char * +Options::shared_client_test (u_short port, + ACE_SSL_SOCK_Stream &cli_stream) +{ + ACE_INET_Addr remote_addr (port, this->host_); + + ACE_SSL_SOCK_Connector con; + + if (con.connect (cli_stream, + remote_addr) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("(%P|%t) %p\n"), + ACE_TEXT ("connection failed")), + 0); + else + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) connected to %C at port %d\n"), + remote_addr.get_host_name (), + remote_addr.get_port_number ())); + + char *buf; + ACE_NEW_RETURN (buf, + char[this->message_len ()], + 0); + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) waiting...\n"))); + + return buf; +} +// Static function entry point to the oneway client service. + +void +Options::oneway_client_test (void) +{ + ACE_SSL_SOCK_Stream cli_stream; + + // Add 1 to the port to trigger the oneway test! + char *request = this->shared_client_test (this->port () + 1, + cli_stream); + if (request == 0) + return; + + // This variable is allocated off the stack to obviate the need for + // locking. + size_t iteration = 0; + + // Keep track of return value. + int result = 0; + ACE_INT32 len = this->message_len (); + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) starting oneway transmission\n"))); + + // Perform oneway transmission of data to server (correctly handles + // "incomplete writes"). + + for (ssize_t r_bytes; + (r_bytes = this->read (request, len, iteration)) > 0; + // Transmit at the proper rate. + ACE_OS::sleep (this->sleep_time ())) + if (ACE_OS::memcmp (request, + this->quit_string (), + ACE_OS::strlen (this->quit_string ())) == 0) + break; + else if (cli_stream.send_n (request, r_bytes) == -1) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("(%P|%t) %p\n"), + ACE_TEXT ("send_n"))); + result = -1; + break; + } + + // Close the connection. + cli_stream.close (); + + delete [] request; +} + +// Static function entry point to the twoway client service. + +void +Options::twoway_client_test (void) +{ + ACE_SSL_SOCK_Stream cli_stream; + + char *request = this->shared_client_test (this->port (), + cli_stream); + if (request == 0) + return; + + // This variable is allocated off the stack to obviate the need for + // locking. + size_t iteration = 0; + + // Keep track of return value. + int result = 0; + + // Timer business. + ACE_High_Res_Timer timer; + + ACE_INT32 len = this->message_len (); + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) starting twoway transmission\n"))); + + // Perform twoway transmission of data to server (correctly handles + // "incomplete writes"). + + for (ssize_t r_bytes; + (r_bytes = this->read (request, len, iteration)) > 0; + // Transmit at the proper rate. + ACE_OS::sleep (this->sleep_time ())) + if (ACE_OS::memcmp (request, + this->quit_string (), + ACE_OS::strlen (this->quit_string ())) == 0) + break; + + // Transmit <request> to the server. + else + { + // Note that we use the incremental feature of the + // <ACE_High_Res_Timer> so that we don't get "charged" for the + // <ACE_OS::sleep> used to control the rate at which requests + // are sent. + timer.start_incr (); + + if (cli_stream.send_n (request, r_bytes) == -1) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("(%P|%t) %p\n"), + ACE_TEXT ("send_n"))); + result = -1; + break; + } + // Receive the reply from the server. Normally, it just sends + // back 24 bytes, which is typical for an IIOP reply. + else if (cli_stream.recv (request, r_bytes) <= 0) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("(%P|%t) %p\n"), + ACE_TEXT ("recv"))); + result = -1; + break; + } + + timer.stop_incr (); + } + + ACE_Time_Value tv; + + timer.elapsed_time_incr (tv); + double real_time = tv.sec () * ACE_ONE_SECOND_IN_USECS + tv.usec (); + double messages_per_sec = iteration * double (ACE_ONE_SECOND_IN_USECS) / real_time; + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%t) messages = %d\n(%t) usec-per-message = %f\n(%t) messages-per-second = %0.00f\n"), + iteration, + real_time / double (iteration), + messages_per_sec < 0 ? 0 : messages_per_sec)); + + // Close the connection. + cli_stream.close (); + + delete [] request; +} + +void +Options::run (void) +{ + if (this->oneway_ == 0) + this->twoway_client_test (); + else + this->oneway_client_test (); +} + +static int +run_client (void) +{ + // Raise the socket handle limit to the maximum. + ACE::set_handle_limit (); + + OPTIONS::instance ()->run (); + + return 0; +} + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + // Initialize the logger. + ACE_LOG_MSG->open (argv[0]); + + if (OPTIONS::instance ()->parse_args (argc, argv) == -1) + return -1; + + // Run the client + run_client (); + + return 0; +} + diff --git a/ACE/examples/IPC_SAP/SSL_SAP/SSL-client-simple.h b/ACE/examples/IPC_SAP/SSL_SAP/SSL-client-simple.h new file mode 100644 index 00000000000..4ec6b815a4c --- /dev/null +++ b/ACE/examples/IPC_SAP/SSL_SAP/SSL-client-simple.h @@ -0,0 +1,98 @@ +// -*- C++ -*- +// $Id$ + +// This file defines the Options class for SSL-client-simple. IBM C++ +// compiler's template auto-instantiator needs this in a separate file. + +#ifndef ACE_SSL_CLIENT_SIMPLE_H +#define ACE_SSL_CLIENT_SIMPLE_H + +#include "ace/SSL/SSL_SOCK_Stream.h" +#include "ace/Time_Value.h" + +class Options + // = TITLE + // Define the options for this test. +{ +public: + Options (void); + // Constructor. + + ~Options (void); + // Destructor. + + int parse_args (int argc, ACE_TCHAR *argv[]); + // Parse the command-line arguments. + + const ACE_Time_Value &sleep_time (void) const; + // Return the amount of time to sleep in order to implement the + // proper transmission rates. + + u_short port (void) const; + // Port of the server. + + const ACE_TCHAR *host (void) const; + // Host of the server. + + const char *quit_string (void) const; + // String that shuts down the client/server. + + ssize_t read (void *buf, size_t len, size_t &iterations); + // Read from the appropriate location. + + size_t message_len (void) const; + // Returns the length of the message to send. + + const void *message_buf (void) const; + // Returns a pointer to the message. + + void run (void); + // Run the test + +private: + int init (void); + // Initialize the message we're sending to the user and set up the + // barrier. + + char *shared_client_test (u_short port, + ACE_SSL_SOCK_Stream &cli_stream); + // Performs the shared behavior of the oneway and twoway client + // tests. + + void twoway_client_test (void); + // Performs the twoway test. + + void oneway_client_test (void); + // Performs the oneway test. + + const ACE_TCHAR *host_; + // Host of the server. + + u_short port_; + // Port of the server. + + ACE_Time_Value sleep_time_; + // Sleep_Time value. + + enum {QUIT_STRING_SIZE = 128}; + char quit_string_[QUIT_STRING_SIZE]; + // String that shuts down the client/server. + + size_t message_len_; + // Size of the message we send to the server. + + char *message_buf_; + // Pointer to the message we send to the server. + + ACE_HANDLE io_source_; + // Are we reading I/O from ACE_STDIN or from our generator? + + size_t iterations_; + // Number of iterations. + + char oneway_; + // Are we running oneway or twoway? + +}; + +#endif /* ACE_SSL_CLIENT_SIMPLE_H */ diff --git a/ACE/examples/IPC_SAP/SSL_SAP/SSL-client.cpp b/ACE/examples/IPC_SAP/SSL_SAP/SSL-client.cpp new file mode 100644 index 00000000000..539b97c931c --- /dev/null +++ b/ACE/examples/IPC_SAP/SSL_SAP/SSL-client.cpp @@ -0,0 +1,418 @@ +// $Id$ + +// This tests the features of the <ACE_SSL_SOCK_Connector> and +// <ACE_SSL_SOCK_Stream> classes. In addition, it can be used to test the +// oneway and twoway latency and throughput at the socket-level. This +// is useful as a baseline to compare against ORB-level performance +// for the same types of data. + +#include "ace/OS_NS_string.h" +#include "ace/OS_NS_unistd.h" +#include "ace/INET_Addr.h" +#include "ace/Thread_Manager.h" +#include "ace/Singleton.h" +#include "ace/Get_Opt.h" +#include "ace/High_Res_Timer.h" + +#include "ace/SSL/SSL_SOCK_Connector.h" + +#include "SSL-client.h" + +ACE_RCSID(SSL_SAP, SSL_client, "$Id$") + +Options::Options (void) + : host_ (ACE_DEFAULT_SERVER_HOST), + port_ (ACE_DEFAULT_SERVER_PORT), + sleep_time_ (0, 0), // By default, don't sleep between calls. + threads_ (10), + message_len_ (0), + message_buf_ (0), + io_source_ (ACE_INVALID_HANDLE), // Defaults to using the generator. + iterations_ (10000), + oneway_ (1) // Make oneway calls the default. +#if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0) + , barrier_ (0) +#endif /* ACE_MT_SAFE */ +{ + ACE_OS::strcpy (quit_string_, "q"); +} + +Options::~Options (void) +{ + ACE_MT (delete this->barrier_); + delete [] this->message_buf_; +} + +// Options Singleton. +typedef ACE_Singleton<Options, ACE_SYNCH_RECURSIVE_MUTEX> OPTIONS; + +int +Options::init (void) +{ + // Check for default case. + if (this->message_len_ == 0) + this->message_len_ = ACE_OS::strlen ("TAO"); + + this->message_len_ += sizeof (ACE_UINT32); + + ACE_NEW_RETURN (this->message_buf_, + char[this->message_len_], + -1); + + // Copy the length into the beginning of the message. + ACE_UINT32 length = ntohl (this->message_len_); + ACE_OS::memcpy ((void *) this->message_buf_, + (void *) &length, + sizeof length); + + ACE_OS::memset ((void *) (this->message_buf_ + sizeof (ACE_UINT32)), + 'a', + this->message_len_ - sizeof (ACE_UINT32)); + + // Allocate the barrier with the correct count. + ACE_MT (ACE_NEW_RETURN (this->barrier_, + ACE_Barrier (this->threads_), + -1)); + return 0; +} + +size_t +Options::message_len (void) const +{ + return this->message_len_; +} + +const void * +Options::message_buf (void) const +{ + return this->message_buf_; +} + +ssize_t +Options::read (void *buf, size_t len, size_t &iteration) +{ + ACE_UNUSED_ARG (len); + + if (this->io_source_ == ACE_STDIN) + return ACE_OS::read (ACE_STDIN, buf, len); + else if (iteration >= this->iterations_) + return 0; + else + { + ACE_OS::memcpy (buf, + this->message_buf (), + len); + iteration++; + return len; + } +} + +int +Options::parse_args (int argc, ACE_TCHAR *argv[]) +{ + ACE_Get_Opt getopt (argc, argv, ACE_TEXT ("2h:i:m:p:q:st:T:"), 1); + + for (int c; (c = getopt ()) != -1; ) + switch (c) + { + case '2': // Disable the oneway client. + this->oneway_ = 0; + break; + case 'h': + this->host_ = getopt.opt_arg (); + break; + case 'i': + this->iterations_ = ACE_OS::atoi (getopt.opt_arg ()); + break; + case 'm': + this->message_len_ = ACE_OS::atoi (getopt.opt_arg ()); + break; + case 'p': + this->port_ = ACE_OS::atoi (getopt.opt_arg ()); + break; + case 'q': + ACE_OS::strncpy (this->quit_string_, + ACE_TEXT_ALWAYS_CHAR (getopt.opt_arg ()), + QUIT_STRING_SIZE); + break; + case 's': + this->io_source_ = ACE_STDIN; + break; + case 't': + this->threads_ = (size_t) ACE_OS::atoi (getopt.opt_arg ()); + break; + case 'T': + this->sleep_time_.set (0, ACE_OS::atoi (getopt.opt_arg ())); + break; + default: + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("(%P|%t) usage: %n [-2] [-h <host>] ") + ACE_TEXT ("[-i iterations] [-m message-size] ") + ACE_TEXT ("[-p <port>] [-q <quit string>] ") + ACE_TEXT ("[-s] [-t <threads>] [-T <sleep_time>]\n")), + -1); + } + + return this->init (); +} + +u_short +Options::port (void) const +{ + return this->port_; +} + +const ACE_TCHAR * +Options::host (void) const +{ + return this->host_; +} + +const char * +Options::quit_string (void) const +{ + return this->quit_string_; +} + +size_t +Options::threads (void) const +{ + return this->threads_; +} + +const ACE_Time_Value & +Options::sleep_time (void) const +{ + return this->sleep_time_; +} + +char * +Options::shared_client_test (u_short port, + ACE_SSL_SOCK_Stream &cli_stream) +{ + ACE_INET_Addr remote_addr (port, this->host_); + + ACE_SSL_SOCK_Connector con; + + if (con.connect (cli_stream, + remote_addr) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("(%P|%t) %p\n"), + ACE_TEXT ("connection failed")), + 0); + else + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) connected to %C at port %d\n"), + remote_addr.get_host_name (), + remote_addr.get_port_number ())); + + // Allocate the transmit buffer. + char *buf; + ACE_NEW_RETURN (buf, + char[this->message_len ()], + 0); + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) waiting...\n"))); + + // Wait for all other threads to finish initialization. + ACE_MT (this->barrier_->wait ()); + return buf; +} +// Static function entry point to the oneway client service. + +void * +Options::oneway_client_test (void *) +{ + Options *options = OPTIONS::instance (); + ACE_SSL_SOCK_Stream cli_stream; + + // Add 1 to the port to trigger the oneway test! + char *request = options->shared_client_test (options->port () + 1, + cli_stream); + if (request == 0) + return 0; + + // This variable is allocated off the stack to obviate the need for + // locking. + size_t iteration = 0; + + // Keep track of return value. + size_t result = 0; + ACE_INT32 len = options->message_len (); + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) starting oneway transmission\n"))); + + // Perform oneway transmission of data to server (correctly handles + // "incomplete writes"). + + for (ssize_t r_bytes; + (r_bytes = options->read (request, len, iteration)) > 0; + // Transmit at the proper rate. + ACE_OS::sleep (options->sleep_time ())) + if (ACE_OS::memcmp (request, + options->quit_string (), + ACE_OS::strlen (options->quit_string ())) == 0) + break; + else if (cli_stream.send_n (request, r_bytes) == -1) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("(%P|%t) %p\n"), + ACE_TEXT ("send_n"))); + result = size_t (-1); + break; + } + + // Close the connection. + cli_stream.close (); + + delete [] request; + return (void *) result; +} + +// Static function entry point to the twoway client service. + +void * +Options::twoway_client_test (void *) +{ + Options *options = OPTIONS::instance (); + + ACE_SSL_SOCK_Stream cli_stream; + + char *request = options->shared_client_test (options->port (), + cli_stream); + if (request == 0) + return 0; + + // This variable is allocated off the stack to obviate the need for + // locking. + size_t iteration = 0; + + // Keep track of return value. + size_t result = 0; + + // Timer business. + ACE_High_Res_Timer timer; + + ACE_INT32 len = options->message_len (); + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) starting twoway transmission\n"))); + + // Perform twoway transmission of data to server (correctly handles + // "incomplete writes"). + + for (ssize_t r_bytes; + (r_bytes = options->read (request, len, iteration)) > 0; + // Transmit at the proper rate. + ACE_OS::sleep (options->sleep_time ())) + if (ACE_OS::memcmp (request, + options->quit_string (), + ACE_OS::strlen (options->quit_string ())) == 0) + break; + + // Transmit <request> to the server. + else + { + // Note that we use the incremental feature of the + // <ACE_High_Res_Timer> so that we don't get "charged" for the + // <ACE_OS::sleep> used to control the rate at which requests + // are sent. + timer.start_incr (); + + if (cli_stream.send_n (request, r_bytes) == -1) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("(%P|%t) %p\n"), + ACE_TEXT ("send_n"))); + result = size_t (-1); + break; + } + // Receive the reply from the server. Normally, it just sends + // back 24 bytes, which is typical for an IIOP reply. + else if (cli_stream.recv (request, r_bytes) <= 0) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("(%P|%t) %p\n"), + ACE_TEXT ("recv"))); + result = size_t (-1); + break; + } + + timer.stop_incr (); + } + + ACE_Time_Value tv; + + timer.elapsed_time_incr (tv); + double real_time = tv.sec () * ACE_ONE_SECOND_IN_USECS + tv.usec (); + double messages_per_sec = + iteration * double (ACE_ONE_SECOND_IN_USECS) / real_time; + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%t) messages = %d\n") + ACE_TEXT ("(%t) usec-per-message = %f\n") + ACE_TEXT ("(%t) messages-per-second = %0.00f\n"), + iteration, + real_time / double (iteration), + messages_per_sec < 0 ? 0 : messages_per_sec)); + + // Close the connection. + cli_stream.close (); + + delete [] request; + return (void *) result; +} + +ACE_THR_FUNC +Options::thr_func (void) +{ + if (this->oneway_ == 0) + return ACE_THR_FUNC (&Options::twoway_client_test); + else + return ACE_THR_FUNC (&Options::oneway_client_test); +} + +static int +run_client (void) +{ + // Raise the socket handle limit to the maximum. + ACE::set_handle_limit (); + +#if defined (ACE_HAS_THREADS) + if (ACE_Thread_Manager::instance ()->spawn_n ( + OPTIONS::instance ()->threads (), + OPTIONS::instance ()->thr_func ()) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("(%P|%t) %p\n"), + ACE_TEXT ("spawn_n")), + 1); + else + ACE_Thread_Manager::instance ()->wait (); +#else + *(OPTIONS::instance ()->thr_func) (); +#endif /* ACE_HAS_THREADS */ + return 0; +} + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + ACE_SSL_Context *context = ACE_SSL_Context::instance (); + + context->certificate ("./dummy.pem", SSL_FILETYPE_PEM); + context->private_key ("./key.pem", SSL_FILETYPE_PEM); + + // Initialize the logger. + ACE_LOG_MSG->open (argv[0]); + + if (OPTIONS::instance ()->parse_args (argc, argv) == -1) + return -1; + + // Run the client + run_client (); + + return 0; +} + diff --git a/ACE/examples/IPC_SAP/SSL_SAP/SSL-client.h b/ACE/examples/IPC_SAP/SSL_SAP/SSL-client.h new file mode 100644 index 00000000000..af081004368 --- /dev/null +++ b/ACE/examples/IPC_SAP/SSL_SAP/SSL-client.h @@ -0,0 +1,111 @@ +// -*- C++ -*- +// $Id$ + +// This file defines the Options class for SSL-client. IBM C++ compiler'd +// template auto-instantiator needs this in a separate file. + +#ifndef __ACE_SSL_CLIENT_H +#define __ACE_SSL_CLIENT_H + +#include "ace/Barrier.h" +#include "ace/Time_Value.h" + +#include "ace/SSL/SSL_SOCK_Stream.h" + +class Options + // = TITLE + // Define the options for this test. +{ +public: + Options (void); + // Constructor. + + ~Options (void); + // Destructor. + + int parse_args (int argc, ACE_TCHAR *argv[]); + // Parse the command-line arguments. + + const ACE_Time_Value &sleep_time (void) const; + // Return the amount of time to sleep in order to implement the + // proper transmission rates. + + u_short port (void) const; + // Port of the server. + + const ACE_TCHAR *host (void) const; + // Host of the server. + + size_t threads (void) const; + // Number of threads. + + const char *quit_string (void) const; + // String that shuts down the client/server. + + ssize_t read (void *buf, size_t len, size_t &iterations); + // Read from the appropriate location. + + size_t message_len (void) const; + // Returns the length of the message to send. + + const void *message_buf (void) const; + // Returns a pointer to the message. + + ACE_THR_FUNC thr_func (void); + // Returns a pointer to the entry point into the thread that runs + // the client test function. + +private: + int init (void); + // Initialize the message we're sending to the user and set up the + // barrier. + + char *shared_client_test (u_short port, + ACE_SSL_SOCK_Stream &cli_stream); + // Performs the shared behavior of the oneway and twoway client + // tests. + + static void *twoway_client_test (void *); + // Performs the twoway test. + + static void *oneway_client_test (void *); + // Performs the oneway test. + + const ACE_TCHAR *host_; + // Host of the server. + + u_short port_; + // Port of the server. + + ACE_Time_Value sleep_time_; + // Sleep_Time value. + + size_t threads_; + // Number of threads. + + enum {QUIT_STRING_SIZE = 128}; + char quit_string_[QUIT_STRING_SIZE]; + // String that shuts down the client/server. + + size_t message_len_; + // Size of the message we send to the server. + + char *message_buf_; + // Pointer to the message we send to the server. + + ACE_HANDLE io_source_; + // Are we reading I/O from ACE_STDIN or from our generator? + + size_t iterations_; + // Number of iterations. + + char oneway_; + // Are we running oneway or twoway? + + // Please leave the ; inside the parenthesis to avoid Green Hills + // (and probably other) compiler warning about extra ;. + ACE_MT (ACE_Barrier *barrier_;) + // Barrier used to synchronize the start of all the threads. +}; + +#endif /* __ACE_SSL_CLIENT_H */ diff --git a/ACE/examples/IPC_SAP/SSL_SAP/SSL-server-fancy.cpp b/ACE/examples/IPC_SAP/SSL_SAP/SSL-server-fancy.cpp new file mode 100644 index 00000000000..e2d2c8ad0c1 --- /dev/null +++ b/ACE/examples/IPC_SAP/SSL_SAP/SSL-server-fancy.cpp @@ -0,0 +1,606 @@ +// $Id$ + +// This example tests the features of the <ACE_SSL_SOCK_Acceptor>, +// <ACE_SSL_SOCK_Stream>, and <ACE_Svc_Handler> classes. If the platform +// supports threads it uses a thread-per-connection concurrency model. +// Otherwise, it uses a single-threaded iterative server model. + +#include "ace/Svc_Handler.h" +#include "ace/Singleton.h" +#include "ace/Profile_Timer.h" +#include "ace/Get_Opt.h" +#include "ace/OS_NS_sys_select.h" + +#include "ace/SSL/SSL_SOCK_Acceptor.h" + +#include "SSL-server-fancy.h" + +ACE_RCSID (SSL_SAP, + SSL_server_fancy, + "$Id$") + +// Forward declaration. +class Handler; + +class Handler_Factory +{ + // = TITLE + // Creates the oneway or twoway handlers. +public: + Handler_Factory (void); + // Constructor. + + ~Handler_Factory (void); + // Destructor. + + int handle_events (void); + // Run the main event loop. + +private: + int init_acceptors (void); + // Initialize the acceptors. + + int create_handler (ACE_SSL_SOCK_Acceptor &acceptor, + Handler *(*handler_factory) (ACE_SSL_SOCK_Stream *), + const char *handler_type); + // Factory that creates the right kind of <Handler>. + + // = Factory functions. + + static Handler *make_twoway_handler (ACE_SSL_SOCK_Stream *); + // Create a twoway handler. + + static Handler *make_oneway_handler (ACE_SSL_SOCK_Stream *); + // Create a oneway handler. + + ACE_SSL_SOCK_Acceptor twoway_acceptor_; + // Twoway acceptor factory. + + ACE_SSL_SOCK_Acceptor oneway_acceptor_; + // Oneway acceptor factory. +}; + +class Handler : public ACE_Svc_Handler<ACE_SSL_SOCK_STREAM, ACE_NULL_SYNCH> +{ + // = TITLE + // Base class for the oneway and twoway handlers. + + friend class Handler_Factory; + // The factory has special permission. (to access svc ()). + +public: + virtual int open (void * = 0); + // Generic initialization method. + + virtual int close (u_long); + // Close down and delete this. + +protected: + + Handler (ACE_SSL_SOCK_Stream *ssl_stream); + // Constructor. + + int parse_header_and_allocate_buffer (char *&buf, + ACE_INT32 *len); + // Implement the generic code that's called from any of the subclass + // <run> methods to get the header and the buffer to read the data. + // This method factors out common code. + + virtual int run (void) = 0; + // Hook method called by the <svc> template method to do the actual + // protocol. Must be overridden by the subclass. + + virtual int svc (void); + // Template method entry point into the handler task. + + virtual void print_results (void); + // Print the results. + + size_t total_bytes_; + // Total number of bytes received. + + size_t message_count_; + // Number of messages received. + + ACE_Profile_Timer timer_; + // Keeps track of how much time we're using. + + ACE_SSL_SOCK_Stream *ssl_stream_; + //keep state information for a ssl_stream. +}; + +class Twoway_Handler : public Handler +{ + // = TITLE + // Performs the twoway protocol. +public: + + Twoway_Handler (ACE_SSL_SOCK_Stream *ssl_stream); + // Constructor. + +private: + + virtual int run (void); + // Template Method hook called by <svc>. + +}; + +class Oneway_Handler : public Handler +{ + // = TITLE +public: + Oneway_Handler (ACE_SSL_SOCK_Stream *ssl_stream); + // Constructor. + +private: + virtual int run (void); + // Template Method hook called by <svc>. + + virtual void print_results (void); + // Print the results. +}; + +u_short +Options::port (void) const +{ + return this->port_; +} + +int +Options::verbose (void) const +{ + return this->verbose_; +} + +int +Options::reply_message_len (void) const +{ + return this->reply_message_len_; +} + +Options::~Options (void) +{ +} + +Options::Options (void) + : verbose_ (0), + port_ (ACE_DEFAULT_SERVER_PORT), + reply_message_len_ (24) // Default to the approximate size of an + // GIOP reply message. +{ +} + +int +Options::parse_args (int argc, ACE_TCHAR *argv[]) +{ + ACE_Get_Opt getopt (argc, argv, ACE_TEXT ("p:r:v"), 1); + + for (int c; (c = getopt ()) != -1; ) + switch (c) + { + case 'p': + this->port_ = ACE_OS::atoi (getopt.opt_arg ()); + break; + case 'r': + this->reply_message_len_ = ACE_OS::atoi (getopt.opt_arg ()); + break; + case 'v': + this->verbose_ = 1; + break; + default: + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("(%P|%t) usage: %n [-p <port>] [-v]")), + -1); + } + + return 0; +} + +// Options Singleton. +typedef ACE_Singleton<Options, ACE_SYNCH_RECURSIVE_MUTEX> OPTIONS; + +Handler::Handler (ACE_SSL_SOCK_Stream *ssl_stream) + : total_bytes_ (0), + message_count_ (0), + ssl_stream_ (ssl_stream) + +{ +} + +int +Handler::open (void *) +{ + ACE_INET_Addr cli_addr; + + // Make sure we're not in non-blocking mode. + if (this->ssl_stream_-> disable (ACE_NONBLOCK) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("disable")), + 0); + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) client %C connected from %d \n"), + cli_addr.get_host_name (), + cli_addr.get_port_number ())); + + return 0; +} + +int +Handler::close (u_long) +{ + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) closing down %@\n"), + this)); + + delete this->ssl_stream_; + delete this; + + return 0; +} + +int +Handler::svc (void) +{ + // Timer logic. + this->timer_.start (); + + // Invoke the hook method to run the specific test. + int result = this->run (); + + this->timer_.stop (); + + this->print_results (); + + return result; +} + +int +Handler::parse_header_and_allocate_buffer (char *&request, + ACE_INT32 *len) +{ + ssize_t result = this->ssl_stream_ -> recv_n ((void *) len, + sizeof (ACE_INT32)); + if (result == 0) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) connected closed\n"))); + return -1; + } + else if (result == -1 || result != sizeof (ACE_INT32)) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("(%P|%t) %p\n"), + ACE_TEXT ("recv_n failed")), + -1); + else + { + *len = ntohl (*len); + ACE_NEW_RETURN (request, + char[*len], + -1); + } + + return 0; +} + +void +Handler::print_results (void) +{ +} + +Twoway_Handler::Twoway_Handler (ACE_SSL_SOCK_Stream* ssl_stream) + : Handler (ssl_stream) +{ +} + +// Function entry point into the twoway server task. + +int +Twoway_Handler::run (void) +{ + // Read data from client (terminate on error). + + char *request = 0; + + for (;;) + { + ACE_INT32 len = 0; + + if (parse_header_and_allocate_buffer (request, + &len) == -1) + return -1; + + // Subtract off the sizeof the length prefix. + ssize_t r_bytes = + this->ssl_stream_ -> recv_n (request, + len - sizeof (ACE_UINT32)); + + if (r_bytes == -1) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("recv"))); + break; + } + else if (r_bytes == 0) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) reached end of input, connection ") + ACE_TEXT ("closed by client\n"))); + break; + } + else if (OPTIONS::instance ()->verbose () + && ACE::write_n (ACE_STDOUT, + request, + r_bytes) != r_bytes) + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("ACE::write_n"))); + else + { + ssize_t s_bytes = + (ssize_t) OPTIONS::instance ()->reply_message_len (); + + // Don't try to send more than is in the request buffer! + if (s_bytes > r_bytes) + s_bytes = r_bytes; + + if (this->ssl_stream_ -> send_n (request, + s_bytes) != s_bytes) + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("send_n"))); + } + this->total_bytes_ += size_t (r_bytes); + this->message_count_++; + + delete [] request; + request = 0; + } + + delete [] request; + return 0; +} + +Oneway_Handler::Oneway_Handler (ACE_SSL_SOCK_Stream *ssl_stream) + : Handler (ssl_stream) +{ +} + +void +Oneway_Handler::print_results (void) +{ + ACE_Profile_Timer::ACE_Elapsed_Time et; + this->timer_.elapsed_time (et); + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("\t\treal time = %f secs \n\t\tuser time = %f secs \n\t\tsystem time = %f secs\n"), + et.real_time, + et.user_time, + et.system_time)); + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("\t\tmessages = %d\n\t\ttotal bytes = %d\n\t\tmbits/sec = %f\n\t\tusec-per-message = %f\n"), + this->message_count_, + this->total_bytes_, + (((double) this->total_bytes_ * 8) / et.real_time) / (double) (1024 * 1024), + ((et.user_time + et.system_time) / (double) this->message_count_) * ACE_ONE_SECOND_IN_USECS)); +} + +// Function entry point into the oneway server task. + +int +Oneway_Handler::run (void) +{ + // Read data from client (terminate on error). + + char *request = 0; + + for (;;) + { + ACE_INT32 len = 0; + + if (parse_header_and_allocate_buffer (request, + &len) == -1) + return -1; + + // Subtract off the sizeof the length prefix. + ssize_t r_bytes = + this->ssl_stream_ -> recv_n (request, + len - sizeof (ACE_UINT32)); + + if (r_bytes == -1) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("recv"))); + break; + } + else if (r_bytes == 0) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) reached end of input, connection ") + ACE_TEXT ("closed by client\n"))); + break; + } + else if (OPTIONS::instance ()->verbose () + && ACE::write_n (ACE_STDOUT, + request, + r_bytes) != r_bytes) + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("ACE::write_n"))); + + this->total_bytes_ += size_t (r_bytes); + this->message_count_++; + delete [] request; + request = 0; + } + + delete [] request; + return 0; +} + +// Create a twoway handler. + +Handler * +Handler_Factory::make_twoway_handler (ACE_SSL_SOCK_Stream *ssl_stream) +{ + return new Twoway_Handler (ssl_stream); +} + +// Create a oneway handler. + +Handler * +Handler_Factory::make_oneway_handler (ACE_SSL_SOCK_Stream *ssl_stream) + +{ + return new Oneway_Handler (ssl_stream); +} + +int +Handler_Factory::init_acceptors (void) +{ + // Create the oneway and twoway server addresses. + ACE_INET_Addr twoway_server_addr (OPTIONS::instance ()->port ()); + ACE_INET_Addr oneway_server_addr (OPTIONS::instance ()->port () + 1); + + // Create acceptors, reuse the address. + if (this->twoway_acceptor_.open (twoway_server_addr, 1) == -1 + || this->oneway_acceptor_.open (oneway_server_addr, 1) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("open")), + -1); + else if (this->twoway_acceptor_.get_local_addr (twoway_server_addr) == -1 + || this->oneway_acceptor_.get_local_addr (oneway_server_addr) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("get_local_addr")), + -1); + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) starting twoway server at port %d and oneway server at port %d\n"), + twoway_server_addr.get_port_number (), + oneway_server_addr.get_port_number ())); + return 0; +} + +int +Handler_Factory::create_handler ( + ACE_SSL_SOCK_Acceptor &acceptor, + Handler * (*handler_factory) (ACE_SSL_SOCK_Stream* ), + const char *handler_type) +{ + ACE_SSL_SOCK_Stream* new_stream; + + ACE_NEW_RETURN (new_stream, ACE_SSL_SOCK_Stream, -1); + + if (acceptor.accept (*new_stream) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("accept")), + -1); + + Handler *handler; + + ACE_ALLOCATOR_RETURN (handler, + (*handler_factory) (new_stream), + -1); + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) spawning %s handler\n"), + handler_type)); + + if (handler->open () == -1) + return -1; + +#if defined (ACE_MT_SAFE) + // Spawn a new thread and run the new connection in that thread of + // control using the <server> function as the entry point. + return handler->activate (); +#else + handler->svc (); + handler->close (0); + return 0; +#endif /* ACE_HAS_THREADS */ +} + +Handler_Factory::Handler_Factory (void) +{ +} + +Handler_Factory::~Handler_Factory (void) +{ + this->twoway_acceptor_.close (); + this->oneway_acceptor_.close (); +} + +// Run the main event loop. + +int +Handler_Factory::handle_events (void) +{ + if (this->init_acceptors () == -1) + return -1; + + fd_set handles; + + FD_ZERO (&handles); + FD_SET ((ACE_SOCKET) this->twoway_acceptor_.get_handle (), &handles); + FD_SET ((ACE_SOCKET) this->oneway_acceptor_.get_handle (), &handles); + + // Performs the iterative server activities. + + for (;;) + { + ACE_Time_Value timeout (ACE_DEFAULT_TIMEOUT); + fd_set temp = handles; + + int result = + ACE_OS::select (int (this->oneway_acceptor_.get_handle ()) + 1, + (fd_set *) &temp, + 0, + 0, + timeout); + if (result == -1) + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("(%P|%t) %p\n"), + ACE_TEXT ("select"))); + else if (result == 0 && OPTIONS::instance ()->verbose ()) + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) select timed out\n"))); + else + { + if (FD_ISSET (this->twoway_acceptor_.get_handle (), + &temp)) + this->create_handler (this->twoway_acceptor_, + &Handler_Factory::make_twoway_handler, + "twoway"); + if (FD_ISSET (this->oneway_acceptor_.get_handle (), + &temp)) + this->create_handler (this->oneway_acceptor_, + &Handler_Factory::make_oneway_handler, + "oneway"); + } + } + + ACE_NOTREACHED (return 0;) +} + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + + ACE_SSL_Context *context = ACE_SSL_Context::instance (); + + context->certificate ("./dummy.pem", SSL_FILETYPE_PEM); + context->private_key ("./key.pem", SSL_FILETYPE_PEM); + + OPTIONS::instance ()->parse_args (argc, argv); + + Handler_Factory server; + + return server.handle_events (); +} + diff --git a/ACE/examples/IPC_SAP/SSL_SAP/SSL-server-fancy.h b/ACE/examples/IPC_SAP/SSL_SAP/SSL-server-fancy.h new file mode 100644 index 00000000000..fed1b513f90 --- /dev/null +++ b/ACE/examples/IPC_SAP/SSL_SAP/SSL-server-fancy.h @@ -0,0 +1,44 @@ +// -*- C++ -*- +// $Id$ + +// This file defines the Options class for SSL-server-fancy. +// IBM C++ compiler'd template auto-instantiator needs this in a separate file. + +#ifndef __ACE_SSL_SERVER_FANCY_H +#define __ACE_SSL_SERVER_FANCY_H + +class Options + // = TITLE + // Define the options for this test. +{ +public: + Options (void); + // Constructor. + + ~Options (void); + // Destructor. + + int parse_args (int argc, ACE_TCHAR *argv[]); + // Parse the command-line arguments. + + int verbose (void) const; + // Are we running in verbose mode? + + u_short port (void) const; + // Port number that we are listening at. + + int reply_message_len (void) const; + // Size of the reply message. + +private: + int verbose_; + // Are we running in verbose mode? + + u_short port_; + // Port number we listen at. + + size_t reply_message_len_; + // Size of the reply message. +}; + +#endif /* __ACE_SSL_SERVER_FANCY_H */ diff --git a/ACE/examples/IPC_SAP/SSL_SAP/SSL-server-poll.cpp b/ACE/examples/IPC_SAP/SSL_SAP/SSL-server-poll.cpp new file mode 100644 index 00000000000..83333ccc357 --- /dev/null +++ b/ACE/examples/IPC_SAP/SSL_SAP/SSL-server-poll.cpp @@ -0,0 +1,212 @@ +// $Id$ + +// IPC_SAP/poll server, which illustrates how to integrate the ACE +// SSL socket wrappers with the SVR4 <poll> system call to create a +// single-threaded concurrent server. This server program can be +// driven by the oneway test mode of SSL-client.cpp. + +#include "ace/OS_NS_stdlib.h" +#include "ace/OS_NS_unistd.h" +#include "ace/Time_Value.h" +#include "ace/SSL/SSL_SOCK_Acceptor.h" + +ACE_RCSID (SSL_SAP, + SSL_server_poll, + "$Id$") + +#if defined (ACE_HAS_POLL) + +#include "ace/SSL/SSL_SOCK_Stream.h" + +#include "ace/Log_Msg.h" +#include "ace/INET_Addr.h" +#include "ace/OS_NS_stdio.h" +#include "ace/OS_NS_poll.h" + + +// Should we be verbose? +static int verbose = 0; + +// Max number of open handles. +static const int MAX_HANDLES = 200; + +struct Buffer_Info +{ + void *buf_; + // Pointer to the buffer. + + size_t len_; + // Length of the buffer. +}; + +// Array of <pollfd>'s. +static struct pollfd poll_array[MAX_HANDLES]; + +// Array of <Buffer_Info>. +static Buffer_Info buffer_array[MAX_HANDLES]; + +static void +init_poll_array (void) +{ + int i; + + for (i = 0; i < MAX_HANDLES; i++) + { + poll_array[i].fd = ACE_INVALID_HANDLE; + poll_array[i].events = POLLIN; + } +} + +static int +init_buffer (size_t index) +{ + ACE_INT32 len; + + if (ACE::recv_n (poll_array[index].fd, + (void *) &len, + sizeof (ACE_INT32)) != sizeof (ACE_INT32)) + ACE_ERROR_RETURN ((LM_ERROR, + "(%P|%t) %p\n", + "recv_n failed"), + -1); + else + { + len = ntohl (len); + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) reading messages of size %d from handle %d\n", + len, + poll_array[index].fd)); + + ACE_ALLOCATOR_RETURN (buffer_array[index].buf_, + ACE_OS::malloc (len), + -1); + buffer_array[index].len_ = len; + } + return 0; +} + +static void +handle_data (size_t &n_handles) +{ + // Handle pending logging messages first (s_handle + 1 is guaranteed + // to be lowest client descriptor). + + for (size_t index = 1; index < n_handles; index++) + { + if (ACE_BIT_ENABLED (poll_array[index].revents, POLLIN)) + { + // First time in, we need to initialize the buffer. + if (buffer_array[index].buf_ == 0 + && init_buffer (index) == -1) + { + ACE_ERROR ((LM_ERROR, + "(%P|%t) %p\n", + "init_buffer")); + continue; + } + + // Read data from client (terminate on error). + + ssize_t n = ACE::recv (poll_array[index].fd, + buffer_array[index].buf_, + buffer_array[index].len_); + // <recv> will not block in this case! + + if (n == -1) + ACE_ERROR ((LM_ERROR, + "%p\n", + "read failed")); + else if (n == 0) + { + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) closing oneway server at handle %d\n", + poll_array[index].fd)); + + // Handle client connection shutdown. + ACE_OS::close (poll_array[index].fd); + poll_array[index].fd = poll_array[--n_handles].fd; + + ACE_OS::free ((void *) buffer_array[index].buf_); + buffer_array[index].buf_ = 0; + buffer_array[index].len_ = 0; + } + else if (verbose) + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) %*s", + n, + buffer_array[index].buf_)); + } + } +} + +static void +handle_connections (ACE_SSL_SOCK_Acceptor &peer_acceptor, + size_t &n_handles) +{ + if (ACE_BIT_ENABLED (poll_array[0].revents, POLLIN)) + { + ACE_SSL_SOCK_Stream new_stream; + + ACE_INET_Addr client; + ACE_Time_Value nonblock (0, 0); + + // Handle all pending connection requests (note use of "polling" + // feature that doesn't block). + + while (ACE_OS::poll (poll_array, 1, nonblock) > 0) + if (peer_acceptor.accept (new_stream, &client) == -1) + ACE_OS::perror ("accept"); + else + { + const char *s = client.get_host_name (); + + ACE_ASSERT (s != 0); + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) client %s\n", + s)); + poll_array[n_handles++].fd = new_stream.get_handle (); + } + } +} + +int +main (int, char *[]) +{ + u_short port = ACE_DEFAULT_SERVER_PORT + 1; + + // Create a server end-point. + ACE_INET_Addr addr (port); + ACE_SSL_SOCK_Acceptor peer_acceptor (addr); + + ACE_HANDLE s_handle = peer_acceptor.get_handle (); + + init_poll_array (); + + poll_array[0].fd = s_handle; + + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) starting oneway server at port %d\n", + port)); + + for (size_t n_handles = 1;;) + { + // Wait for client I/O events (handle interrupts). + while (ACE_OS::poll (poll_array, n_handles) == -1 + && errno == EINTR) + continue; + + handle_data (n_handles); + handle_connections (peer_acceptor, n_handles); + } + + /* NOTREACHED */ + return 0; +} +#else +#include "ace/OS_NS_stdio.h" +int main (int, char *[]) +{ + ACE_OS::fprintf (stderr, "This feature is not supported\n"); + return 0; +} +#endif /* ACE_HAS_POLL */ diff --git a/ACE/examples/IPC_SAP/SSL_SAP/SSL-server-simple.cpp b/ACE/examples/IPC_SAP/SSL_SAP/SSL-server-simple.cpp new file mode 100644 index 00000000000..22535160cf0 --- /dev/null +++ b/ACE/examples/IPC_SAP/SSL_SAP/SSL-server-simple.cpp @@ -0,0 +1,366 @@ +// $Id$ + +// This example tests the features of the <ACE_SSL_SOCK_Acceptor>, +// <ACE_SSL_SOCK_Stream>, and <ACE_Svc_Handler> classes. + +#include "ace/Thread_Manager.h" +#include "ace/Handle_Set.h" +#include "ace/Profile_Timer.h" +#include "ace/OS_NS_sys_select.h" + +#include "ace/SSL/SSL_SOCK_Acceptor.h" + +ACE_RCSID(SSL_SAP, SSL_server_simple, "$Id$") + +// Are we running verbosely? +static int verbose = 1; + +// Function entry point into the twoway server task. + +int +twoway_server (ACE_SSL_SOCK_Stream &stream) +{ + ACE_INET_Addr cli_addr; + + // Make sure we're not in non-blocking mode. + if (stream.disable (ACE_NONBLOCK) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "disable"), + 0); + else if (stream.get_remote_addr (cli_addr) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "get_remote_addr"), + 0); + + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) client %s connected from %d\n", + cli_addr.get_host_name (), + cli_addr.get_port_number ())); + + size_t total_bytes = 0; + size_t message_count = 0; + + char *request = 0; + + // Read data from client (terminate on error). + + for (;;) + { + ACE_INT32 len; + + ssize_t r_bytes = stream.recv_n ((void *) &len, + sizeof (ACE_INT32)); + if (r_bytes == -1) + { + ACE_ERROR ((LM_ERROR, + "%p\n", + "recv")); + break; + } + else if (r_bytes == 0) + { + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) reached end of input, connection closed by client\n")); + break; + } + else if (r_bytes != sizeof (ACE_INT32)) + { + ACE_ERROR ((LM_ERROR, + "(%P|%t) %p\n", + "recv_n failed")); + break; + } + else + { + len = ntohl (len); + ACE_NEW_RETURN (request, + char [len], + 0); + } + + // Subtract off the sizeof the length prefix. + r_bytes = stream.recv_n (request, + len - sizeof (ACE_UINT32)); + if (r_bytes == -1) + { + ACE_ERROR ((LM_ERROR, + "%p\n", + "recv")); + break; + } + else if (r_bytes == 0) + { + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) reached end of input, connection closed by client\n")); + break; + } + else if (verbose + && ACE::write_n (ACE_STDOUT, + request, + r_bytes) != r_bytes) + ACE_ERROR ((LM_ERROR, + "%p\n", + "ACE::write_n")); + else if (stream.send_n (request, + r_bytes) != r_bytes) + ACE_ERROR ((LM_ERROR, + "%p\n", + "send_n")); + + total_bytes += size_t (r_bytes); + message_count++; + + delete [] request; + request = 0; + } + + // Close new endpoint (listening endpoint stays open). + stream.close (); + + delete [] request; + return 0; +} + +// Function entry point into the oneway server task. + +static int +oneway_server (ACE_SSL_SOCK_Stream &stream) +{ + ACE_INET_Addr cli_addr; + + // Make sure we're not in non-blocking mode. + if (stream.disable (ACE_NONBLOCK) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "disable"), + 0); + else if (stream.get_remote_addr (cli_addr) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "get_remote_addr"), + 0); + + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) client %s connected from %d\n", + cli_addr.get_host_name (), + cli_addr.get_port_number ())); + + // Timer business + ACE_Profile_Timer timer; + timer.start (); + + size_t total_bytes = 0; + size_t message_count = 0; + + char *request = 0; + + // Read data from client (terminate on error). + + for (;;) + { + ACE_INT32 len; + + ssize_t r_bytes = stream.recv_n ((void *) &len, + sizeof (ACE_INT32)); + if (r_bytes == -1) + { + ACE_ERROR ((LM_ERROR, + "%p\n", + "recv")); + break; + } + else if (r_bytes == 0) + { + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) reached end of input, connection closed by client\n")); + break; + } + else if (r_bytes != sizeof (ACE_INT32)) + { + ACE_ERROR ((LM_ERROR, + "(%P|%t) %p\n", + "recv_n failed")); + break; + } + else + { + len = ntohl (len); + ACE_NEW_RETURN (request, + char [len], + 0); + } + + // Subtract off the sizeof the length prefix. + r_bytes = stream.recv_n (request, + len - sizeof (ACE_UINT32)); + + if (r_bytes == -1) + { + ACE_ERROR ((LM_ERROR, + "%p\n", + "recv")); + break; + } + else if (r_bytes == 0) + { + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) reached end of input, connection closed by client\n")); + break; + } + else if (verbose + && ACE::write_n (ACE_STDOUT, request, r_bytes) != r_bytes) + ACE_ERROR ((LM_ERROR, + "%p\n", + "ACE::write_n")); + + total_bytes += size_t (r_bytes); + message_count++; + + delete [] request; + request = 0; + } + + timer.stop (); + + ACE_Profile_Timer::ACE_Elapsed_Time et; + timer.elapsed_time (et); + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("\t\treal time = %f secs \n\t\tuser time = %f secs \n\t\tsystem time = %f secs\n"), + et.real_time, + et.user_time, + et.system_time)); + + double messages_per_sec = double (message_count) / et.real_time; + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("\t\tmessages = %d\n\t\ttotal bytes = %d\n\t\tmbits/sec = %f\n\t\tusec-per-message = %f\n\t\tmessages-per-second = %0.00f\n"), + message_count, + total_bytes, + (((double) total_bytes * 8) / et.real_time) / (double) (1024 * 1024), + (et.real_time / (double) message_count) * 1000000, + messages_per_sec < 0 ? 0 : messages_per_sec)); + + // Close new endpoint (listening endpoint stays open). + stream.close (); + + delete [] request; + return 0; +} + +static int +run_event_loop (u_short port) +{ + // Raise the socket handle limit to the maximum. + ACE::set_handle_limit (); + + // Create the oneway and twoway acceptors. + ACE_SSL_SOCK_Acceptor twoway_acceptor; + ACE_SSL_SOCK_Acceptor oneway_acceptor; + + // Create the oneway and twoway server addresses. + ACE_INET_Addr twoway_server_addr (port); + ACE_INET_Addr oneway_server_addr (port + 1); + + // Create acceptors, reuse the address. + if (twoway_acceptor.open (twoway_server_addr, 1) == -1 + || oneway_acceptor.open (oneway_server_addr, 1) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "open"), + 1); + else if (twoway_acceptor.get_local_addr (twoway_server_addr) == -1 + || oneway_acceptor.get_local_addr (oneway_server_addr) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "get_local_addr"), + 1); + + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) starting twoway server at port %d and oneway server at port %d\n", + twoway_server_addr.get_port_number (), + oneway_server_addr.get_port_number ())); + + // Keep these objects out here to prevent excessive constructor + // calls within the loop. + ACE_SSL_SOCK_Stream new_stream; + + ACE_Handle_Set handle_set; + handle_set.set_bit (twoway_acceptor.get_handle ()); + handle_set.set_bit (oneway_acceptor.get_handle ()); + + // Performs the iterative server activities. + + for (;;) + { + ACE_Time_Value timeout (ACE_DEFAULT_TIMEOUT); + ACE_Handle_Set temp = handle_set; + + int maxfd = int(oneway_acceptor.get_handle ()); + if (maxfd < int(twoway_acceptor.get_handle ())) + maxfd = int(twoway_acceptor.get_handle ()); + int result = ACE_OS::select (maxfd + 1, + (fd_set *) temp, + 0, + 0, + timeout); + if (result == -1) + ACE_ERROR ((LM_ERROR, + "(%P|%t) %p\n", + "select")); + else if (result == 0 && verbose) + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) select timed out\n")); + else + { + if (temp.is_set (twoway_acceptor.get_handle ())) + { + int r = twoway_acceptor.accept (new_stream); + while (r == -1 && errno == EAGAIN) + r = twoway_acceptor.accept (new_stream); + if (r == -1) + { + ACE_ERROR ((LM_ERROR, + "%p\n", + "accept")); + continue; + } + else + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) spawning twoway server\n")); + + // Run the twoway server. + twoway_server (new_stream); + } + if (temp.is_set (oneway_acceptor.get_handle ())) + { + if (oneway_acceptor.accept (new_stream) == -1) + { + ACE_ERROR ((LM_ERROR, "%p\n", "accept")); + continue; + } + else + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) spawning oneway server\n")); + + // Run the oneway server. + oneway_server (new_stream); + } + } + } + + /* NOTREACHED */ +} + +int +main (int argc, char *argv[]) +{ + u_short port = ACE_DEFAULT_SERVER_PORT; + + if (argc > 1) + port = ACE_OS::atoi (argv[1]); + + return run_event_loop (port); +} diff --git a/ACE/examples/IPC_SAP/SSL_SAP/SSL-server.cpp b/ACE/examples/IPC_SAP/SSL_SAP/SSL-server.cpp new file mode 100644 index 00000000000..8563067af03 --- /dev/null +++ b/ACE/examples/IPC_SAP/SSL_SAP/SSL-server.cpp @@ -0,0 +1,430 @@ +// $Id$ + +// This example tests the features of the <ACE_SSL_SOCK_Acceptor>, +// <ACE_SSL_SOCK_Stream>, and <ACE_Svc_Handler> classes. If the platform +// supports threads it uses a thread-per-connection concurrency model. +// Otherwise, it uses a single-threaded iterative server model. + +#include "ace/Thread_Manager.h" +#include "ace/Handle_Set.h" +#include "ace/Profile_Timer.h" +#include "ace/OS_NS_sys_select.h" + +#include "ace/SSL/SSL_SOCK_Acceptor.h" + +ACE_RCSID(SSL_SAP, SSL_server, "$Id$") + +// Are we running verbosely? +static int verbose = 0; + +static void +run_server (ACE_THR_FUNC server, + ACE_SSL_SOCK_Stream * new_stream) +{ +#if defined (ACE_HAS_THREADS) + // Spawn a new thread and run the new connection in that thread of + // control using the <server> function as the entry point. + if (ACE_Thread_Manager::instance ()->spawn (server, + (void *) new_stream, + THR_DETACHED) == -1) + ACE_ERROR ((LM_ERROR, + "(%P|%t) %p\n", + "spawn")); +#else + (*server) ((void *) new_stream); +#endif /* ACE_HAS_THREADS */ +} + +// Function entry point into the twoway server task. + +static ACE_THR_FUNC_RETURN +twoway_server (void *arg) +{ + ACE_INET_Addr cli_addr; + ACE_SSL_SOCK_Stream * new_stream = (ACE_SSL_SOCK_Stream *) arg; + + // Make sure we're not in non-blocking mode. + if (new_stream->disable (ACE_NONBLOCK) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "disable"), + 0); + else if (new_stream->get_remote_addr (cli_addr) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "get_remote_addr"), + 0); + + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) client %s connected from %d\n", + cli_addr.get_host_name (), + cli_addr.get_port_number ())); + + size_t total_bytes = 0; + size_t message_count = 0; + + char *request = 0; + + // Read data from client (terminate on error). + + for (;;) + { + ACE_INT32 len; + + ssize_t r_bytes = new_stream->recv_n ((void *) &len, + sizeof (ACE_INT32)); + if (r_bytes == -1) + { + ACE_ERROR ((LM_ERROR, + "%p\n", + "recv")); + break; + } + else if (r_bytes == 0) + { + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) reached end of input, connection closed by client\n")); + break; + } + else if (r_bytes != sizeof (ACE_INT32)) + { + ACE_ERROR ((LM_ERROR, + "(%P|%t) %p\n", + "recv_n failed")); + break; + } + else + { + len = ntohl (len); + ACE_NEW_RETURN (request, + char [len], + 0); + } + + // Subtract off the sizeof the length prefix. + r_bytes = new_stream->recv_n (request, + len - sizeof (ACE_UINT32)); + if (r_bytes == -1) + { + ACE_ERROR ((LM_ERROR, + "%p\n", + "recv")); + break; + } + else if (r_bytes == 0) + { + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) reached end of input, " + "connection closed by client\n")); + break; + } + else if (verbose + && ACE::write_n (ACE_STDOUT, + request, + r_bytes) != r_bytes) + ACE_ERROR ((LM_ERROR, + "%p\n", + "ACE::write_n")); + else if (new_stream->send_n (request, + r_bytes) != r_bytes) + ACE_ERROR ((LM_ERROR, + "%p\n", + "send_n")); + + total_bytes += size_t (r_bytes); + message_count++; + + delete [] request; + request = 0; + } + + // Close new endpoint (listening endpoint stays open). + new_stream->close (); + + delete new_stream; + + delete [] request; + + return 0; +} + +// Function entry point into the oneway server task. + +static ACE_THR_FUNC_RETURN +oneway_server (void *arg) +{ + ACE_INET_Addr cli_addr; + ACE_SSL_SOCK_Stream * new_stream = (ACE_SSL_SOCK_Stream *) arg; + + // Make sure we're not in non-blocking mode. + if (new_stream->disable (ACE_NONBLOCK) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "disable"), + 0); + else if (new_stream->get_remote_addr (cli_addr) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "get_remote_addr"), + 0); + + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) client %s connected from %d\n", + cli_addr.get_host_name (), + cli_addr.get_port_number ())); + + // Timer business + ACE_Profile_Timer timer; + timer.start (); + + size_t total_bytes = 0; + size_t message_count = 0; + + char *request = 0; + + // Read data from client (terminate on error). + + for (;;) + { + ACE_INT32 len; + + ssize_t r_bytes = new_stream->recv_n ((void *) &len, + sizeof (ACE_INT32)); + if (r_bytes == -1) + { + ACE_ERROR ((LM_ERROR, + "%p\n", + "recv")); + break; + } + else if (r_bytes == 0) + { + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) reached end of input, connection closed by client\n")); + break; + } + else if (r_bytes != sizeof (ACE_INT32)) + { + ACE_ERROR ((LM_ERROR, + "(%P|%t) %p\n", + "recv_n failed")); + break; + } + else + { + len = ntohl (len); + ACE_NEW_RETURN (request, + char [len], + 0); + } + + // Subtract off the sizeof the length prefix. + r_bytes = new_stream->recv_n (request, + len - sizeof (ACE_UINT32)); + + if (r_bytes == -1) + { + ACE_ERROR ((LM_ERROR, + "%p\n", + "recv")); + break; + } + else if (r_bytes == 0) + { + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) reached end of input, connection closed by client\n")); + break; + } + else if (verbose + && ACE::write_n (ACE_STDOUT, request, r_bytes) != r_bytes) + ACE_ERROR ((LM_ERROR, + "%p\n", + "ACE::write_n")); + + total_bytes += size_t (r_bytes); + message_count++; + + delete [] request; + request = 0; + } + + timer.stop (); + + ACE_Profile_Timer::ACE_Elapsed_Time et; + timer.elapsed_time (et); + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("\t\treal time = %f secs \n") + ACE_TEXT ("\t\tuser time = %f secs \n") + ACE_TEXT ("\t\tsystem time = %f secs\n"), + et.real_time, + et.user_time, + et.system_time)); + + double messages_per_sec = double (message_count) / et.real_time; + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("\t\tmessages = %d\n") + ACE_TEXT ("\t\ttotal bytes = %d\n") + ACE_TEXT ("\t\tmbits/sec = %f\n") + ACE_TEXT ("\t\tusec-per-message = %f\n") + ACE_TEXT ("\t\tmessages-per-second = %0.00f\n"), + message_count, + total_bytes, + (((double) total_bytes * 8) / et.real_time) / (double) (1024 * 1024), + (et.real_time / (double) message_count) * 1000000, + messages_per_sec < 0 ? 0 : messages_per_sec)); + + // Close new endpoint (listening endpoint stays open). + new_stream->close (); + + delete new_stream; + + delete [] request; + + return 0; +} + +static int +run_event_loop (u_short port) +{ + // Raise the socket handle limit to the maximum. + ACE::set_handle_limit (); + + // Create the oneway and twoway acceptors. + ACE_SSL_SOCK_Acceptor twoway_acceptor; + ACE_SSL_SOCK_Acceptor oneway_acceptor; + + // Create the oneway and twoway server addresses. + ACE_INET_Addr twoway_server_addr (port); + ACE_INET_Addr oneway_server_addr (port + 1); + + // Create acceptors, reuse the address. + if (twoway_acceptor.open (twoway_server_addr, 1) == -1 + || oneway_acceptor.open (oneway_server_addr, 1) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "open"), + 1); + else if (twoway_acceptor.get_local_addr (twoway_server_addr) == -1 + || oneway_acceptor.get_local_addr (oneway_server_addr) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "get_local_addr"), + 1); + + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) starting twoway server at port %d and oneway server at port %d\n", + twoway_server_addr.get_port_number (), + oneway_server_addr.get_port_number ())); + + // Keep these objects out here to prevent excessive constructor + // calls within the loop. + + ACE_Handle_Set handle_set; + handle_set.set_bit (twoway_acceptor.get_handle ()); + handle_set.set_bit (oneway_acceptor.get_handle ()); + + ACE_SSL_SOCK_Stream * new_stream = 0; + + // Performs the iterative server activities. + for (;;) + { + ACE_Time_Value timeout (ACE_DEFAULT_TIMEOUT); + ACE_Handle_Set temp = handle_set; + + int result = ACE_OS::select (int (oneway_acceptor.get_handle ()) + 1, + (fd_set *) temp, + 0, + 0, + timeout); + if (result == -1) + ACE_ERROR ((LM_ERROR, + "(%P|%t) %p\n", + "select")); + else if (result == 0 && verbose) + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) select timed out\n")); + else + { + // A new ACE_SSL_SOCK_Stream must be initialized for each + // connection. However, it retains (SSL) state so simply + // initializing a new ACE_SSL_SOCK_Stream by passing it a + // handle isn't enough, nor is it allowed. Such a scheme is + // is sometimes done with the non-SSL aware + // ACE_SOCK_Stream. An ACE_SSL_SOCK_Stream should only be + // initialized by an ACE_SSL_SOCK_Acceptor (server side), or an + // ACE_SSL_SOCK_Connector (client side). + // + // It is also possible to copy or assign an + // ACE_SSL_SOCK_Stream since it implements both + // methods/operators. However, the user must ensure that + // the copy or assignment is atomic. + + if (temp.is_set (twoway_acceptor.get_handle ())) + { + ACE_NEW_RETURN (new_stream, + ACE_SSL_SOCK_Stream, + -1); + + if (twoway_acceptor.accept (*new_stream) == -1) + { + ACE_ERROR ((LM_ERROR, + "%p\n", + "accept")); + + delete new_stream; + + continue; + } + else + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) spawning twoway server\n")); + + // Run the twoway server. + run_server (twoway_server, + new_stream); + } + if (temp.is_set (oneway_acceptor.get_handle ())) + { + ACE_NEW_RETURN (new_stream, + ACE_SSL_SOCK_Stream, + -1); + + if (oneway_acceptor.accept (*new_stream) == -1) + { + ACE_ERROR ((LM_ERROR, "%p\n", "accept")); + + delete new_stream; + + continue; + } + else + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) spawning oneway server\n")); + + // Run the oneway server. + run_server (oneway_server, + new_stream); + } + } + } + + /* NOTREACHED */ +} + +int +main (int argc, char *argv[]) +{ + ACE_SSL_Context *context = ACE_SSL_Context::instance (); + + context->certificate ("./dummy.pem", SSL_FILETYPE_PEM); + context->private_key ("./key.pem", SSL_FILETYPE_PEM); + + u_short port = ACE_DEFAULT_SERVER_PORT; + + if (argc > 1) + port = ACE_OS::atoi (argv[1]); + + return run_event_loop (port); +} diff --git a/ACE/examples/IPC_SAP/SSL_SAP/SSL_SAP.mpc b/ACE/examples/IPC_SAP/SSL_SAP/SSL_SAP.mpc new file mode 100644 index 00000000000..675f104f4dc --- /dev/null +++ b/ACE/examples/IPC_SAP/SSL_SAP/SSL_SAP.mpc @@ -0,0 +1,44 @@ +// -*- MPC -*- +// $Id$ + +project(*client) : aceexe, ssl { + exename = client + Source_Files { + SSL-client.cpp + } +} + +project(*client_simple) : aceexe, ssl { + exename = client-simple + Source_Files { + SSL-client-simple.cpp + } +} + +project(*server) : aceexe, ssl { + exename = server + Source_Files { + SSL-server.cpp + } +} + +project(*server_fancy) : aceexe, ssl { + exename = server-fancy + Source_Files { + SSL-server-fancy.cpp + } +} + +project(*server_poll) : aceexe, ssl { + exename = server-poll + Source_Files { + SSL-server-poll.cpp + } +} + +project(*server_simple) : aceexe, ssl { + exename = server-simple + Source_Files { + SSL-server-simple.cpp + } +} diff --git a/ACE/examples/IPC_SAP/SSL_SAP/dummy.pem b/ACE/examples/IPC_SAP/SSL_SAP/dummy.pem new file mode 100644 index 00000000000..d631a33b956 --- /dev/null +++ b/ACE/examples/IPC_SAP/SSL_SAP/dummy.pem @@ -0,0 +1,15 @@ +-----BEGIN CERTIFICATE----- +MIICaTCCAdICAQAwDQYJKoZIhvcNAQEEBQAwcjELMAkGA1UEBhMCVVMxCzAJBgNV +BAgTAkNBMQ8wDQYDVQQHEwZJcnZpbmUxDDAKBgNVBAoTA09DSTEMMAoGA1UECxMD +VEFPMREwDwYDVQQDEwhwcml5YW5rYTEWMBQGCSqGSIb3DQEJARYHcGdvbnRsYTAe +Fw0wMTAzMjkwNDM4NDZaFw0wMTA0MjgwNDM4NDZaMIGHMQswCQYDVQQGEwJVUzEL +MAkGA1UECBMCQ0ExDzANBgNVBAcTBklydmluZTEdMBsGA1UEChMUT2JqZWN0IENv +bXB1dGluZyBJbmMxEDAOBgNVBAsTB09DSStUQU8xETAPBgNVBAMTCHByaXlhbmth +MRYwFAYJKoZIhvcNAQkBFgdwZ29udGxhMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCB +iQKBgQClC6z/bX1JHF1Hg06NCnBmsikEjViEdJFuqLOH3rXSGbm+2Eo+IO4dHlFS +u6+Ntk4olBZTuf0DqzyEgrOiN7cnKXpxJzb1cwCmVkvDQISMygf4o66+CHtF8o8Z +Sbi9F5u9W+MILaoCexEIVZqfHffcGxvm5O2MorBSQNka3NcC3wIDAQABMA0GCSqG +SIb3DQEBBAUAA4GBADuKX6kllE2sNdQYMbSzt5C/lcpgcsK0BR6L01cQA95b5TvL +HsKMeeeRj2npR4EPXY2gqgWTrKHZvf01aoKE5LuyzSQ+qfFMuEfo7+p9SYIuIrLD +5+J0wOwN0R0YZAEY5gCAqRGw26dwWDai+PASPsx0YXV1y9jBB1FFtUFgrpR8 +-----END CERTIFICATE----- diff --git a/ACE/examples/IPC_SAP/SSL_SAP/key.pem b/ACE/examples/IPC_SAP/SSL_SAP/key.pem new file mode 100644 index 00000000000..54ff8f0f488 --- /dev/null +++ b/ACE/examples/IPC_SAP/SSL_SAP/key.pem @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXAIBAAKBgQClC6z/bX1JHF1Hg06NCnBmsikEjViEdJFuqLOH3rXSGbm+2Eo+ +IO4dHlFSu6+Ntk4olBZTuf0DqzyEgrOiN7cnKXpxJzb1cwCmVkvDQISMygf4o66+ +CHtF8o8ZSbi9F5u9W+MILaoCexEIVZqfHffcGxvm5O2MorBSQNka3NcC3wIDAQAB +AoGALYq/PexUeewdwTH2ZuzOf0gCEYN/PW19A/ABOii2OzdmDcdZFTO5AMfw4Mdx +dcUsY/4Y+xmDO5Pwqw/1yXleTDqvEKCgIEHN4NWnYYSiZOy3LBzQ8XaMZ7/2PCqc +s4EtesuRB2kZ7PH2R1vJfyGIxZPaO5MOFbs3QFnpBUjqOmECQQDQCYgnBcshCEro +gsrTjxtZiVHjmXEo0Uo2m4CBQW1PLJmmUXBzivGkVFfhjKULjwvso3BePfmzy9wP +7YFjVXN9AkEAyxjBXi2kYCcXfGQiNuIrLkyVXeGR2YWnhzS2nL1TjNngmCBbnj48 +qvoqOUQgFK0AeTe/x7lb4Cf24ejWF5vmiwJALensorAkpKWv4qD7IrXy00/7QsAa +uWd3eZXYRq6p8U9mmc5fgyCnNB1pR95CjsqDVza7FhGXipbzepBwffveAQJBAMKc +mxYyqDMW4nNoxDxRJs17xxkpwAdvAiQWB/JTnQ737DX5s7EDtECl7PXo6NDHIhAF +srigToCR6wl4gkYnNpcCQHmlfa9Duf3VJI/XeHE9ZU8vS4qgx0Ikfh01xCqWlsaq +nPRmtfktt4P8gxlryZCEPpRs9l/XwQY6tnpHr5EmV2Y= +-----END RSA PRIVATE KEY----- diff --git a/ACE/examples/IPC_SAP/SSL_SAP/local_data b/ACE/examples/IPC_SAP/SSL_SAP/local_data new file mode 100644 index 00000000000..c0119859a28 --- /dev/null +++ b/ACE/examples/IPC_SAP/SSL_SAP/local_data @@ -0,0 +1 @@ +I am Iron man! diff --git a/ACE/examples/IPC_SAP/SSL_SAP/summarize b/ACE/examples/IPC_SAP/SSL_SAP/summarize new file mode 100755 index 00000000000..ee8ffd2df25 --- /dev/null +++ b/ACE/examples/IPC_SAP/SSL_SAP/summarize @@ -0,0 +1,45 @@ +eval '(exit $?0)' && eval 'exec perl -w -S $0 ${1+"$@"}' + & eval 'exec perl -w -S $0 $argv:q' + if 0; + +# $Id$ +# +# Summarizes results from a series of runs of run_test, with +# different numbers of clients. Example usage: +# +# $ for i in 1 2 5 10 15 20 25 30 35 40 45 50; do ./run_test $i; done +# $ ./summarize +# +# The first three lines above let this script run without specifying the +# full path to perl, as long as it is in the user's PATH. +# Taken from perlrun man page. + +@files = glob 'client-*.log'; +@total_threads = (); + +foreach $file (@files) { + my ($i); + ($i = $file) =~ s/client-(\d+).log/$1/; + push @total_threads, $i; +} + +print "No.of threads\t\tAverage Latency\n\n"; + +foreach $total_threads (sort {$a <=> $b} @total_threads) { + undef $high_latency; + + $high_latency = 0; + open (FILE, "client-${total_threads}.log") || + die "$0: unable to open \"client-${total_threads}.log\"\n"; + while ($line = <FILE>) { + if ($line =~ /.*usec-per-message = ([\d\.]+)/) + { + $high_latency += $1 ; + $number++; + } + } + close FILE; + + printf "%3d\t\t\t%8f\n", + $total_threads, $high_latency/$number; +} diff --git a/ACE/examples/IPC_SAP/TLI_SAP/.cvsignore b/ACE/examples/IPC_SAP/TLI_SAP/.cvsignore new file mode 100644 index 00000000000..db59757e191 --- /dev/null +++ b/ACE/examples/IPC_SAP/TLI_SAP/.cvsignore @@ -0,0 +1,16 @@ +ATM-client +ATM-client +ATM-server +ATM-server +CPP-client +CPP-client +CPP-server +CPP-server +db-client +db-client +db-server +db-server +ftp-client +ftp-client +ftp-server +ftp-server diff --git a/ACE/examples/IPC_SAP/TLI_SAP/CPP-ATM-client.cpp b/ACE/examples/IPC_SAP/TLI_SAP/CPP-ATM-client.cpp new file mode 100644 index 00000000000..6990763a8b0 --- /dev/null +++ b/ACE/examples/IPC_SAP/TLI_SAP/CPP-ATM-client.cpp @@ -0,0 +1,162 @@ +// $Id$ + +#include "ace/TLI_Connector.h" +#include "ace/ATM_QoS.h" +#include "ace/ATM_Addr.h" +#include "ace/Log_Msg.h" + +ACE_RCSID(TLI_SAP, CPP_ATM_client, "$Id$") + +#if defined (ACE_HAS_FORE_ATM_XTI) + +/* ACE_XTI/ATM Client */ + +int main (int argc, char *argv[]) +{ + if (argc < 2) + ACE_ERROR_RETURN ((LM_ERROR, + "Usage: %s [-s selector] hostname [QoS in KB/sec]\n", + argv[0]), + 1); + + unsigned char selector = ACE_ATM_Addr::DEFAULT_SELECTOR; + int selector_specified = 0; + extern int optind; + int opt; + while ((opt = ACE_OS::getopt (argc, argv, "s:?h")) != EOF) + { + switch(opt) + { + case 's': + selector = ACE_OS::atoi (optarg); + selector_specified = 1; + break; + case '?': + case 'h': + ACE_ERROR_RETURN ((LM_ERROR, + "Usage: %s hostname [-s selector] [QoS in KB/s]\n", + argv[0]), + 1); + } // switch + } // while getopt + + const char *host = argv[optind]; + + int rate = (argc == 3) ? ACE_OS::atoi (argv[2]) : + (argc == 5) ? ACE_OS::atoi (argv[4]) : 0; + // The timeout really gets ignored since FORE's drivers don't work when + // ioctl or fcntl calls are made on the transport id/file descriptor + int timeout = ACE_DEFAULT_TIMEOUT; + + char buf[BUFSIZ]; + + ACE_TLI_Stream cli_stream; + + ACE_ATM_Addr remote_addr (host); + if (selector_specified) + remote_addr.set_selector(selector); + char hostname[MAXNAMELEN]; + ACE_OS::hostname(hostname, MAXNAMELEN); + ACE_ATM_Addr local_addr (hostname); + + // In order to construct connections options the file handle is + // needed. Therefore, we need to open the TLI_Stream before we + // construct the options. + if (cli_stream.open (ACE_XTI_ATM_DEVICE, O_RDWR, 0) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "open failed"), + 1); + + ACE_DEBUG ((LM_DEBUG, + "starting non-blocking connect\n")); + + // Initiate timed, non-blocking connection with server. + ACE_TLI_Connector con; + + // Construct QoS options - currently FORE only supports bandwidth + ACE_ATM_QoS qos; + qos.set_rate(cli_stream.get_handle (), + rate, + ACE_ATM_QoS::OPT_FLAGS_CPID); + + struct netbuf optbuf = qos.get_qos(); +// long optlen = 0; +// char *options = remote_addr.construct_options (cli_stream.get_handle (), +// rate, +// ACE_ATM_Addr::OPT_FLAGS_CPID, +// &optlen); +// struct netbuf optbuf; +// optbuf.len = optlen; +// optbuf.buf = options; + + // Not sure why but reuse_addr set to true/1 causes problems for + // FORE/XTI/ATM - this is now handled in ACE_TLI_Connector::connect() + if (con.connect (cli_stream, + remote_addr, + (ACE_Time_Value *) &ACE_Time_Value::zero, + local_addr, + 1, + O_RDWR, + 0, + ACE_XTI_ATM_DEVICE, + 0, + 1, + 0, + &optbuf) == -1) + { + if (errno != EWOULDBLOCK) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "connection failed"), + 1); + + ACE_DEBUG ((LM_DEBUG, + "starting timed connect\n")); + + // Check if non-blocking connection is in progress, and wait up + // to timeout seconds for it to complete. + ACE_Time_Value tv (timeout); + + if (con.complete (cli_stream, + &remote_addr, + &tv) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "connection failed"), + 1); + else + ACE_DEBUG ((LM_DEBUG, + "connected to %s\n", + remote_addr.addr_to_string ())); + } + + // Send data to server (correctly handles "incomplete writes"). + + for (int r_bytes; + (r_bytes = ACE_OS::read (ACE_STDIN, buf, sizeof buf)) > 0; + ) + if (cli_stream.send_n (buf, + r_bytes, + 0) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "send_n"), + 1); + + // Explicitly close the connection. + if (cli_stream.close () == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "close"), + -1); + return 0; +} +#else +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_ERROR_RETURN ((LM_ERROR, + "your platform isn't configured to support XTI/ATM\n"), + 1); +} +#endif /* ACE_HAS_TLI */ diff --git a/ACE/examples/IPC_SAP/TLI_SAP/CPP-ATM-server.cpp b/ACE/examples/IPC_SAP/TLI_SAP/CPP-ATM-server.cpp new file mode 100644 index 00000000000..d4d3dec813c --- /dev/null +++ b/ACE/examples/IPC_SAP/TLI_SAP/CPP-ATM-server.cpp @@ -0,0 +1,114 @@ +// $Id$ + +#include "ace/TLI_Acceptor.h" +#include "ace/ATM_Addr.h" +#include "ace/Log_Msg.h" + +ACE_RCSID(TLI_SAP, CPP_ATM_server, "$Id$") + +#if defined (ACE_HAS_FORE_ATM_XTI) +// ACE_TLI Server + +int +main (int argc, char *argv[]) +{ + ACE_Time_Value timeout (ACE_DEFAULT_TIMEOUT); + + unsigned char selector = ACE_ATM_Addr::DEFAULT_SELECTOR; + int selector_specified = 0; + int opt; + while ((opt = ACE_OS::getopt (argc, argv, "s:?h")) != EOF) + { + switch(opt) + { + case 's': + selector = ACE_OS::atoi (optarg); + selector_specified = 1; + break; + case '?': + case 'h': + ACE_ERROR_RETURN ((LM_ERROR, + "Usage: %s [-s selector]\n", argv[0]), + 1); + } // switch + } // while getopt + + // Create a server address. + ACE_ATM_Addr addr; + if (selector_specified) + addr.set_selector(selector); + + // Create a server, reuse the addr. + ACE_TLI_Acceptor peer_acceptor; + + // Not sure why but reuse_addr set to true/1 causes problems for + // FORE/XTI/ATM - this is now handled in ACE_TLI_Acceptor::open() + if (peer_acceptor.open (addr, + 1, + O_RDWR, + 0, + 5, + ACE_XTI_ATM_DEVICE) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "open"), + -1); + + ACE_TLI_Stream new_stream; + + ACE_DEBUG ((LM_DEBUG, + "starting server at address %s\n", + addr.addr_to_string ())); + + + // Performs the iterative server activities + + for (;;) + { + char buf[BUFSIZ]; + + // Create a new ACE_TLI_Stream endpoint (note automatic restart + // if errno == EINTR). + if (peer_acceptor.accept (new_stream, + &addr, + &timeout) == -1) + { + ACE_ERROR ((LM_ERROR, + "%p\n", + "accept")); + continue; + } + + ACE_DEBUG ((LM_DEBUG, + "client %s connected\n", + addr.addr_to_string ())); + + // Read data from client (terminate on error). + + for (int r_bytes; + (r_bytes = new_stream.recv (buf, sizeof buf, 0)) > 0; ) + if (ACE_OS::write (ACE_STDOUT, + buf, + r_bytes) != r_bytes) + ACE_ERROR ((LM_ERROR, + "%p\n", + "ACE::send_n")); + + // Close new endpoint (listening endpoint stays open). + if (new_stream.close () == -1) + ACE_ERROR ((LM_ERROR, + "%p\n", + "close")); + + } + /* NOTREACHED */ + return 0; +} +#else +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_ERROR_RETURN ((LM_ERROR, + "your platform isn't configured to support XTI/ATM\n"), + 1); +} +#endif /* ACE_HAS_TLI */ diff --git a/ACE/examples/IPC_SAP/TLI_SAP/CPP-client.cpp b/ACE/examples/IPC_SAP/TLI_SAP/CPP-client.cpp new file mode 100644 index 00000000000..550356bba2e --- /dev/null +++ b/ACE/examples/IPC_SAP/TLI_SAP/CPP-client.cpp @@ -0,0 +1,94 @@ +// $Id$ + +#include "ace/TLI_Connector.h" +#include "ace/INET_Addr.h" +#include "ace/Log_Msg.h" +#include "ace/OS_NS_stdlib.h" +#include "ace/OS_NS_unistd.h" +#include "ace/Time_Value.h" + +ACE_RCSID(TLI_SAP, CPP_client, "$Id$") + +#if defined (ACE_HAS_TLI) + +/* ACE_TLI Client */ + +int ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + const ACE_TCHAR *host = argc > 1 ? argv[1] : ACE_DEFAULT_SERVER_HOST; + u_short r_port = argc > 2 ? ACE_OS::atoi (argv[2]) : ACE_DEFAULT_SERVER_PORT; + int timeout = argc > 3 ? ACE_OS::atoi (argv[3]) : ACE_DEFAULT_TIMEOUT; + u_short l_port = argc > 4 ? ACE_OS::atoi (argv[4]) : ACE_DEFAULT_LOCAL_PORT; + + char buf[BUFSIZ]; + + ACE_TLI_Stream cli_stream; + + ACE_INET_Addr remote_addr (r_port, host); + ACE_INET_Addr local_addr (l_port); + + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("starting non-blocking connect\n"))); + + // Initiate timed, non-blocking connection with server. + ACE_TLI_Connector con; + + if (con.connect (cli_stream, + remote_addr, + (ACE_Time_Value *) &ACE_Time_Value::zero, + local_addr, + 1) == -1) + { + if (errno != EWOULDBLOCK) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("connection failed")), + 1); + + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("starting timed connect\n"))); + + // Check if non-blocking connection is in progress, and wait up + // to timeout seconds for it to complete. + ACE_Time_Value tv (timeout); + + if (con.complete (cli_stream, + &remote_addr, + &tv) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("connection failed")), + 1); + else + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("connected to %s\n"), + remote_addr.get_host_name ())); + } + + // Send data to server (correctly handles "incomplete writes"). + + for (int r_bytes; + (r_bytes = ACE_OS::read (ACE_STDIN, buf, sizeof buf)) > 0; + ) + if (cli_stream.send_n (buf, + r_bytes, + 0) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("send_n")), + 1); + + // Explicitly close the connection. + if (cli_stream.close () == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("close")), + -1); + return 0; +} +#else +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("your platform isn't configured to support TLI\n")), + 1); +} +#endif /* ACE_HAS_TLI */ diff --git a/ACE/examples/IPC_SAP/TLI_SAP/CPP-server.cpp b/ACE/examples/IPC_SAP/TLI_SAP/CPP-server.cpp new file mode 100644 index 00000000000..4ed8c0bf643 --- /dev/null +++ b/ACE/examples/IPC_SAP/TLI_SAP/CPP-server.cpp @@ -0,0 +1,89 @@ +// $Id$ + +#include "ace/TLI_Acceptor.h" +#include "ace/Log_Msg.h" +#include "ace/OS_NS_stdlib.h" +#include "ace/OS_NS_unistd.h" + +ACE_RCSID(TLI_SAP, CPP_server, "$Id$") + +#if defined (ACE_HAS_TLI) +// ACE_TLI Server + +int +main (int argc, char *argv[]) +{ + u_short port = argc > 1 ? ACE_OS::atoi (argv[1]) : ACE_DEFAULT_SERVER_PORT; + ACE_Time_Value timeout (argc > 2 ? ACE_OS::atoi (argv[2]) : ACE_DEFAULT_TIMEOUT); + + // Create a server address. + ACE_INET_Addr addr (port); + + // Create a server, reuse the addr. + ACE_TLI_Acceptor peer_acceptor; + + // Not sure why but reuse_addr set to true/1 causes problems for + // FORE/XTI/ATM - this is now handled in ACE_TLI_Acceptor::open() + if (peer_acceptor.open (addr, 1) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "open"), + -1); + + ACE_TLI_Stream new_stream; + + ACE_DEBUG ((LM_DEBUG, + "starting server at host %s\n", + addr.get_host_name ())); + + // Performs the iterative server activities + + for (;;) + { + char buf[BUFSIZ]; + + // Create a new ACE_TLI_Stream endpoint (note automatic restart + // if errno == EINTR). + if (peer_acceptor.accept (new_stream, + &addr, + &timeout) == -1) + { + ACE_ERROR ((LM_ERROR, + "%p\n", + "accept")); + continue; + } + + ACE_DEBUG ((LM_DEBUG, + "client %s connected\n", + addr.get_host_name ())); + + // Read data from client (terminate on error). + + for (int r_bytes; + (r_bytes = new_stream.recv (buf, sizeof buf)) > 0; ) + if (ACE_OS::write (ACE_STDOUT, + buf, + r_bytes) != r_bytes) + ACE_ERROR ((LM_ERROR, + "%p\n", + "ACE::send_n")); + + // Close new endpoint (listening endpoint stays open). + if (new_stream.close () == -1) + ACE_ERROR ((LM_ERROR, + "%p\n", + "close")); + + } + /* NOTREACHED */ + return 0; +} +#else +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_ERROR_RETURN ((LM_ERROR, + "your platform isn't configured to support TLI\n"), + 1); +} +#endif /* ACE_HAS_TLI */ diff --git a/ACE/examples/IPC_SAP/TLI_SAP/Makefile.am b/ACE/examples/IPC_SAP/TLI_SAP/Makefile.am new file mode 100644 index 00000000000..80b48222d22 --- /dev/null +++ b/ACE/examples/IPC_SAP/TLI_SAP/Makefile.am @@ -0,0 +1,124 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +ACE_BUILDDIR = $(top_builddir) +ACE_ROOT = $(top_srcdir) + +## Makefile.TLI_SAP_ATM_Client.am +noinst_PROGRAMS = ATM-client + +ATM_client_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +ATM_client_SOURCES = \ + CPP-ATM-client.cpp + +ATM_client_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.TLI_SAP_ATM_Server.am +noinst_PROGRAMS += ATM-server + +ATM_server_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +ATM_server_SOURCES = \ + CPP-ATM-server.cpp + +ATM_server_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.TLI_SAP_CPP_Client.am +noinst_PROGRAMS += CPP-client + +CPP_client_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +CPP_client_SOURCES = \ + CPP-client.cpp + +CPP_client_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.TLI_SAP_CPP_Server.am +noinst_PROGRAMS += CPP-server + +CPP_server_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +CPP_server_SOURCES = \ + CPP-server.cpp + +CPP_server_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.TLI_SAP_Db_Client.am +noinst_PROGRAMS += db-client + +db_client_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +db_client_SOURCES = \ + db-client.cpp + +db_client_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.TLI_SAP_Db_Server.am +noinst_PROGRAMS += db-server + +db_server_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +db_server_SOURCES = \ + db-server.cpp + +db_server_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.TLI_SAP_Ftp_Client.am +noinst_PROGRAMS += ftp-client + +ftp_client_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +ftp_client_SOURCES = \ + ftp-client.cpp + +ftp_client_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.TLI_SAP_Ftp_Server.am +noinst_PROGRAMS += ftp-server + +ftp_server_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +ftp_server_SOURCES = \ + ftp-server.cpp + +ftp_server_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Clean up template repositories, etc. +clean-local: + -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.* + -rm -f gcctemp.c gcctemp so_locations *.ics + -rm -rf cxx_repository ptrepository ti_files + -rm -rf templateregistry ir.out + -rm -rf ptrepository SunWS_cache Templates.DB diff --git a/ACE/examples/IPC_SAP/TLI_SAP/TLI_SAP.mpc b/ACE/examples/IPC_SAP/TLI_SAP/TLI_SAP.mpc new file mode 100644 index 00000000000..0fe9b1aa17b --- /dev/null +++ b/ACE/examples/IPC_SAP/TLI_SAP/TLI_SAP.mpc @@ -0,0 +1,58 @@ +// -*- MPC -*- +// $Id$ + +project(*ATM_client) : aceexe { + exename = ATM-client + Source_Files { + CPP-ATM-client.cpp + } +} + +project(*ATM_server) : aceexe { + exename = ATM-server + Source_Files { + CPP-ATM-server.cpp + } +} + +project(*CPP_client) : aceexe { + exename = CPP-client + Source_Files { + CPP-client.cpp + } +} + +project(*CPP_server) : aceexe { + exename = CPP-server + Source_Files { + CPP-server.cpp + } +} + +project(*db_client) : aceexe { + exename = db-client + Source_Files { + db-client.cpp + } +} + +project(*db_server) : aceexe { + exename = db-server + Source_Files { + db-server.cpp + } +} + +project(*ftp_client) : aceexe { + exename = ftp-client + Source_Files { + ftp-client.cpp + } +} + +project(*ftp_server) : aceexe { + exename = ftp-server + Source_Files { + ftp-server.cpp + } +} diff --git a/ACE/examples/IPC_SAP/TLI_SAP/db-client.cpp b/ACE/examples/IPC_SAP/TLI_SAP/db-client.cpp new file mode 100644 index 00000000000..6136d0ae4c5 --- /dev/null +++ b/ACE/examples/IPC_SAP/TLI_SAP/db-client.cpp @@ -0,0 +1,60 @@ +// $Id$ + +#include "ace/TLI_Connector.h" +#include "ace/Log_Msg.h" +#include "ace/OS_NS_stdio.h" +#include "ace/OS_NS_stdlib.h" +#include "ace/OS_NS_string.h" + +ACE_RCSID(TLI_SAP, db_client, "$Id$") + +#if defined (ACE_HAS_TLI) +const int MAXLINE = 255; + +int ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + if (argc < 2) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("Usage: %s employee_id [server-host port-number]\n"), + argv[0]), + -1); + + const ACE_TCHAR *emp_num = argv[1]; + const ACE_TCHAR *host_name = argc < 3 ? ACE_DEFAULT_SERVER_HOST : argv[2]; + unsigned short port = argc < 4 ? ACE_DEFAULT_SERVER_PORT : ACE_OS::atoi (argv[3]); + int n; + char buf[MAXLINE]; + + ACE_TLI_Stream client; + ACE_TLI_Connector con; + + if (con.connect (client, ACE_INET_Addr (port, host_name)) == -1) + ACE_OS::t_error ((char *) host_name), ACE_OS::exit (1); + + ACE_OS::strcpy (buf, ACE_TEXT_ALWAYS_CHAR (emp_num)); + n = ACE_OS::strlen (buf); + + if (client.send_n (buf, n) != n) + ACE_OS::t_error ("client.send error"); + + if (client.recv (buf, MAXLINE) == -1 && t_errno != TLOOK && client.look () != T_DISCONNECT) + ACE_OS::t_error ("client.recv error"); + + if (ACE_OS::strcmp (buf, "ERROR") == 0) + ACE_OS::printf ("Employee ID %s not in database\n", emp_num); + else + ACE_OS::printf ("Employee name requested is: %s\n", buf); + + if (client.close () == -1) + ACE_OS::t_error ("cli_close"), ACE_OS::exit (1); + + return 0; +} +#else +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_ERROR_RETURN ((LM_ERROR, + "your platform isn't configured to support TLI\n"), + 1); +} +#endif /* ACE_HAS_TLI */ diff --git a/ACE/examples/IPC_SAP/TLI_SAP/db-server.cpp b/ACE/examples/IPC_SAP/TLI_SAP/db-server.cpp new file mode 100644 index 00000000000..145c4a13ad0 --- /dev/null +++ b/ACE/examples/IPC_SAP/TLI_SAP/db-server.cpp @@ -0,0 +1,121 @@ +// $Id$ + +// Simple multi-threaded database server example. + +#include "ace/OS_NS_stdio.h" +#include "ace/TLI_Acceptor.h" +#include "ace/Thread_Manager.h" + +ACE_RCSID(TLI_SAP, db_server, "$Id$") + +#if defined (ACE_HAS_THREADS) && defined (ACE_HAS_TLI) + +// Global thread manager. +ACE_Thread_Manager thr_mgr; + +void * +lookup_name (ACE_HANDLE handle) +{ + enum + { + MAXLINE = 255, + EMPNAMELEN = 512 + }; + + static struct + { + int emp_id; + const char *emp_name; + } employee_db[] = + { + {123, "John Wayne Bobbit"}, + {124, "Woody Allen"}, + {125, "O. J. Simpson"}, + {126, "Bill Clinton"}, + {127, "Rush Limbaugh"}, + {128, "Michael Jackson"}, + {129, "Kenneth Starr"}, + {130, "Paula Jones"}, + {131, "Monica Lewinsky"}, + {132, "Marv Albert"}, + {0, ""} + }; + + int flags; + int employee_id; + int index; + int found; + ACE_TLI_Stream stream; + char recvline[MAXLINE]; + char sendline[MAXLINE]; + + ACE_DEBUG ((LM_DEBUG, + "stream handle = %d, thread id = %t\n", + handle)); + stream.set_handle (handle); + + ssize_t n = stream.recv (recvline, MAXLINE, &flags); + + if (n == -1) + ACE_OS::t_error ("stream.recv error"); + + employee_id = ACE_OS::atoi (recvline); + found = 0; + + for (index = 0; found == 0 && employee_db[index].emp_id; index++) + if (employee_id == employee_db[index].emp_id) + { + found = 1; + n = ACE_OS::sprintf (sendline, + "%s", employee_db[index].emp_name); + } + + if (found == 0) + n = ACE_OS::sprintf (sendline, "%s", "ERROR"); + + if (stream.send (sendline, n + 1, 0) == -1) + ACE_OS::t_error ("stream.send error"); + + if (stream.sndrel () == -1) + ACE_OS::t_error ("stream.send error"); + + if (stream.close () == -1) + ACE_OS::t_error ("stream.close error"); + + return 0; +} + +int +main (int argc, char *argv[]) +{ + u_short port = argc > 1 ? ACE_OS::atoi (argv[1]) : ACE_DEFAULT_SERVER_PORT; + ACE_INET_Addr l_addr (port); + ACE_TLI_Acceptor server (l_addr, 1); // Create server, reuse addr if in use. + ACE_TLI_Stream new_stream; + + // Wait for a connection from a client. This is an example of a + // concurrent server. + + for (;;) + { + if (server.accept (new_stream) == -1) + ACE_OS::t_error ("server.accept error"); + + if (thr_mgr.spawn (ACE_THR_FUNC (lookup_name), + (void *) new_stream.get_handle (), + THR_DETACHED) == -1) + ACE_DEBUG ((LM_ERROR, + "server: can't create worker thread %d\n")); + } + + ACE_NOTREACHED (return 0); +} +#else +#include <stdio.h> +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_ERROR_RETURN ((LM_ERROR, + "platform isn't configured to support TLI\n"), + 1); +} +#endif /* ACE_HAS_THREADS */ diff --git a/ACE/examples/IPC_SAP/TLI_SAP/ftp-client.cpp b/ACE/examples/IPC_SAP/TLI_SAP/ftp-client.cpp new file mode 100644 index 00000000000..c783e0aba55 --- /dev/null +++ b/ACE/examples/IPC_SAP/TLI_SAP/ftp-client.cpp @@ -0,0 +1,54 @@ +// $Id$ + +#include "ace/TLI_Connector.h" +#include "ace/Log_Msg.h" +#include "ace/OS_NS_fcntl.h" +#include "ace/OS_NS_stdio.h" +#include "ace/OS_NS_stdlib.h" +#include "ace/OS_NS_unistd.h" + +ACE_RCSID(TLI_SAP, ftp_client, "$Id$") + +#if defined (ACE_HAS_TLI) + +int ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + if (argc < 2) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("Usage: %s filename ") + ACE_TEXT ("[server-host port-number]\n"), + argv[0]), + 1); + + const ACE_TCHAR *filename = argv[1]; + const ACE_TCHAR *host_name = argc < 3 ? ACE_DEFAULT_SERVER_HOST : argv[2]; + u_short port = argc < 4 ? ACE_DEFAULT_SERVER_PORT : ACE_OS::atoi (argv[3]); + + ACE_TLI_Stream client; + ACE_TLI_Connector con; + int fd; + char buf[BUFSIZ]; + + if (con.connect (client, ACE_INET_Addr (port, host_name)) == -1) + ACE_OS::t_error ((char *) host_name), ACE_OS::exit (1); + + if ((fd = ACE_OS::open (filename, O_RDONLY)) == -1) + ACE_OS::perror (filename), ACE_OS::exit (1); + + for (int n; (n = ACE_OS::read (fd, buf, sizeof buf)) > 0; ) + if (client.send_n (buf, n) != n) + ACE_OS::t_error ("client.send error"); + + if (client.close () == -1) + ACE_OS::t_error ("cli_close"), ACE_OS::exit (1); + + return 0; +} +#else +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("your platform isn't configured to support TLI\n")), + 1); +} +#endif /* ACE_HAS_TLI */ diff --git a/ACE/examples/IPC_SAP/TLI_SAP/ftp-server.cpp b/ACE/examples/IPC_SAP/TLI_SAP/ftp-server.cpp new file mode 100644 index 00000000000..23596a84dd4 --- /dev/null +++ b/ACE/examples/IPC_SAP/TLI_SAP/ftp-server.cpp @@ -0,0 +1,83 @@ +// $Id$ + +// Simple file transfer example + +#include "ace/OS_NS_stdio.h" +#include "ace/Thread_Manager.h" +#include "ace/TLI_Acceptor.h" + +ACE_RCSID(TLI_SAP, ftp_server, "$Id$") + +#if defined (ACE_HAS_THREADS) && defined (ACE_HAS_TLI) + +ACE_Thread_Manager thr_mgr; + +void * +read_file (void *fd) +{ + ACE_TLI_Stream stream; + char buf[BUFSIZ]; + int flags = 0; + ssize_t n; + + // Cast the arg to a long, first, because a pointer is the same size + // as a long on all current ACE platforms. + stream.set_handle ((int) (long) fd); + + ACE_DEBUG((LM_DEBUG, "start (tid = %t, fd = %d)\n", + stream.get_handle ())); + + while ((n = stream.recv (buf, sizeof buf, &flags)) > 0) + continue; + + ACE_UNUSED_ARG (n); + + ACE_DEBUG ((LM_DEBUG,"finish (tid = %t, fd = %d)\n", + stream.get_handle ())); + + if (stream.close () == -1) + ACE_OS::t_error ("stream.close error"); + + return 0; +} + +int +main (int argc, char *argv[]) +{ + u_short port = argc > 1 ? ACE_OS::atoi (argv[1]) : ACE_DEFAULT_SERVER_PORT; + ACE_TLI_Acceptor server; + ACE_TLI_Stream new_stream; + + // Open the server and reuse the address if in use... + if (server.open (ACE_INET_Addr (port), 1) == -1) + ACE_OS::t_error ("server.open"), ACE_OS::exit (1); + + // Wait for a connection from a client. This is an example of a + // concurrent server. + + for (int count = 1; ; count++) + { + ACE_DEBUG ((LM_DEBUG, + "thread %t, blocking for accept #%d\n", + count)); + + if (server.accept (new_stream) == -1) + ACE_OS::t_error ("server.accept error"); + + else if (thr_mgr.spawn (ACE_THR_FUNC (read_file), + (void *) new_stream.get_handle (), + THR_DETACHED | THR_BOUND) == -1) + ACE_OS::perror ("can't create worker thread\n"); + } + + ACE_NOTREACHED (return 0); +} +#else +#include <stdio.h> +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_ERROR_RETURN ((LM_ERROR, + "your platform isn't configured to support TLI\n"), + 1); +} +#endif /* ACE_HAS_THREADS */ diff --git a/ACE/examples/IPC_SAP/UPIPE_SAP/.cvsignore b/ACE/examples/IPC_SAP/UPIPE_SAP/.cvsignore new file mode 100644 index 00000000000..66a3e2ba941 --- /dev/null +++ b/ACE/examples/IPC_SAP/UPIPE_SAP/.cvsignore @@ -0,0 +1,6 @@ +ex1 +ex1 +ex2 +ex2 +ex3 +ex3 diff --git a/ACE/examples/IPC_SAP/UPIPE_SAP/Makefile.am b/ACE/examples/IPC_SAP/UPIPE_SAP/Makefile.am new file mode 100644 index 00000000000..60054e3c7c0 --- /dev/null +++ b/ACE/examples/IPC_SAP/UPIPE_SAP/Makefile.am @@ -0,0 +1,73 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +ACE_BUILDDIR = $(top_builddir) +ACE_ROOT = $(top_srcdir) + +noinst_PROGRAMS = + +## Makefile.UPIPE_SAP_Ex1.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS += ex1 + +ex1_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +ex1_SOURCES = \ + ex1.cpp + +ex1_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Makefile.UPIPE_SAP_Ex2.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS += ex2 + +ex2_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +ex2_SOURCES = \ + ex2.cpp + +ex2_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Makefile.UPIPE_SAP_Ex3.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS += ex3 + +ex3_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +ex3_SOURCES = \ + ex3.cpp + +ex3_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Clean up template repositories, etc. +clean-local: + -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.* + -rm -f gcctemp.c gcctemp so_locations *.ics + -rm -rf cxx_repository ptrepository ti_files + -rm -rf templateregistry ir.out + -rm -rf ptrepository SunWS_cache Templates.DB diff --git a/ACE/examples/IPC_SAP/UPIPE_SAP/UPIPE_SAP.mpc b/ACE/examples/IPC_SAP/UPIPE_SAP/UPIPE_SAP.mpc new file mode 100644 index 00000000000..d34d8671735 --- /dev/null +++ b/ACE/examples/IPC_SAP/UPIPE_SAP/UPIPE_SAP.mpc @@ -0,0 +1,26 @@ +// -*- MPC -*- +// $Id$ + +project(*ex1) : aceexe { + avoids += ace_for_tao + exename = ex1 + Source_Files { + ex1.cpp + } +} + +project(*ex2) : aceexe { + avoids += ace_for_tao + exename = ex2 + Source_Files { + ex2.cpp + } +} + +project(*ex3) : aceexe { + avoids += ace_for_tao + exename = ex3 + Source_Files { + ex3.cpp + } +} diff --git a/ACE/examples/IPC_SAP/UPIPE_SAP/ex1.cpp b/ACE/examples/IPC_SAP/UPIPE_SAP/ex1.cpp new file mode 100644 index 00000000000..39ad86d5819 --- /dev/null +++ b/ACE/examples/IPC_SAP/UPIPE_SAP/ex1.cpp @@ -0,0 +1,183 @@ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// examples +// +// = FILENAME +// ex1.cpp +// +// = DESCRIPTION +// Example for using <ACE_UPIPE_SAP> and <ACE_Thread> for +// intra-process communication. +// +// = AUTHOR +// Gerhard Lenzer and Douglas C. Schmidt +// +// ============================================================================ + +#include "ace/OS_main.h" +#include "ace/OS_NS_string.h" +#include "ace/Stream.h" +#include "ace/UPIPE_Acceptor.h" +#include "ace/UPIPE_Connector.h" + +ACE_RCSID(UPIPE_SAP, ex1, "$Id$") + +#if defined (ACE_HAS_THREADS) + +// Global pattern +static ACE_UPIPE_Addr addr (ACE_TEXT("pattern")); + +// peer1 thread entry point. + +static void * +peer1 (void *) +{ + ACE_UPIPE_Stream c_stream; + + ACE_DEBUG ((LM_DEBUG, + "(%t) peer1 starting connect\n")); + ACE_UPIPE_Connector con; + + if (con.connect (c_stream, addr) == -1) + ACE_ERROR ((LM_ERROR, + "(%t) peer1 ACE_UPIPE_Connector failed\n")); + + ACE_Message_Block *mb; + ACE_NEW_RETURN (mb, + ACE_Message_Block (20), + 0); + + mb->copy ("hello", 6); + + if (c_stream.send (mb) == -1) + ACE_ERROR ((LM_ERROR, + "(%t) error peer1 send\n")); + + if (c_stream.recv (mb) == -1) + ACE_ERROR ((LM_ERROR, + "(%t) error peer1 recv\n")); + + ACE_ERROR ((LM_ERROR, + "(%t) peer1 ack is \"%s\"\n", + mb->rd_ptr ())); + + // Free up the memory block. + mb->release (); + + // Now try the send()/recv() interface. + char mytext[] = "This string is sent by peer1 as buffer"; + + ACE_ERROR ((LM_ERROR, + "(%t) peer1 sending text\n")); + if (c_stream.send (mytext, sizeof mytext) == -1) + ACE_ERROR ((LM_ERROR, + "(%t) buffer send from peer1 failed\n")); + + char conbuf[30]; // Buffer to receive response. + + int i = 0; + + for (char c = ' '; c != '!'; i++) + { + if (c_stream.recv (&c, 1) == -1) + ACE_ERROR ((LM_ERROR, + "(%t) buffer recv from peer1 failed\n")); + else + conbuf[i] = c; + } + + conbuf[i] = '\0'; + ACE_DEBUG ((LM_DEBUG, + "(%t) peer1 received buffer with \"%s\"\n", + conbuf)); + c_stream.close (); + return 0; +} + +static void * +peer2 (void *) +{ + ACE_UPIPE_Acceptor acc (addr); + ACE_UPIPE_Stream s_stream; + + // Spawn a peer1 thread. + if (ACE_Thread_Manager::instance ()->spawn (ACE_THR_FUNC (peer1), + (void *) 0, + THR_NEW_LWP | THR_DETACHED) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "spawn"), + 0); + + ACE_DEBUG ((LM_DEBUG, + "(%t) peer2 starting accept\n")); + + if (acc.accept (s_stream) == -1) + ACE_ERROR ((LM_ERROR, + "(%t) ACE_UPIPE_Acceptor.accept failed\n")); + + ACE_Message_Block *mb = 0; + + if (s_stream.recv (mb) == -1) + ACE_ERROR ((LM_ERROR, + "(%t) peer2 recv failed\n")); + + ACE_DEBUG ((LM_DEBUG, "(%t) peer2 recv is \"%s\"\n", + mb->rd_ptr ())); + + mb->wr_ptr (mb->rd_ptr ()); + mb->copy ("thanks", 7); + + if (s_stream.send (mb) == -1) + ACE_ERROR ((LM_ERROR, + "(%t) peer2 send failed\n")); + + char s_buf[42]; + ACE_DEBUG ((LM_DEBUG, + "(%t) peer2 sleeping on recv\n")); + + if (s_stream.recv (s_buf, sizeof s_buf) == -1) + ACE_ERROR ((LM_ERROR, + "(%t) peer2 recv failed\n")); + else + ACE_DEBUG ((LM_DEBUG, + "(%t) peer2 received buffer with \"%s\"\n", + s_buf)); + + ACE_OS::strcpy (s_buf, + "this is the peer2 response!"); + + if (s_stream.send (s_buf, 30) == -1) + ACE_ERROR ((LM_ERROR, + "(%t) peer2 send failed\n")); + s_stream.close (); + return 0; +} + +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + // Spawn a peer2 thread. + if (ACE_Thread_Manager::instance ()->spawn (ACE_THR_FUNC (peer2), + (void *) 0, + THR_NEW_LWP | THR_DETACHED) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "spawn"), + 1); + // Wait for peer2 and peer1 threads to exit. + ACE_Thread_Manager::instance ()->wait (); + return 0; +} +#else +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_ERROR_RETURN ((LM_ERROR, + "threads not supported on this platform\n"), + -1); +} +#endif /* ACE_HAS_THREADS */ diff --git a/ACE/examples/IPC_SAP/UPIPE_SAP/ex2.cpp b/ACE/examples/IPC_SAP/UPIPE_SAP/ex2.cpp new file mode 100644 index 00000000000..e19a83460ce --- /dev/null +++ b/ACE/examples/IPC_SAP/UPIPE_SAP/ex2.cpp @@ -0,0 +1,179 @@ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// examples +// +// = FILENAME +// ex2.cpp +// +// = DESCRIPTION +// Example for using <ACE_UPIPE_SAP> and <ACE_Thread> for +// intra-process communication. +// +// = AUTHOR +// Gerhard Lenzer and Douglas C. Schmidt +// +// ============================================================================ + +#include "ace/OS_main.h" +#include "ace/UPIPE_Connector.h" +#include "ace/UPIPE_Acceptor.h" +#include "ace/Auto_Ptr.h" +#include "ace/OS_NS_time.h" + +ACE_RCSID(UPIPE_SAP, ex2, "$Id$") + +#if defined (ACE_HAS_THREADS) + +// Data for testsuite. +static int size = 0; +static int iterations = 0; + +static void * +supplier (void *) +{ + ACE_UPIPE_Stream s_stream; + + ACE_UPIPE_Addr c_addr (ACE_TEXT("pattern")); + + ACE_Auto_Basic_Array_Ptr<char> mybuf (new char[size]); + + for (int i = 0; i < size; i++) + mybuf[i] = 'a'; + + ACE_DEBUG ((LM_DEBUG, + "(%t) supplier starting connect thread\n")); + + ACE_UPIPE_Connector con; + + if (con.connect (s_stream, c_addr) == -1) + ACE_ERROR ((LM_ERROR, + "(%t) %p\n", + "ACE_UPIPE_Acceptor.connect failed")); + + // Test asynchronicity (the "acausal principle" ;-)). + s_stream.enable (ACE_SIGIO); + + ACE_Message_Block *mb_p; + + for (int j = 0; j < iterations; j++) + { + ACE_NEW_RETURN (mb_p, + ACE_Message_Block (size, + ACE_Message_Block::MB_DATA, + (ACE_Message_Block *) 0, + mybuf.get ()), + 0); + if (s_stream.send (mb_p) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "(%t) %p\n", + "send failed"), + 0); + } + + ACE_NEW_RETURN (mb_p, + ACE_Message_Block ((size_t) 0), + 0); + + // Insert a 0-sized message block to signal the other side to shut + // down. + if (s_stream.send (mb_p) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "(%t) %p\n", + "send failed"), + 0); + s_stream.close (); + return 0; +} + +static void * +consumer (void *) +{ + ACE_UPIPE_Stream c_stream; + + // Set the high water mark to size to achieve optimum performance. + + int wm = size * iterations; + + if (c_stream.control (ACE_IO_Cntl_Msg::SET_HWM, + &wm) == -1) + ACE_DEBUG ((LM_DEBUG, + "set HWM failed\n")); + + ACE_UPIPE_Addr serv_addr (ACE_TEXT("pattern")); + + // accept will wait up to 4 seconds + ACE_UPIPE_Acceptor acc (serv_addr); + + ACE_DEBUG ((LM_DEBUG, + "(%t) consumer spawning the supplier thread\n")); + + // Spawn the supplier thread. + if (ACE_Thread_Manager::instance ()->spawn (ACE_THR_FUNC (supplier), + (void *) 0, + THR_NEW_LWP | THR_DETACHED) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "spawn"), + 0); + + ACE_DEBUG ((LM_DEBUG, + "(%t) consumer starting accept\n")); + + if (acc.accept (c_stream) == -1) + ACE_ERROR ((LM_ERROR, + "(%t) %p\n", + "ACE_UPIPE_Acceptor.accept failed")); + + // Time measurement. + time_t currsec; + ACE_OS::time (&currsec); + time_t start = (time_t) currsec; + + int received_messages = 0; + + for (ACE_Message_Block *mb = 0; + c_stream.recv (mb) != -1 && mb->size () != 0; + mb->release ()) + received_messages++; + + ACE_OS::time (&currsec); + time_t secs = (time_t) currsec - start; + + ACE_DEBUG ((LM_DEBUG, + "(%t) Transferred %d blocks of size %d\n" + "The program ran %d seconds\n", + received_messages, size, secs)); + c_stream.close (); + return 0; +} + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + size = argc > 1 ? ACE_OS::atoi (argv[1]) : 32; + iterations = argc > 2 ? ACE_OS::atoi (argv[2]) : 16; + + // Spawn the two threads. + if (ACE_Thread_Manager::instance ()->spawn (ACE_THR_FUNC (consumer), + (void *) 0, + THR_NEW_LWP | THR_DETACHED) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "spawn"), + 1); + // Wait for producer and consumer threads to exit. + ACE_Thread_Manager::instance ()->wait (); + return 0; +} +#else +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_ERROR_RETURN ((LM_ERROR, + "threads not supported on this platform\n"), + 0); +} +#endif /* ACE_HAS_THREADS */ diff --git a/ACE/examples/IPC_SAP/UPIPE_SAP/ex3.cpp b/ACE/examples/IPC_SAP/UPIPE_SAP/ex3.cpp new file mode 100644 index 00000000000..57ff4f34d9e --- /dev/null +++ b/ACE/examples/IPC_SAP/UPIPE_SAP/ex3.cpp @@ -0,0 +1,159 @@ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// examples +// +// = FILENAME +// ex3.cpp +// +// = DESCRIPTION +// Example for using <ACE_UPIPE_SAP> and <ACE_Thread> for intra-process +// communication. This example uses char buffers as input/output +// interface to the <ACE_UPIPE_Stream>. +// +// = AUTHOR +// Gerhard Lenzer and Prashant Jain. +// +// ============================================================================ + +#include "ace/OS_main.h" +#include "ace/UPIPE_Connector.h" +#include "ace/UPIPE_Acceptor.h" +#include "ace/Auto_Ptr.h" +#include "ace/OS_NS_time.h" + +ACE_RCSID(UPIPE_SAP, ex3, "$Id$") + +#if defined (ACE_HAS_THREADS) + +// Data for testsuite. +static int size = 0; +static int iterations = 0; + +static void * +supplier (void *) +{ + ACE_UPIPE_Stream s_stream; + ACE_UPIPE_Addr c_addr (ACE_TEXT("pattern")); + + ACE_UPIPE_Connector con; + + ACE_DEBUG ((LM_DEBUG, + "(%t) supplier starting connect thread\n")); + + if (con.connect (s_stream, c_addr) == -1) + ACE_ERROR ((LM_ERROR, + "(%t) %p\n", + "ACE_UPIPE_Acceptor.connect failed")); + + ACE_Auto_Basic_Array_Ptr<char> mybuf (new char[size]); + + for (int i = 0; i < size; i++) + mybuf[i] = 'a'; + + for (int j = 0; j < iterations; j++) + if (s_stream.send (mybuf.get (), size) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "(%t) %p\n", "send failed"), + 0); + + // Insert a 0-sized message block to signal the other side to shut + // down. + if (s_stream.send (new ACE_Message_Block ((size_t) 0)) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "(%t) %p\n", "error put"), + 0); + s_stream.close (); + return 0; +} + +static void * +consumer (void *) +{ + ACE_UPIPE_Stream c_stream; + ACE_UPIPE_Addr serv_addr (ACE_TEXT("pattern")); + + // Accept will wait up to 4 seconds + ACE_UPIPE_Acceptor acc (serv_addr); + + ACE_DEBUG ((LM_DEBUG, + "(%t) consumer spawning the supplier thread\n")); + + // Spawn the supplier thread. + if (ACE_Thread_Manager::instance ()->spawn (ACE_THR_FUNC (supplier), + (void *) 0, + THR_NEW_LWP | THR_DETACHED) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "spawn"), + 0); + ACE_DEBUG ((LM_DEBUG, + "(%t) consumer starting accept\n")); + + if (acc.accept (c_stream) == -1) + ACE_ERROR ((LM_ERROR, "(%t) %p\n", + "ACE_UPIPE_Acceptor.accept failed")); + + // Ensure deletion upon exit. + ACE_Auto_Basic_Array_Ptr<char> mybuf (new char[size]); + time_t currsec; + + ACE_OS::time (&currsec); + + time_t start = (time_t) currsec; + int result = 0; + int blocks = 0; + + for (;; blocks++) + { + result = c_stream.recv (mybuf.get (), size); + if (result <= 0) + break; + } + + if (result == -1) + ACE_ERROR ((LM_ERROR, + "(%t) %p\n", "recv failed")); + + ACE_OS::time (&currsec); + time_t secs = (time_t) currsec - start; + + ACE_DEBUG ((LM_DEBUG, + "(%t) Transferred %d blocks of size %d\n" + "The program ran %d seconds\n", + blocks, + size, + secs)); + c_stream.close (); + return 0; +} + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + size = argc > 1 ? ACE_OS::atoi (argv[1]) : 32; + iterations = argc > 2 ? ACE_OS::atoi (argv[2]) : 16; + + // Spawn the thread. + if (ACE_Thread_Manager::instance ()->spawn (ACE_THR_FUNC (consumer), + (void *) 0, + THR_NEW_LWP | THR_DETACHED) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "spawn"), + 1); + // Wait for producer and consumer threads to exit. + ACE_Thread_Manager::instance ()->wait (); + return 0; +} +#else +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_ERROR_RETURN ((LM_ERROR, + "threads not supported on this platform\n"), + 0); +} +#endif /* ACE_HAS_THREADS */ diff --git a/ACE/examples/Log_Msg/.cvsignore b/ACE/examples/Log_Msg/.cvsignore new file mode 100644 index 00000000000..c4e57879139 --- /dev/null +++ b/ACE/examples/Log_Msg/.cvsignore @@ -0,0 +1,6 @@ +test_callback +test_callback +test_log_msg +test_log_msg +test_ostream +test_ostream diff --git a/ACE/examples/Log_Msg/Log_Msg.mpc b/ACE/examples/Log_Msg/Log_Msg.mpc new file mode 100644 index 00000000000..0c7b0f67563 --- /dev/null +++ b/ACE/examples/Log_Msg/Log_Msg.mpc @@ -0,0 +1,23 @@ +// -*- MPC -*- +// $Id$ + +project(*test_log_msg) : aceexe { + exename = test_log_msg + Source_Files { + test_log_msg.cpp + } +} + +project(*test_ostream) : aceexe { + exename = test_ostream + Source_Files { + test_ostream.cpp + } +} + +project(*test_callback) : aceexe { + exename = test_callback + Source_Files { + test_callback.cpp + } +} diff --git a/ACE/examples/Log_Msg/Log_Msg_MFC/Log_Msg_MFC.cpp b/ACE/examples/Log_Msg/Log_Msg_MFC/Log_Msg_MFC.cpp new file mode 100644 index 00000000000..5aa9c95f0d4 --- /dev/null +++ b/ACE/examples/Log_Msg/Log_Msg_MFC/Log_Msg_MFC.cpp @@ -0,0 +1,90 @@ +// Log_Msg_MFC.cpp : Defines the class behaviors for the application. +// $Id$ + +#include "ace/Log_Msg.h" +#include "Log_Msg_MFC.h" + +#if defined (ACE_WIN32) + +#include "stdafx.h" +#include "Log_Msg_MFCDlg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +#include <ace/ACE.h> + +///////////////////////////////////////////////////////////////////////////// +// CLog_Msg_MFCApp + +BEGIN_MESSAGE_MAP(CLog_Msg_MFCApp, CWinApp) + //{{AFX_MSG_MAP(CLog_Msg_MFCApp) + // NOTE - the ClassWizard will add and remove mapping macros here. + // DO NOT EDIT what you see in these blocks of generated code! + //}}AFX_MSG + ON_COMMAND(ID_HELP, CWinApp::OnHelp) +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CLog_Msg_MFCApp construction + +CLog_Msg_MFCApp::CLog_Msg_MFCApp() +{ + // TODO: add construction code here, + // Place all significant initialization in InitInstance +} + +///////////////////////////////////////////////////////////////////////////// +// The one and only CLog_Msg_MFCApp object + +CLog_Msg_MFCApp theApp; + +///////////////////////////////////////////////////////////////////////////// +// CLog_Msg_MFCApp initialization + +BOOL CLog_Msg_MFCApp::InitInstance() +{ + // Standard initialization + // If you are not using these features and wish to reduce the size + // of your final executable, you should remove from the following + // the specific initialization routines you do not need. + + // Need to call ACE::init() before calling any functions in ACE. + // If we were writing a console based application, the ACE macros which + // re-define main() would automatically call this. However, since + // we are running inside an MFC application, we need to explicitly call this. + ACE::init(); + + // Call to set the ACE Log_Msg class here. + // From now on, whenever we use ACE_DEBUG macros, the output + // will be sent to the log() method of our MFC_Log class. + ACE_Log_Msg::instance()->msg_callback( &m_mfc_logger ); + ACE_Log_Msg::instance()->set_flags( ACE_Log_Msg::MSG_CALLBACK ); + + CLog_Msg_MFCDlg dlg; + m_pMainWnd = &dlg; + int nResponse = dlg.DoModal(); + if (nResponse == IDOK) + { + // TODO: Place code here to handle when the dialog is + // dismissed with OK + } + else if (nResponse == IDCANCEL) + { + // TODO: Place code here to handle when the dialog is + // dismissed with Cancel + } + + // Since we called ACE::init(), we need to call ACE:fini(), otherwise + // the debugger will complain about memory leaks. + ACE::fini(); + + // Since the dialog has been closed, return FALSE so that we exit the + // application, rather than start the application's message pump. + return FALSE; +} + +#endif /* ACE_WIN32 */ diff --git a/ACE/examples/Log_Msg/Log_Msg_MFC/Log_Msg_MFC.h b/ACE/examples/Log_Msg/Log_Msg_MFC/Log_Msg_MFC.h new file mode 100644 index 00000000000..66940811ba1 --- /dev/null +++ b/ACE/examples/Log_Msg/Log_Msg_MFC/Log_Msg_MFC.h @@ -0,0 +1,62 @@ +// Log_Msg_MFC.h : main header file for the LOG_MSG_MFC application +// $Id$ + +#if !defined(AFX_LOG_MSG_MFC_H__03FA2C60_71EA_44F9_AC4C_2F19168B4755__INCLUDED_) +#define AFX_LOG_MSG_MFC_H__03FA2C60_71EA_44F9_AC4C_2F19168B4755__INCLUDED_ + +#include "ace/config-all.h" + +#if defined (ACE_WIN32) + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#ifndef __AFXWIN_H__ + #error include 'stdafx.h' before including this file for PCH +#endif + +#include "resource.h" // main symbols + +// Add some includes here for our Logger +#include "MFC_Log.h" + +///////////////////////////////////////////////////////////////////////////// +// CLog_Msg_MFCApp: +// See Log_Msg_MFC.cpp for the implementation of this class +// + +class CLog_Msg_MFCApp : public CWinApp +{ +public: + CLog_Msg_MFCApp(); + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CLog_Msg_MFCApp) + public: + virtual BOOL InitInstance(); + //}}AFX_VIRTUAL + +// Implementation + + //{{AFX_MSG(CLog_Msg_MFCApp) + // NOTE - the ClassWizard will add and remove member functions here. + // DO NOT EDIT what you see in these blocks of generated code ! + //}}AFX_MSG + DECLARE_MESSAGE_MAP() + + // MFC Log class for ACE_Log_Msg. To be used by ACE_DEBUG + MFC_Log m_mfc_logger; + +}; + + +///////////////////////////////////////////////////////////////////////////// + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif /* ACE_WIN32 */ + +#endif // !defined(AFX_LOG_MSG_MFC_H__03FA2C60_71EA_44F9_AC4C_2F19168B4755__INCLUDED_) diff --git a/ACE/examples/Log_Msg/Log_Msg_MFC/Log_Msg_MFC.mpc b/ACE/examples/Log_Msg/Log_Msg_MFC/Log_Msg_MFC.mpc new file mode 100644 index 00000000000..fea7e91ec9f --- /dev/null +++ b/ACE/examples/Log_Msg/Log_Msg_MFC/Log_Msg_MFC.mpc @@ -0,0 +1,12 @@ +// -*- MPC -*- +// $Id$ + +project : aceexe, ace_mfc { + exename = Log_Msg_MFC + Source_Files { + Log_Msg_MFC.cpp + Log_Msg_MFCDlg.cpp + MFC_Log.cpp + StdAfx.cpp + } +} diff --git a/ACE/examples/Log_Msg/Log_Msg_MFC/Log_Msg_MFC.rc b/ACE/examples/Log_Msg/Log_Msg_MFC/Log_Msg_MFC.rc new file mode 100644 index 00000000000..5f2f04dce74 --- /dev/null +++ b/ACE/examples/Log_Msg/Log_Msg_MFC/Log_Msg_MFC.rc @@ -0,0 +1,207 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "#define _AFX_NO_SPLITTER_RESOURCES\r\n" + "#define _AFX_NO_OLE_RESOURCES\r\n" + "#define _AFX_NO_TRACKER_RESOURCES\r\n" + "#define _AFX_NO_PROPERTY_RESOURCES\r\n" + "\r\n" + "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n" + "#ifdef _WIN32\r\n" + "LANGUAGE 9, 1\r\n" + "#pragma code_page(1252)\r\n" + "#endif //_WIN32\r\n" + "#include ""res\\Log_Msg_MFC.rc2"" // non-Microsoft Visual C++ edited resources\r\n" + "#include ""afxres.rc"" // Standard components\r\n" + "#endif\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDR_MAINFRAME ICON DISCARDABLE "res\\Log_Msg_MFC.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_ABOUTBOX DIALOG DISCARDABLE 0, 0, 235, 55 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "About Log_Msg_MFC" +FONT 8, "MS Sans Serif" +BEGIN + ICON IDR_MAINFRAME,IDC_STATIC,11,17,20,20 + LTEXT "Log_Msg_MFC Version 1.0",IDC_STATIC,40,10,119,8, + SS_NOPREFIX + LTEXT "Copyright (C) 2002",IDC_STATIC,40,25,119,8 + DEFPUSHBUTTON "OK",IDOK,178,7,50,14,WS_GROUP +END + +IDD_LOG_MSG_MFC_DIALOG DIALOGEX 0, 0, 320, 200 +STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_APPWINDOW +CAPTION "Log_Msg_MFC" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,241,170,50,14 + PUSHBUTTON "DebugMe",IDC_BUTTON1,92,96,50,14 + LTEXT "Run this program inside the Visual Studio debugger. Press the DebugMe button and see the ACE_DEBUG messages appear in the Visual Studio debug console.", + IDC_STATIC,83,28,116,56 +END + + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,1 + PRODUCTVERSION 1,0,0,1 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904B0" + BEGIN + VALUE "CompanyName", "\0" + VALUE "FileDescription", "Log_Msg_MFC MFC Application\0" + VALUE "FileVersion", "1, 0, 0, 1\0" + VALUE "InternalName", "Log_Msg_MFC\0" + VALUE "LegalCopyright", "Copyright (C) 2002\0" + VALUE "LegalTrademarks", "\0" + VALUE "OriginalFilename", "Log_Msg_MFC.EXE\0" + VALUE "ProductName", "Log_Msg_MFC Application\0" + VALUE "ProductVersion", "1, 0, 0, 1\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +#endif // !_MAC + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO DISCARDABLE +BEGIN + IDD_ABOUTBOX, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 228 + TOPMARGIN, 7 + BOTTOMMARGIN, 48 + END + + IDD_LOG_MSG_MFC_DIALOG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 313 + TOPMARGIN, 7 + BOTTOMMARGIN, 193 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE DISCARDABLE +BEGIN + IDS_ABOUTBOX "&About Log_Msg_MFC..." +END + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// +#define _AFX_NO_SPLITTER_RESOURCES +#define _AFX_NO_OLE_RESOURCES +#define _AFX_NO_TRACKER_RESOURCES +#define _AFX_NO_PROPERTY_RESOURCES + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE 9, 1 +#pragma code_page(1252) +#endif //_WIN32 +#include "res\Log_Msg_MFC.rc2" // non-Microsoft Visual C++ edited resources +#include "afxres.rc" // Standard components +#endif + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/ACE/examples/Log_Msg/Log_Msg_MFC/Log_Msg_MFCDlg.cpp b/ACE/examples/Log_Msg/Log_Msg_MFC/Log_Msg_MFCDlg.cpp new file mode 100644 index 00000000000..ec014f9d9eb --- /dev/null +++ b/ACE/examples/Log_Msg/Log_Msg_MFC/Log_Msg_MFCDlg.cpp @@ -0,0 +1,185 @@ +// Log_Msg_MFCDlg.cpp : implementation file +// $Id$ + +#include "Log_Msg_MFC.h" + +#if defined (ACE_WIN32) + +#include "ace/Log_Msg.h" +#include "stdafx.h" +#include "Log_Msg_MFCDlg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CAboutDlg dialog used for App About + +class CAboutDlg : public CDialog +{ +public: + CAboutDlg(); + +// Dialog Data + //{{AFX_DATA(CAboutDlg) + enum { IDD = IDD_ABOUTBOX }; + //}}AFX_DATA + + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CAboutDlg) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + //{{AFX_MSG(CAboutDlg) + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD) +{ + //{{AFX_DATA_INIT(CAboutDlg) + //}}AFX_DATA_INIT +} + +void CAboutDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CAboutDlg) + //}}AFX_DATA_MAP +} + +BEGIN_MESSAGE_MAP(CAboutDlg, CDialog) + //{{AFX_MSG_MAP(CAboutDlg) + // No message handlers + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CLog_Msg_MFCDlg dialog + +CLog_Msg_MFCDlg::CLog_Msg_MFCDlg(CWnd* pParent /*=NULL*/) + : CDialog(CLog_Msg_MFCDlg::IDD, pParent) +{ + //{{AFX_DATA_INIT(CLog_Msg_MFCDlg) + // NOTE: the ClassWizard will add member initialization here + //}}AFX_DATA_INIT + // Note that LoadIcon does not require a subsequent DestroyIcon in Win32 + m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); +} + +void CLog_Msg_MFCDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CLog_Msg_MFCDlg) + // NOTE: the ClassWizard will add DDX and DDV calls here + //}}AFX_DATA_MAP +} + +BEGIN_MESSAGE_MAP(CLog_Msg_MFCDlg, CDialog) + //{{AFX_MSG_MAP(CLog_Msg_MFCDlg) + ON_WM_SYSCOMMAND() + ON_WM_PAINT() + ON_WM_QUERYDRAGICON() + ON_BN_CLICKED(IDC_BUTTON1, OnDebugButtonClicked) + ON_WM_CLOSE() + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CLog_Msg_MFCDlg message handlers + +BOOL CLog_Msg_MFCDlg::OnInitDialog() +{ + CDialog::OnInitDialog(); + + + // Add "About..." menu item to system menu. + + // IDM_ABOUTBOX must be in the system command range. + ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); + ASSERT(IDM_ABOUTBOX < 0xF000); + +#if !defined (_WIN32_WCE) + CMenu* pSysMenu = GetSystemMenu(FALSE); + if (pSysMenu != NULL) + { + CString strAboutMenu; + strAboutMenu.LoadString(IDS_ABOUTBOX); + if (!strAboutMenu.IsEmpty()) + { + pSysMenu->AppendMenu(MF_SEPARATOR); + pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); + } + } +#endif /* !_WIN32_WCE */ + + // Set the icon for this dialog. The framework does this automatically + // when the application's main window is not a dialog + SetIcon(m_hIcon, TRUE); // Set big icon + SetIcon(m_hIcon, FALSE); // Set small icon + + // TODO: Add extra initialization here + + return TRUE; // return TRUE unless you set the focus to a control +} + +void CLog_Msg_MFCDlg::OnSysCommand(UINT nID, LPARAM lParam) +{ + if ((nID & 0xFFF0) == IDM_ABOUTBOX) + { + CAboutDlg dlgAbout; + dlgAbout.DoModal(); + } + else + { + CDialog::OnSysCommand(nID, lParam); + } +} + +// If you add a minimize button to your dialog, you will need the code below +// to draw the icon. For MFC applications using the document/view model, +// this is automatically done for you by the framework. + +void CLog_Msg_MFCDlg::OnPaint() +{ + if (IsIconic()) + { + CPaintDC dc(this); // device context for painting + + // Center icon in client rectangle + int cxIcon = GetSystemMetrics(SM_CXICON); + int cyIcon = GetSystemMetrics(SM_CYICON); + CRect rect; + GetClientRect(&rect); + int x = (rect.Width() - cxIcon + 1) / 2; + int y = (rect.Height() - cyIcon + 1) / 2; + + // Draw the icon + dc.DrawIcon(x, y, m_hIcon); + } + else + { + CDialog::OnPaint(); + } +} + +// The system calls this to obtain the cursor to display while the user drags +// the minimized window. +HCURSOR CLog_Msg_MFCDlg::OnQueryDragIcon() +{ + return (HCURSOR) m_hIcon; +} + +void CLog_Msg_MFCDlg::OnDebugButtonClicked() +{ + ACE_DEBUG(( LM_DEBUG, "Debug message sent!\n" )); + +} + +#endif /* ACE_WIN32 */ diff --git a/ACE/examples/Log_Msg/Log_Msg_MFC/Log_Msg_MFCDlg.h b/ACE/examples/Log_Msg/Log_Msg_MFC/Log_Msg_MFCDlg.h new file mode 100644 index 00000000000..0a26de3e5e7 --- /dev/null +++ b/ACE/examples/Log_Msg/Log_Msg_MFC/Log_Msg_MFCDlg.h @@ -0,0 +1,59 @@ +// Log_Msg_MFCDlg.h : header file +// $Id$ + +#if !defined(AFX_LOG_MSG_MFCDLG_H__5BB9CACE_CBCE_40DD_B57F_ED05B79DB033__INCLUDED_) +#define AFX_LOG_MSG_MFCDLG_H__5BB9CACE_CBCE_40DD_B57F_ED05B79DB033__INCLUDED_ + +#include "ace/config-all.h" + +#if defined (ACE_WIN32) + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#include "Resource.h" + +///////////////////////////////////////////////////////////////////////////// +// CLog_Msg_MFCDlg dialog + +class CLog_Msg_MFCDlg : public CDialog +{ +// Construction +public: + CLog_Msg_MFCDlg(CWnd* pParent = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CLog_Msg_MFCDlg) + enum { IDD = IDD_LOG_MSG_MFC_DIALOG }; + // NOTE: the ClassWizard will add data members here + //}}AFX_DATA + + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CLog_Msg_MFCDlg) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + HICON m_hIcon; + + // Generated message map functions + //{{AFX_MSG(CLog_Msg_MFCDlg) + virtual BOOL OnInitDialog(); + afx_msg void OnSysCommand(UINT nID, LPARAM lParam); + afx_msg void OnPaint(); + afx_msg HCURSOR OnQueryDragIcon(); + afx_msg void OnDebugButtonClicked(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() + +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif /* ACE_WIN32 */ + +#endif // !defined(AFX_LOG_MSG_MFCDLG_H__5BB9CACE_CBCE_40DD_B57F_ED05B79DB033__INCLUDED_) diff --git a/ACE/examples/Log_Msg/Log_Msg_MFC/MFC_Log.cpp b/ACE/examples/Log_Msg/Log_Msg_MFC/MFC_Log.cpp new file mode 100644 index 00000000000..18899d5611c --- /dev/null +++ b/ACE/examples/Log_Msg/Log_Msg_MFC/MFC_Log.cpp @@ -0,0 +1,45 @@ +// $Id$ +// MFC_Log.cpp: implementation of the MFC_Log class. +// +////////////////////////////////////////////////////////////////////// + +#include "ace/OS_NS_stdio.h" +#include "MFC_Log.h" + +#if defined (ACE_WIN32) +# include "stdafx.h" +#endif /* ACE_WIN32 */ + +#include "ace/Log_Record.h" +#include "ace/Time_Value.h" + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +MFC_Log::MFC_Log () +{ + +} + +void +MFC_Log::log (ACE_Log_Record& log_record) +{ + unsigned long priority = log_record.type(); + ACE_TCHAR Message[512]; + + ACE_OS::sprintf (Message, + ACE_TEXT ("%d.%03ld %s"), + log_record.time_stamp().sec(), + log_record.time_stamp().usec()/ 1000, + log_record.msg_data()); + +#if defined (ACE_WIN32) + ACE_TEXT_OutputDebugString(Message); +#endif /* ACE_WIN32 */ +} + +MFC_Log::~MFC_Log () +{ + +} diff --git a/ACE/examples/Log_Msg/Log_Msg_MFC/MFC_Log.h b/ACE/examples/Log_Msg/Log_Msg_MFC/MFC_Log.h new file mode 100644 index 00000000000..657b0e8a914 --- /dev/null +++ b/ACE/examples/Log_Msg/Log_Msg_MFC/MFC_Log.h @@ -0,0 +1,47 @@ +/* -*- C++ -*- */ + +//============================================================================= +/** + * @file MFC_Log.h + * + * $Id$ + * + * @author Craig Rodrigues <crodrigu@bbn.com> + * @author Chris Hafey <chafey@stentor.com> + * @author Don Hinton <dhinton@ieee.org> + */ +//============================================================================= + +#ifndef MFC_LOG_H +#define MFC_LOG_H + +#include "ace/Log_Msg_Callback.h" + +class ACE_Log_Record; + +/** + * @class MFC_Log + * + * @brief A callback class for ACE_Log_Msg which sends output to + * Microsoft debugger + * + * Register this class as a MSG_CALLBACK with the ACE_Log_Msg singleton and + * send debug output to the Microsoft debugger console window with + * ACE_DEBUG macros. + */ +class MFC_Log : public virtual ACE_Log_Msg_Callback +{ +public: + /// Constructor + MFC_Log(); + + /// method called by ACE_Log_Msg to log an event + void log(ACE_Log_Record& log_record); + + /// destructor + virtual ~MFC_Log(); + +}; + +#endif /* MFC_LOG_H */ + diff --git a/ACE/examples/Log_Msg/Log_Msg_MFC/README b/ACE/examples/Log_Msg/Log_Msg_MFC/README new file mode 100644 index 00000000000..d64001aff87 --- /dev/null +++ b/ACE/examples/Log_Msg/Log_Msg_MFC/README @@ -0,0 +1,40 @@ + MFC Logging Example documentation + ================================= + by Craig Rodrigues <crodrigu@bbn.com> + 2002/08/02 + +The example in this directory is a Microsoft Foundation Class (MFC) +example which illustrates how to write an ACE_Log_Msg_Callback which +can send debug output to the Microsoft debugger console. + +This is very useful when debugging an MFC GUI-based application which +uses ACE. + +NOTES +===== + - Make sure that $ACE_ROOT/ace/acemfcd.lib is built before building this + example. Follow the instructions in $ACE_ROOT/ACE-INSTALL.html for building + ACE with Visual C++. Do a Batch Build of ACE, and make sure that you build + the target "ACE DLL - Win32 MFC Debug". + + - We must call ACE::init() and ACE::fini() in the right places + otherwise we will get strange crashes and memory leaks + when invoking ACE_Log_Msg::instance(). + A good place to invoke these methods is in the method which overrides + CWinApp::InitInstance(). + In this example, we invoke these methods in CLog_Msg_MFCApp::InitInstance(). + + - We must set the ACE_Log_Msg singleton to use our callback with: + ACE_Log_Msg::instance()->msg_callback( &m_mfc_logger ); + ACE_Log_Msg::instance()->set_flags( ACE_Log_Msg::MSG_CALLBACK ); + + This is also done in CLog_Msg_MFCApp::InitInstance(). + + +THANKS +====== +Thanks to the following people who provided assistance on the ACE +mailing list: +Chris Hafey <chafey@stentor.com> +Don Hinton <dhinton@ieee.org> + diff --git a/ACE/examples/Log_Msg/Log_Msg_MFC/Resource.h b/ACE/examples/Log_Msg/Log_Msg_MFC/Resource.h new file mode 100644 index 00000000000..d1aa3df6ce1 --- /dev/null +++ b/ACE/examples/Log_Msg/Log_Msg_MFC/Resource.h @@ -0,0 +1,21 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by Log_Msg_MFC.rc +// $Id$ +#define IDM_ABOUTBOX 0x0010 +#define IDD_ABOUTBOX 100 +#define IDS_ABOUTBOX 101 +#define IDD_LOG_MSG_MFC_DIALOG 102 +#define IDR_MAINFRAME 128 +#define IDC_BUTTON1 1000 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 129 +#define _APS_NEXT_COMMAND_VALUE 32771 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/ACE/examples/Log_Msg/Log_Msg_MFC/StdAfx.cpp b/ACE/examples/Log_Msg/Log_Msg_MFC/StdAfx.cpp new file mode 100644 index 00000000000..7325df7a861 --- /dev/null +++ b/ACE/examples/Log_Msg/Log_Msg_MFC/StdAfx.cpp @@ -0,0 +1,9 @@ +// $Id$ +// stdafx.cpp : source file that includes just the standard includes +// Log_Msg_MFC.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + + + diff --git a/ACE/examples/Log_Msg/Log_Msg_MFC/StdAfx.h b/ACE/examples/Log_Msg/Log_Msg_MFC/StdAfx.h new file mode 100644 index 00000000000..caf39678fcb --- /dev/null +++ b/ACE/examples/Log_Msg/Log_Msg_MFC/StdAfx.h @@ -0,0 +1,28 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// $Id$ + +#if !defined(AFX_STDAFX_H__41816CD6_CE58_4714_8C74_1C67651B50ED__INCLUDED_) +#define AFX_STDAFX_H__41816CD6_CE58_4714_8C74_1C67651B50ED__INCLUDED_ + +#ifdef USING_PCH + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers + +#include <afxwin.h> // MFC core and standard components +#include <afxext.h> // MFC extensions +#include <afxdtctl.h> // MFC support for Internet Explorer 4 Common Controls +#ifndef _AFX_NO_AFXCMN_SUPPORT +#include <afxcmn.h> // MFC support for Windows Common Controls +#endif // _AFX_NO_AFXCMN_SUPPORT + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // USING_PCH +#endif // !defined(AFX_STDAFX_H__41816CD6_CE58_4714_8C74_1C67651B50ED__INCLUDED_) diff --git a/ACE/examples/Log_Msg/Log_Msg_MFC/res/Log_Msg_MFC.ico b/ACE/examples/Log_Msg/Log_Msg_MFC/res/Log_Msg_MFC.ico Binary files differnew file mode 100644 index 00000000000..7eef0bcbe65 --- /dev/null +++ b/ACE/examples/Log_Msg/Log_Msg_MFC/res/Log_Msg_MFC.ico diff --git a/ACE/examples/Log_Msg/Log_Msg_MFC/res/Log_Msg_MFC.rc2 b/ACE/examples/Log_Msg/Log_Msg_MFC/res/Log_Msg_MFC.rc2 new file mode 100644 index 00000000000..f8d03632acf --- /dev/null +++ b/ACE/examples/Log_Msg/Log_Msg_MFC/res/Log_Msg_MFC.rc2 @@ -0,0 +1,13 @@ +// +// LOG_MSG_MFC.RC2 - resources Microsoft Visual C++ does not edit directly +// + +#ifdef APSTUDIO_INVOKED + #error this file is not editable by Microsoft Visual C++ +#endif //APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// Add manually edited resources here... + +///////////////////////////////////////////////////////////////////////////// diff --git a/ACE/examples/Log_Msg/Makefile.am b/ACE/examples/Log_Msg/Makefile.am new file mode 100644 index 00000000000..c5d038d332d --- /dev/null +++ b/ACE/examples/Log_Msg/Makefile.am @@ -0,0 +1,59 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +ACE_BUILDDIR = $(top_builddir) +ACE_ROOT = $(top_srcdir) + +## Makefile.Log_Msg_Test_Callback.am +noinst_PROGRAMS = test_callback + +test_callback_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +test_callback_SOURCES = \ + test_callback.cpp + +test_callback_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Log_Msg_Test_Log_Msg.am +noinst_PROGRAMS += test_log_msg + +test_log_msg_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +test_log_msg_SOURCES = \ + test_log_msg.cpp + +test_log_msg_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Log_Msg_Test_Ostream.am +noinst_PROGRAMS += test_ostream + +test_ostream_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +test_ostream_SOURCES = \ + test_ostream.cpp + +test_ostream_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Clean up template repositories, etc. +clean-local: + -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.* + -rm -f gcctemp.c gcctemp so_locations *.ics + -rm -rf cxx_repository ptrepository ti_files + -rm -rf templateregistry ir.out + -rm -rf ptrepository SunWS_cache Templates.DB diff --git a/ACE/examples/Log_Msg/README b/ACE/examples/Log_Msg/README new file mode 100644 index 00000000000..047caf9ca77 --- /dev/null +++ b/ACE/examples/Log_Msg/README @@ -0,0 +1,65 @@ +This directory contains program(s) that demonstrate how to use ACE's +Log_Msg class to record various information. + + * test_callback.cpp: This program tests the Log_Msg + abstraction wrt writing to user defined callback objects. + + * test_ostream.cpp: This program illustrates how the + ACE_Log_Msg abstraction can be used to write to + stderr and to a file. For even more sophisticated + use-cases of ACE_Log_Msg please see the + $ACE_ROOT/netsvcs/clients/Logger/ examples. + + * test_log_msg.cpp: This program tests various feature of the + Log_Msg facility. It opens a log file and writes some + messages using different log priorities and output stream. + + You can invoke the program with or without command + parameters. When invoked with any parameters like, + + ./Log_Msg foobar + + the log messages are direct to stdout (or, ostream in C++.) + In this case, the program simulates an error EWOULDBLOCK and + write an error log to stdout as, + + would block + op_status and errnum work! + + When invoked without any parameters, except does the same + test as above but logs to default log stream "stderr," the + program also demonstrates logging messages/errors with + different priority and changing the logging destination. A + sample output is, + + would block + op_status and errnum work! + 3.141600, hello = 10000 + 6.283200, world = 20000 + 6.283200, world = 20000 + 9.424800, world = 30000 + 12.566400, world = 40000 + 15.708000, world = 50000 + HEXDUMP 48 bytes + 01 00 00 00 02 00 00 00 04 00 00 00 08 00 00 00 ................ + 10 00 00 00 20 00 00 00 40 00 00 00 80 00 00 00 .... ...@....... + 00 01 00 00 00 02 00 00 00 04 00 00 00 08 00 00 ................ + ./Log_Msg.EXE: (2710), badname: Function not implemented + + In this test, there are two lines containing "world` = + 20000." That's because in the program, both stderr and + stdout are "turned on" for logging before writing this log + message. The line containing "world = 30000" is written to + stdout only. Rest of the lines are all to the stderr. You + can examine this behavior by redirecting stderr and stdout + to different files. + + The HEXDUMP output shows how to take an arbitrary object and + hexdump its content for debugging. Finally, the program + shows an ordinary use case of logging error messages using + the ACE_ERROR macro. + + If you look into the program, there is also a demonstration + showing how to disable certain priorities of error message + temporarily. + diff --git a/ACE/examples/Log_Msg/test_callback.cpp b/ACE/examples/Log_Msg/test_callback.cpp new file mode 100644 index 00000000000..e263c9777eb --- /dev/null +++ b/ACE/examples/Log_Msg/test_callback.cpp @@ -0,0 +1,166 @@ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// examples/Log_Msg +// +// = FILENAME +// test_callback.cpp +// +// = DESCRIPTION +// This program tests the <ACE_Log_Msg> class wrt writing to user +// defined callback objects. In particular, it tests to make sure +// that nested callbacks don't deadlock. +// +// = AUTHOR +// Irfan Pyarali <irfan@cs.wustl.edu> +// +// ============================================================================ + +#include "ace/OS_main.h" +#include "ace/Log_Msg.h" +#include "ace/Log_Msg_Callback.h" +#include "ace/Log_Record.h" +#include "ace/OS_NS_stdio.h" + +ACE_RCSID(Log_Msg, test_callback, "$Id$") + +class Logger : public ACE_Log_Msg_Callback +// Subclassing from ACE_Log_Msg_Callback means that an instance of +// Logger can be a target of a callback. +{ +public: + // Constructor sets whether we're testing "recursive" callback + // logging! + Logger (int be_recursive = 1); + + virtual void log (ACE_Log_Record &log_record); + // Logging callback hook. + + void verbose (int be_verbose); + +private: + int verbose_logging_; + // Flag for testing verbose logging. + + int recursive_; + // Flag for testing recursive callback logging. +}; + +void +Logger::verbose (int be_verbose) +{ + this->verbose_logging_ = be_verbose; +} + +Logger::Logger (int be_recursive) + : recursive_ (be_recursive) +{ +} + +void +Logger::log (ACE_Log_Record &log_record) +{ + int use_log_msg = 0; + + if (this->recursive_) + { + this->recursive_ = 0; + use_log_msg = 1; + } + + if (!this->verbose_logging_) + { + if (use_log_msg) + ACE_DEBUG ((LM_DEBUG, + "Logger::log->%s", + log_record.msg_data ())); + else + ACE_OS::printf ("Recursive Logger callback = %s", + log_record.msg_data ()); + } + else + { + ACE_TCHAR verbose_msg[ACE_Log_Record::MAXVERBOSELOGMSGLEN]; + int result = log_record.format_msg (ACE_LOG_MSG->local_host (), + ACE_LOG_MSG->flags (), + verbose_msg); + if (result == 0) + { + if (use_log_msg) + ACE_DEBUG ((LM_DEBUG, + "Logger::log->%s", + verbose_msg)); + else + ACE_OS::printf ("Recursive Logger callback = %s", + verbose_msg); + } + } + + // Cleanup on the way out. + if (use_log_msg) + this->recursive_ = 1; +} + +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + // This message should show up in stderr. + ACE_DEBUG ((LM_DEBUG, + "(%t) first message\n")); + + ACE_LOG_MSG->clr_flags (ACE_Log_Msg::STDERR); + + // This message should not show up anywhere since we disabled STDERR. + ACE_DEBUG ((LM_DEBUG, + "(%t) second message\n")); + + ACE_LOG_MSG->set_flags (ACE_Log_Msg::MSG_CALLBACK); + + // This message should not show up anywhere since no callback object + // has been specified. + ACE_DEBUG ((LM_DEBUG, + "(%t) third message\n")); + + // Create a callback object and make it "verbose". + Logger logger; + logger.verbose (1); + + // Set the callback object. + ACE_LOG_MSG->msg_callback (&logger); + + // This message should show up via the Logger callback. + ACE_DEBUG ((LM_DEBUG, + "(%t) fourth message\n")); + + ACE_LOG_MSG->set_flags (ACE_Log_Msg::VERBOSE_LITE); + + // This message should show up via the Logger callback (somewhat + // verbosely). + ACE_DEBUG ((LM_DEBUG, + "(%t) fifth message\n")); + + ACE_LOG_MSG->set_flags (ACE_Log_Msg::VERBOSE); + + // This message should show up via the Logger callback (really + // verbosely). + ACE_DEBUG ((LM_DEBUG, + "(%t) sixth message\n")); + + logger.verbose (0); + + // This message should show up via the Logger callback (not + // verbosely). + ACE_DEBUG ((LM_DEBUG, + "(%t) seventh message\n")); + + ACE_LOG_MSG->set_flags (ACE_Log_Msg::STDERR); + + // This message should show up in stderr and the Logger callback. + // The one from the Logger callback will not be verbose, but the one + // from stderr should be verbose. + ACE_DEBUG ((LM_DEBUG, + "(%t) eighth message\n")); + return 0; +} diff --git a/ACE/examples/Log_Msg/test_log_msg.cpp b/ACE/examples/Log_Msg/test_log_msg.cpp new file mode 100644 index 00000000000..a2d40770f56 --- /dev/null +++ b/ACE/examples/Log_Msg/test_log_msg.cpp @@ -0,0 +1,218 @@ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// examples/Log_Msg +// +// = FILENAME +// test_log_msg.cpp +// +// = DESCRIPTION +// This program tests the ACE_Log_Msg abstraction and demontrates +// several common use cases. +// +// = AUTHOR +// Douglas Schmidt <schmidt@cs.wustl.edu> +// +// ============================================================================ + +#include "ace/OS_main.h" + +// FUZZ: disable check_for_streams_include +#include "ace/streams.h" + +#include "ace/Log_Msg.h" +#include "ace/OS_NS_unistd.h" +#include "ace/OS_NS_stdlib.h" + +ACE_RCSID(Log_Msg, test_log_msg, "$Id$") + +static void +cleanup (void) +{ + ACE_DEBUG ((LM_INFO, + "leaving (%P)!\n")); +} + +static void +cause_error (void) +{ + errno = EWOULDBLOCK; + ACE_ERROR ((LM_DEBUG, + "would block\n")); +} + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + int counter = 1; + + if (argc > 1) // Just give a dummy command-line argument to trigger this path. + { + if (ACE_LOG_MSG->open (argv[0], + ACE_Log_Msg::OSTREAM) == -1) + ACE_ERROR ((LM_ERROR, + "cannot open logger!!!\n")); + + cause_error (); + // Check to see what happened. + if (ACE_LOG_MSG->op_status () == -1 + && ACE_LOG_MSG->errnum () == EWOULDBLOCK) + ACE_DEBUG ((LM_DEBUG, + "op_status and errnum work!\n")); + else + ACE_ERROR ((LM_ERROR, + "op_status and errnum failed!\n")); + } + else // The default behavior is to log to STDERR... + { + if (ACE_LOG_MSG->open (argv[0]) == -1) + ACE_ERROR ((LM_ERROR, + "cannot open logger!!!\n")); + + cause_error (); + + // Check to see what happened. + if (ACE_LOG_MSG->op_status () == -1 + && ACE_LOG_MSG->errnum () == EWOULDBLOCK) + ACE_DEBUG ((LM_DEBUG, + "op_status and errnum work!\n")); + else + ACE_ERROR ((LM_ERROR, + "op_status and errnum failed!\n")); + + // Exercise many different combinations of STDERR and OSTREAM. + + double f = 3.1416 * counter++; + int i = 10000; + + ACE_DEBUG ((LM_INFO, + "%10f, %*s%s = %d\n", + f, + 8, + "", + "hello", + i)); + +#if !defined (ACE_LACKS_IOSTREAM_TOTALLY) + + ACE_LOG_MSG->set_flags (ACE_Log_Msg::OSTREAM); + ACE_LOG_MSG->msg_ostream (&cout); + + f = 3.1416 * counter; + i = 10000 * counter++; + + // This message will print twice - once for OSTREAM and once for + // STDERR. + + ACE_DEBUG ((LM_INFO, + "%10f, %*s%s = %d\n", + f, + 8, + "", + "world", + i)); + + ACE_LOG_MSG->clr_flags (ACE_Log_Msg::STDERR); + + f = 3.1416 * counter; + i = 10000 * counter++; + + ACE_DEBUG ((LM_INFO, + "%10f, %*s%s = %d\n", + f, + 8, + "", + "world", + i)); + + ACE_LOG_MSG->msg_ostream (0); + + ACE_LOG_MSG->set_flags (ACE_Log_Msg::STDERR); + + f = 3.1416 * counter; + i = 10000 * counter++; + + ACE_DEBUG ((LM_INFO, + "%10f, %*s%s = %d\n", + f, + 8, + "", + "world", + i)); + + ACE_LOG_MSG->clr_flags (ACE_Log_Msg::OSTREAM); + ACE_LOG_MSG->msg_ostream (&cerr); + + f = 3.1416 * counter; + i = 10000 * counter++; + + ACE_DEBUG ((LM_INFO, + "%10f, %*s%s = %d\n", + f, + 8, + "", + "world", + i)); + +#endif /* !defined (ACE_LACKS_IOSTREAM_TOTALLY) */ + + static int array[] = {1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048}; + + // Print out the binary bytes of the array in hex form. + ACE_LOG_MSG->log_hexdump (LM_DEBUG, + (char *) array, + sizeof array); + + // Disable the LM_DEBUG and LM_INFO messages at the process level. + u_long priority_mask = + ACE_LOG_MSG->priority_mask (ACE_Log_Msg::PROCESS); + ACE_CLR_BITS (priority_mask, + LM_DEBUG | LM_INFO); + ACE_LOG_MSG->priority_mask (priority_mask, + ACE_Log_Msg::PROCESS); + + ACE_DEBUG ((LM_INFO, + "This LM_INFO message should not print!\n")); + ACE_DEBUG ((LM_DEBUG, + "This LM_DEBUG message should not print!\n")); + + ACE_SET_BITS (priority_mask, + LM_INFO); + ACE_LOG_MSG->priority_mask (priority_mask, + ACE_Log_Msg::PROCESS); + + ACE_DEBUG ((LM_INFO, + "This LM_INFO message should print!\n")); + ACE_DEBUG ((LM_DEBUG, + "This LM_DEBUG message should not print!\n")); + + ACE_CLR_BITS (priority_mask, LM_INFO); + ACE_LOG_MSG->priority_mask (priority_mask, + ACE_Log_Msg::PROCESS); + + ACE_DEBUG ((LM_INFO, + "This LM_INFO message should not print!\n")); + ACE_DEBUG ((LM_DEBUG, + "This LM_DEBUG message should not print!\n")); + + char badname[] = "badname"; + + char *l_argv[2]; + l_argv[0] = badname; + l_argv[1] = 0; + + if (ACE_OS::execv (badname, + l_argv) == -1) + { + ACE_ERROR ((LM_ERROR, + "%n: (%x), %p%r\n", + 10000, + badname, + cleanup)); + ACE_OS::_exit (); + } + } + return 0; +} diff --git a/ACE/examples/Log_Msg/test_ostream.cpp b/ACE/examples/Log_Msg/test_ostream.cpp new file mode 100644 index 00000000000..3492195fe9d --- /dev/null +++ b/ACE/examples/Log_Msg/test_ostream.cpp @@ -0,0 +1,89 @@ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// examples/Log_Msg +// +// = FILENAME +// test_ostream.cpp +// +// = DESCRIPTION +// This program tests the Log_Msg abstraction wrt writing to +// stderr and to a file. +// +// = AUTHOR +// Irfan Pyarali <irfan@cse.wustl.edu> +// +// ============================================================================ + +#include "ace/OS_main.h" + +// FUZZ: disable check_for_streams_include +#include "ace/streams.h" + +#include "ace/Log_Msg.h" + +ACE_RCSID(Log_Msg, test_ostream, "$Id$") + +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + // This message should show up in stderr. + ACE_DEBUG ((LM_DEBUG, + "first message\n")); + + ACE_LOG_MSG->clr_flags (ACE_Log_Msg::STDERR); + + // This message should not show up anywhere. + ACE_DEBUG ((LM_DEBUG, + "second message\n")); + + ACE_LOG_MSG->set_flags (ACE_Log_Msg::OSTREAM); + + // This message should not show up anywhere since no ostream has + // been specified. + ACE_DEBUG ((LM_DEBUG, + "third message\n")); + +#if !defined (ACE_LACKS_IOSTREAM_TOTALLY) + // Create a persistent store. + const char *filename = "output"; + ofstream outfile (filename, ios::out | ios::trunc); + + // Check for errors. + if (outfile.bad ()) + return 1; + + // Set the ostream. + ACE_LOG_MSG->msg_ostream (&outfile); + + // This message should show up in the ostream. + ACE_DEBUG ((LM_DEBUG, + "fourth message\n")); +#endif /* ACE_LACKS_IOSTREAM_TOTALLY */ + + ACE_LOG_MSG->set_flags (ACE_Log_Msg::STDERR); + + // This message should show up in stderr and the ostream (without + // ACE_LACKS_IOSTREAM_TOTALLY). + ACE_DEBUG ((LM_DEBUG, + "fifth message\n")); + +#if !defined (ACE_LACKS_IOSTREAM_TOTALLY) + ifstream infile (filename, ios::in); + + if (infile.bad ()) + return 1; + + // This loop should print out the contents of file "output", which should + // have the strings "fourth\n" and "fifth\n" in them. + + char line[BUFSIZ]; + + while (infile.getline (line, BUFSIZ, '\n')) + std::cout << line << std::endl; + +#endif /* ACE_LACKS_IOSTREAM_TOTALLY */ + return 0; +} diff --git a/ACE/examples/Logger/Acceptor-server/.cvsignore b/ACE/examples/Logger/Acceptor-server/.cvsignore new file mode 100644 index 00000000000..76c31d8c56f --- /dev/null +++ b/ACE/examples/Logger/Acceptor-server/.cvsignore @@ -0,0 +1,2 @@ +server_loggerd +server_loggerd diff --git a/ACE/examples/Logger/Acceptor-server/Logger_Acceptor_Server.mpc b/ACE/examples/Logger/Acceptor-server/Logger_Acceptor_Server.mpc new file mode 100644 index 00000000000..1e4d8240e38 --- /dev/null +++ b/ACE/examples/Logger/Acceptor-server/Logger_Acceptor_Server.mpc @@ -0,0 +1,6 @@ +// -*- MPC -*- +// $Id$ + +project : aceexe { + exename = server_loggerd +}
\ No newline at end of file diff --git a/ACE/examples/Logger/Acceptor-server/Makefile.am b/ACE/examples/Logger/Acceptor-server/Makefile.am new file mode 100644 index 00000000000..bf1824c86d3 --- /dev/null +++ b/ACE/examples/Logger/Acceptor-server/Makefile.am @@ -0,0 +1,34 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +ACE_BUILDDIR = $(top_builddir) +ACE_ROOT = $(top_srcdir) + +## Makefile.Logger_Acceptor_Server.am +noinst_PROGRAMS = server_loggerd + +server_loggerd_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +server_loggerd_SOURCES = \ + server_loggerd.cpp \ + server_loggerd.h + +server_loggerd_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Clean up template repositories, etc. +clean-local: + -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.* + -rm -f gcctemp.c gcctemp so_locations *.ics + -rm -rf cxx_repository ptrepository ti_files + -rm -rf templateregistry ir.out + -rm -rf ptrepository SunWS_cache Templates.DB diff --git a/ACE/examples/Logger/Acceptor-server/server_loggerd.cpp b/ACE/examples/Logger/Acceptor-server/server_loggerd.cpp new file mode 100644 index 00000000000..fac6447d898 --- /dev/null +++ b/ACE/examples/Logger/Acceptor-server/server_loggerd.cpp @@ -0,0 +1,241 @@ +// $Id$ +// server_loggerd.cpp,v 4.29 2003/12/30 23:18:59 shuston Exp + +// This server daemon collects, formats, and displays logging +// information forwarded from client daemons running on other hosts in +// the network. In addition, this example illustrates how to use the +// ACE_Reactor, ACE_Acceptor, ACE_Singleton, and the ACE_Test_and_Set +// components. + +#include "ace/OS_NS_string.h" +#include "ace/Get_Opt.h" +#include "ace/Acceptor.h" +#include "ace/Null_Mutex.h" +#include "ace/SOCK_Acceptor.h" +#include "ace/Singleton.h" +#include "ace/Test_and_Set.h" + +// FUZZ: disable check_for_streams_include +#include "ace/streams.h" + +#include "ace/Log_Record.h" +#include "ace/Test_and_Set.h" + +#include "server_loggerd.h" + +ACE_RCSID(Acceptor_server, server_loggerd, "$Id$") + +// ---------------------------------------- + +// Return the port number. + +u_short +Options::port (void) +{ + return this->port_; +} + +// Parse the command-line options. + +void +Options::parse_args (int argc, ACE_TCHAR *argv[]) +{ + this->port_ = ACE_DEFAULT_SERVER_PORT; + + ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("p:")); + + for (int c; (c = get_opt ()) != -1; ) + switch (c) + { + case 'p': + this->port_ = ACE_OS::atoi (get_opt.opt_arg ()); + break; + default: + break; + } +} + +// ---------------------------------------- + +// Our Reactor Singleton. +typedef ACE_Singleton<ACE_Reactor, ACE_Null_Mutex> +REACTOR; + +// Our Options Singleton. +typedef ACE_Singleton<Options, ACE_Null_Mutex> +OPTIONS; + +// Our ACE_Test_and_Set Singleton. +typedef ACE_Singleton<ACE_Test_and_Set <ACE_Null_Mutex, sig_atomic_t>, ACE_Null_Mutex> +QUIT_HANDLER; + +// ---------------------------------------- + +// Specialize a Logging Acceptor. +typedef ACE_Acceptor <Logging_Handler, ACE_SOCK_ACCEPTOR> +Logging_Acceptor; + +// Default constructor. + +Logging_Handler::Logging_Handler (void) +{ +} + +int +Logging_Handler::handle_timeout (const ACE_Time_Value &, + const void *arg) +{ +#if defined (ACE_NDEBUG) + ACE_UNUSED_ARG (arg); +#endif /* ACE_NDEBUG */ + + ACE_ASSERT (arg == this); + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) handling timeout from this = %@\n"), this)); + return 0; +} + +// Perform the logging record receive. + +int +Logging_Handler::handle_input (ACE_HANDLE) +{ + // Perform two recv's to emulate record-oriented semantics. Note + // that this code is not entirely portable since it relies on the + // fact that sizeof (ssize_t) is the same on both the sender and + // receiver side. To correctly handle this is painful, and we leave + // it as an exercise for the reader ;-). + + ssize_t len; + ssize_t n = this->peer ().recv ((void *) &len, sizeof len); + + switch (n) + { + case -1: + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("(%P|%t) %p at host %C\n"), + ACE_TEXT ("client logger"), this->peer_name_), -1); + /* NOTREACHED */ + case 0: + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("(%P|%t) closing log daemon at host %C (fd = %d)\n"), + this->peer_name_, this->get_handle ()), -1); + /* NOTREACHED */ + case sizeof (size_t): + { + ACE_Log_Record lp; + + len = ntohl (len); + n = this->peer ().recv_n ((void *) &lp, len); + + if (n != len) + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("(%P|%t) %p at host %C\n"), + ACE_TEXT ("client logger"), this->peer_name_),-1); + /* NOTREACHED */ + + lp.decode (); + + if (lp.length () == n) + { + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) "))); +#if !defined (ACE_LACKS_IOSTREAM_TOTALLY) + lp.print (ACE_TEXT_CHAR_TO_TCHAR (this->peer_name_), 1, cerr); +#else + lp.print (ACE_TEXT_CHAR_TO_TCHAR (this->peer_name_), 1, stderr); +#endif + } + else + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("(%P|%t) error, lp.length = %d, n = %d\n"), + lp.length (), n)); + break; + } + default: + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("(%P|%t) %p at host %C\n"), + ACE_TEXT ("client logger"), this->peer_name_), -1); + /* NOTREACHED */ + } + + return 0; +} + +int +Logging_Handler::open (void *) +{ + ACE_INET_Addr addr; + + if (this->peer ().get_remote_addr (addr) == -1) + return -1; + else + { + ACE_OS::strncpy (this->peer_name_, + addr.get_host_name (), + MAXHOSTNAMELEN + 1); + + if (REACTOR::instance ()->register_handler (this, READ_MASK) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("(%P|%t) can't register with reactor\n")), + -1); + else if (REACTOR::instance ()->schedule_timer + (this, + (const void *) this, + ACE_Time_Value (2), + ACE_Time_Value (2)) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("(%P|%t) can't register with reactor\n")), + -1); + else + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) connected with %C\n"), + this->peer_name_)); + return 0; + } +} + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + // Acceptor factory. + Logging_Acceptor peer_acceptor; + + OPTIONS::instance ()->parse_args (argc, argv); + + // We need to pass in REACTOR::instance () here so that we don't use + // the default ACE_Reactor::instance (). + + if (peer_acceptor.open + (ACE_INET_Addr (OPTIONS::instance ()->port ()), + REACTOR::instance ()) == -1) + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("open")), -1); + + // Register QUIT_HANDLER to receive SIGINT commands. When received, + // QUIT_HANDLER becomes "set" and thus, the event loop below will + // exit. + else if (REACTOR::instance ()->register_handler + (SIGINT, QUIT_HANDLER::instance ()) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("registering service with ACE_Reactor\n")), + -1); + + // Run forever, performing logging service. + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) starting up server logging daemon\n"))); + + // Perform logging service until QUIT_HANDLER receives SIGINT. + while (QUIT_HANDLER::instance ()->is_set () == 0) + REACTOR::instance ()->handle_events (); + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) shutting down server logging daemon\n"))); + + return 0; +} + +#if defined (ACE_HAS_EXPLICIT_STATIC_TEMPLATE_MEMBER_INSTANTIATION) +template ACE_Singleton<ACE_Reactor, ACE_Null_Mutex> * + ACE_Singleton<ACE_Reactor, ACE_Null_Mutex>::singleton_; +template ACE_Singleton<Options, ACE_Null_Mutex> * + ACE_Singleton<Options, ACE_Null_Mutex>::singleton_; +template ACE_Singleton<ACE_Test_and_Set <ACE_Null_Mutex, sig_atomic_t>, ACE_Null_Mutex> * + ACE_Singleton<ACE_Test_and_Set <ACE_Null_Mutex, sig_atomic_t>, ACE_Null_Mutex>::singleton_; +#endif /* ACE_HAS_EXPLICIT_STATIC_TEMPLATE_MEMBER_INSTANTIATION */ diff --git a/ACE/examples/Logger/Acceptor-server/server_loggerd.h b/ACE/examples/Logger/Acceptor-server/server_loggerd.h new file mode 100644 index 00000000000..33d5f0042ee --- /dev/null +++ b/ACE/examples/Logger/Acceptor-server/server_loggerd.h @@ -0,0 +1,54 @@ +// $Id$ + +// Define classes used with templates in server_loggerd.h. + +#ifndef __SERVER_LOGGERD_H +#define __SERVER_LOGGERD_H + +#include "ace/SOCK_Stream.h" +#include "ace/Svc_Handler.h" +#include "ace/os_include/os_netdb.h" + +class Options +{ + // = TITLE + // Keeps track of the options. +public: + void parse_args (int argc, ACE_TCHAR *argv[]); + u_short port (void); + +private: + u_short port_; + // Port number; +}; + + +class Logging_Handler : public ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH> +// = TITLE +// Receive client message from the remote clients. +// +// = DESCRIPTION +// This class demonstrates how to receive messages from remote +// clients using the notification mechanisms in the +// <ACE_Reactor>. In addition, it also illustrates how to +// utilize the <ACE_Reactor> timer mechanisms, as well. +{ +public: + // = Initialization and termination methods. + Logging_Handler (void); + + // = Hooks for opening and closing handlers. + virtual int open (void *); + +protected: + // = Demultiplexing hooks. + virtual int handle_input (ACE_HANDLE); + virtual int handle_timeout (const ACE_Time_Value &tv, + const void *arg); + +private: + char peer_name_[MAXHOSTNAMELEN + 1]; + // Host we are connected to. +}; + +#endif /* __SERVER_LOGGERD_H */ diff --git a/ACE/examples/Logger/Makefile.am b/ACE/examples/Logger/Makefile.am new file mode 100644 index 00000000000..3aa67282ba4 --- /dev/null +++ b/ACE/examples/Logger/Makefile.am @@ -0,0 +1,15 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +SUBDIRS = \ + Acceptor-server \ + client \ + simple-server + diff --git a/ACE/examples/Logger/README b/ACE/examples/Logger/README new file mode 100644 index 00000000000..bac9aa1d127 --- /dev/null +++ b/ACE/examples/Logger/README @@ -0,0 +1,32 @@ +This directory contains a simple client/server implementation of the +distributed logging server described in several papers in the C++ +Report (which can be obtained via the following WWW URLs: +http://www.cs.wustl.edu/~schmidt/{Reactor1-93.ps.gz,Reactor2-93.ps.gz}). + +The example consists of the following directories: + + . client + + This program talks directly to the server logging + daemon. The server daemon must be started before you + can run this test. + + . simple-server + + This program runs a simple, non-templated, + single-threaded Reactive implementation of the + distributed logging server daemon. + + . Acceptor-server + + This program runs templated, Acceptor-based + single-threaded Reactive implementation of the + distributed logging server daemon. + +To see a more complex solution that implements the design described in +the C++ Report articles, please see the: + +$ACE_ROOT/netsvcs/{clients,lib,servers} + +directories. + diff --git a/ACE/examples/Logger/client/.cvsignore b/ACE/examples/Logger/client/.cvsignore new file mode 100644 index 00000000000..6c538132cc9 --- /dev/null +++ b/ACE/examples/Logger/client/.cvsignore @@ -0,0 +1,2 @@ +logging_app +logging_app diff --git a/ACE/examples/Logger/client/Logger_client.mpc b/ACE/examples/Logger/client/Logger_client.mpc new file mode 100644 index 00000000000..ec75f197b14 --- /dev/null +++ b/ACE/examples/Logger/client/Logger_client.mpc @@ -0,0 +1,6 @@ +// -*- MPC -*- +// $Id$ + +project : aceexe { + exename = logging_app +}
\ No newline at end of file diff --git a/ACE/examples/Logger/client/Makefile.am b/ACE/examples/Logger/client/Makefile.am new file mode 100644 index 00000000000..d38d5699588 --- /dev/null +++ b/ACE/examples/Logger/client/Makefile.am @@ -0,0 +1,33 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +ACE_BUILDDIR = $(top_builddir) +ACE_ROOT = $(top_srcdir) + +## Makefile.Logger_client.am +noinst_PROGRAMS = logging_app + +logging_app_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +logging_app_SOURCES = \ + logging_app.cpp + +logging_app_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Clean up template repositories, etc. +clean-local: + -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.* + -rm -f gcctemp.c gcctemp so_locations *.ics + -rm -rf cxx_repository ptrepository ti_files + -rm -rf templateregistry ir.out + -rm -rf ptrepository SunWS_cache Templates.DB diff --git a/ACE/examples/Logger/client/logging_app.cpp b/ACE/examples/Logger/client/logging_app.cpp new file mode 100644 index 00000000000..ba5bb24295e --- /dev/null +++ b/ACE/examples/Logger/client/logging_app.cpp @@ -0,0 +1,59 @@ +// $Id$ + +// This program sends logging records directly to the server, rather +// than going through the client logging daemon. + +#include "ace/SOCK_Connector.h" +#include "ace/Log_Record.h" +#include "ace/Log_Msg.h" +#include "ace/OS_NS_time.h" +#include "ace/OS_NS_stdio.h" +#include "ace/OS_NS_stdlib.h" +#include "ace/OS_NS_unistd.h" + +ACE_RCSID(client, logging_app, "$Id$") + +static u_short LOGGER_PORT = ACE_DEFAULT_SERVER_PORT; +static const ACE_TCHAR *const LOGGER_HOST = ACE_DEFAULT_SERVER_HOST; +static const int MAX_ITERATIONS = 10; + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + const ACE_TCHAR *logger_host = argc > 1 ? argv[1] : LOGGER_HOST; + u_short logger_port = argc > 2 ? ACE_OS::atoi (argv[2]) : LOGGER_PORT; + int max_iterations = argc > 3 ? ACE_OS::atoi (argv[3]) : MAX_ITERATIONS; + + ACE_SOCK_Stream logger; + ACE_SOCK_Connector connector; + ACE_INET_Addr addr (logger_port, logger_host); + + if (connector.connect (logger, addr) == -1) + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("open")), -1); + + for (int i = 0; i < max_iterations; i++) + { + ACE_Log_Record log_record (LM_DEBUG, + ACE_OS::time ((time_t *) 0), + ACE_OS::getpid ()); + + ACE_TCHAR buf[BUFSIZ]; + ACE_OS::sprintf (buf, ACE_TEXT ("message = %d\n"), i + 1); + log_record.msg_data (buf); + size_t len = log_record.length (); + size_t encoded_len = htonl (len); + + log_record.encode (); + + if (logger.send (4, &encoded_len, sizeof encoded_len, + (char *) &log_record, len) == -1) + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("send")),-1); + else + ACE_OS::sleep (1); + } + + if (logger.close () == -1) + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("close")), -1); + + return 0; +} diff --git a/ACE/examples/Logger/simple-server/.cvsignore b/ACE/examples/Logger/simple-server/.cvsignore new file mode 100644 index 00000000000..76c31d8c56f --- /dev/null +++ b/ACE/examples/Logger/simple-server/.cvsignore @@ -0,0 +1,2 @@ +server_loggerd +server_loggerd diff --git a/ACE/examples/Logger/simple-server/Logger_Simple_Server.mpc b/ACE/examples/Logger/simple-server/Logger_Simple_Server.mpc new file mode 100644 index 00000000000..1e4d8240e38 --- /dev/null +++ b/ACE/examples/Logger/simple-server/Logger_Simple_Server.mpc @@ -0,0 +1,6 @@ +// -*- MPC -*- +// $Id$ + +project : aceexe { + exename = server_loggerd +}
\ No newline at end of file diff --git a/ACE/examples/Logger/simple-server/Logging_Acceptor.cpp b/ACE/examples/Logger/simple-server/Logging_Acceptor.cpp new file mode 100644 index 00000000000..7e5e0d0075c --- /dev/null +++ b/ACE/examples/Logger/simple-server/Logging_Acceptor.cpp @@ -0,0 +1,85 @@ +// $Id$ + +#include "ace/WFMO_Reactor.h" +#include "ace/Log_Msg.h" + +#include "Logging_Acceptor.h" +#include "Logging_Handler.h" +#include "Reactor_Singleton.h" + +ACE_RCSID(simple_server, Logging_Acceptor, "$Id$") + +// Initialize peer_acceptor object. + +int +Logging_Acceptor::open (const ACE_INET_Addr &addr) +{ + // Reuse addr if already in use. + if (this->peer_acceptor_.open (addr, 1) == -1) + return -1; + else + return 0; +} + +// Default constructor. + +Logging_Acceptor::Logging_Acceptor (void) +{ +} + +// Performs termination activities. + +int +Logging_Acceptor::handle_close (ACE_HANDLE, ACE_Reactor_Mask) +{ + this->peer_acceptor_.close (); + // Note, this object MUST be allocated dynamically! + delete this; + return 0; +} + +Logging_Acceptor::~Logging_Acceptor (void) +{ +} + +// Returns underlying device descriptor. + +ACE_HANDLE +Logging_Acceptor::get_handle (void) const +{ + return this->peer_acceptor_.get_handle (); +} + +// Accepts connections from client and registers new object with the +// ACE_Reactor. + +int +Logging_Acceptor::handle_input (ACE_HANDLE) +{ + Logging_Handler *svc_handler; + + ACE_NEW_RETURN (svc_handler, Logging_Handler, -1); + + // Accept the connection from a client client daemon. + + // Try to find out if the implementation of the reactor that we are + // using requires us to reset the event association for the newly + // created handle. This is because the newly created handle will + // inherit the properties of the listen handle, including its event + // associations. + int reset_new_handle = this->reactor ()->uses_event_associations (); + + if (this->peer_acceptor_.accept (svc_handler->peer (), // stream + 0, // remote address + 0, // timeout + 1, // restart + reset_new_handle // reset new handler + ) == -1 + || svc_handler->open () == -1) + { + svc_handler->close (); + ACE_ERROR_RETURN ((LM_ERROR, "%p", "accept/open failed"), -1); + } + + return 0; +} diff --git a/ACE/examples/Logger/simple-server/Logging_Acceptor.h b/ACE/examples/Logger/simple-server/Logging_Acceptor.h new file mode 100644 index 00000000000..0424a7c3889 --- /dev/null +++ b/ACE/examples/Logger/simple-server/Logging_Acceptor.h @@ -0,0 +1,59 @@ +/* -*- C++ -*- */ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// examples +// +// = FILENAME +// Logging_Acceptor.h +// +// = AUTHOR +// Doug Schmidt +// +// ============================================================================ + +#ifndef _CLIENT_ACCEPTOR_H +#define _CLIENT_ACCEPTOR_H + +#include "ace/SOCK_Acceptor.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Event_Handler.h" + +class Logging_Acceptor : public ACE_Event_Handler + // = TITLE + // Handle connection requests from remote client clients. + // + // = DESCRIPTION + // Accepts client connection requests, creates Logging_Handler's + // to process them, and registers these Handlers with the + // ACE_Reactor Singleton. +{ +friend class Logging_Handler; +public: + Logging_Acceptor (void); + // Constructor. + + int open (const ACE_INET_Addr &a); + // Initialization. + +private: + // = Demuxing hooks. + virtual int handle_input (ACE_HANDLE); + virtual int handle_close (ACE_HANDLE, ACE_Reactor_Mask); + virtual ACE_HANDLE get_handle (void) const; + + ~Logging_Acceptor (void); + // By making this private we ensure that the <Logging_Acceptor> is + // allocated dynamically. + + ACE_SOCK_Acceptor peer_acceptor_; + // Passive connection acceptor factory. +}; + +#endif /* _CLIENT_ACCEPTOR_H */ diff --git a/ACE/examples/Logger/simple-server/Logging_Handler.cpp b/ACE/examples/Logger/simple-server/Logging_Handler.cpp new file mode 100644 index 00000000000..111a26248fc --- /dev/null +++ b/ACE/examples/Logger/simple-server/Logging_Handler.cpp @@ -0,0 +1,164 @@ +// $Id$ + +#include "ace/Log_Msg.h" + +#include "Logging_Handler.h" +#include "Reactor_Singleton.h" +#include "ace/Log_Record.h" +#include "ace/OS_NS_string.h" + +ACE_RCSID(simple_server, Logging_Handler, "$Id$") + +// Default constructor. + +Logging_Handler::Logging_Handler (void) +{ +} + +Logging_Handler::~Logging_Handler (void) +{ + // Make sure there are no timers. + REACTOR::instance ()->cancel_timer (this); + + this->cli_stream_.close (); +} + +// Extract the underlying ACE_SOCK_Stream (e.g., for purposes of +// accept()). + +ACE_SOCK_Stream & +Logging_Handler::peer (void) +{ + return this->cli_stream_; +} + +int +Logging_Handler::handle_timeout (const ACE_Time_Value &, + const void *arg) +{ +#if defined (ACE_NDEBUG) + ACE_UNUSED_ARG (arg); +#endif /* ACE_NDEBUG */ + + ACE_ASSERT (arg == this); + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) handling timeout from this = %@\n"), + this)); + return 0; +} + +// Perform the logging record receive. + +int +Logging_Handler::handle_input (ACE_HANDLE) +{ + ssize_t n; + size_t len; + + // Perform two recv's to emulate record-oriented semantics. Note + // that this code is not entirely portable since it relies on the + // fact that sizeof (ssize_t) is the same on both the sender and + // receiver side. To correctly handle this is painful, and we leave + // it as an exercise for the reader ;-). + + switch (n = this->cli_stream_.recv ((void *) &len, sizeof len)) + { + case -1: + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("(%P|%t) %p at host %C\n"), + ACE_TEXT ("client logger"), this->host_name_), -1); + /* NOTREACHED */ + case 0: + ACE_ERROR_RETURN ((LM_ERROR, + "(%P|%t) closing log daemon at host %s (fd = %d)\n", + this->host_name_, this->get_handle ()), -1); + /* NOTREACHED */ + case sizeof (size_t): + { + ACE_Log_Record lp; + + len = ntohl (len); + n = this->cli_stream_.recv_n ((void *) &lp, len); + if (n != (ssize_t) len) + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("(%P|%t) %p at host %C\n"), + ACE_TEXT ("client logger"), this->host_name_), -1); + /* NOTREACHED */ + + lp.decode (); + + if (lp.length () == n) + { + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) "))); + lp.print (ACE_TEXT_CHAR_TO_TCHAR (this->host_name_), 1); + } + else + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("(%P|%t) error, lp.length = %d, n = %d\n"), + lp.length (), n)); + break; + } + default: + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("(%P|%t) %p at host %C\n"), + ACE_TEXT ("client logger"), this->host_name_), -1); + /* NOTREACHED */ + } + + return 0; +} + +// Extract underlying device descriptor. + +ACE_HANDLE +Logging_Handler::get_handle (void) const +{ + return this->cli_stream_.get_handle (); +} + +int +Logging_Handler::open (void) +{ + ACE_INET_Addr addr; + + if (this->cli_stream_.get_remote_addr (addr) == -1) + return -1; + else + { + ACE_OS::strncpy (this->host_name_, + addr.get_host_name (), + MAXHOSTNAMELEN + 1); + + if (REACTOR::instance ()->register_handler (this, READ_MASK) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("(%P|%t) can't register with reactor\n")), + -1); + else if (REACTOR::instance ()->schedule_timer + (this, (const void *) this, + ACE_Time_Value (2), + ACE_Time_Value (2)) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("(%P|%t) can't register with reactor\n")), + -1); + else + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) connected with %C\n"), + this->host_name_)); + return 0; + } +} + +// Perform termination activities when deregistered from the +// ACE_Reactor. + +int +Logging_Handler::handle_close (ACE_HANDLE, ACE_Reactor_Mask) +{ + // Must have been allocated dynamically + delete this; + return 0; +} + +// Perform termination activities when close fails. + +int +Logging_Handler::close (void) +{ + return this->handle_close (); +} diff --git a/ACE/examples/Logger/simple-server/Logging_Handler.h b/ACE/examples/Logger/simple-server/Logging_Handler.h new file mode 100644 index 00000000000..633e04a167c --- /dev/null +++ b/ACE/examples/Logger/simple-server/Logging_Handler.h @@ -0,0 +1,71 @@ +/* -*- C++ -*- */ +// $Id$ + + +// ============================================================================ +// +// = LIBRARY +// examples +// +// = FILENAME +// Logging_Handler.h +// +// = AUTHOR +// Doug Schmidt +// +// ============================================================================ + +#ifndef _CLIENT_HANDLER_H +#define _CLIENT_HANDLER_H + +#include "ace/Event_Handler.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/INET_Addr.h" +#include "ace/SOCK_Stream.h" +#include "ace/os_include/os_netdb.h" + +class Logging_Handler : public ACE_Event_Handler + // = TITLE + // Receive client message from the remote clients. + // + // = DESCRIPTION + // This class demonstrates how to receive messages from remote + // clients using the notification mechanisms in the + // <ACE_Reactor>. In addition, it also illustrates how to + // utilize the <ACE_Reactor> timer mechanisms, as well. +{ +public: + Logging_Handler (void); + + // = Hooks for opening and closing handlers. + virtual int open (void); + virtual int close (void); + + ACE_SOCK_Stream &peer (void); + // Conversion operators. + +protected: + // = Demultiplexing hooks. + virtual ACE_HANDLE get_handle (void) const; + virtual int handle_input (ACE_HANDLE); + virtual int handle_close (ACE_HANDLE = ACE_INVALID_HANDLE, + ACE_Reactor_Mask = ACE_Event_Handler::ALL_EVENTS_MASK); + virtual int handle_timeout (const ACE_Time_Value &tv, const void *arg); + + // = Really should be private... + virtual ~Logging_Handler (void); + // Ensure dynamic allocation. + +private: + char host_name_[MAXHOSTNAMELEN + 1]; + // Host we are connected to. + + ACE_SOCK_Stream cli_stream_; + // Connection with client +}; + +#endif /* _CLIENT_HANDLER_H */ diff --git a/ACE/examples/Logger/simple-server/Makefile.am b/ACE/examples/Logger/simple-server/Makefile.am new file mode 100644 index 00000000000..a018d587b98 --- /dev/null +++ b/ACE/examples/Logger/simple-server/Makefile.am @@ -0,0 +1,38 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +ACE_BUILDDIR = $(top_builddir) +ACE_ROOT = $(top_srcdir) + +## Makefile.Logger_Simple_Server.am +noinst_PROGRAMS = server_loggerd + +server_loggerd_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +server_loggerd_SOURCES = \ + Logging_Acceptor.cpp \ + Logging_Handler.cpp \ + server_loggerd.cpp \ + Logging_Acceptor.h \ + Logging_Handler.h \ + Reactor_Singleton.h + +server_loggerd_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Clean up template repositories, etc. +clean-local: + -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.* + -rm -f gcctemp.c gcctemp so_locations *.ics + -rm -rf cxx_repository ptrepository ti_files + -rm -rf templateregistry ir.out + -rm -rf ptrepository SunWS_cache Templates.DB diff --git a/ACE/examples/Logger/simple-server/Reactor_Singleton.h b/ACE/examples/Logger/simple-server/Reactor_Singleton.h new file mode 100644 index 00000000000..ec0653125a9 --- /dev/null +++ b/ACE/examples/Logger/simple-server/Reactor_Singleton.h @@ -0,0 +1,33 @@ +/* -*- C++ -*- */ +// $Id$ + + +// ============================================================================ +// +// = LIBRARY +// examples +// +// = FILENAME +// Reactor_Singleton.h +// +// = AUTHOR +// Doug Schmidt +// +// ============================================================================ + +#ifndef _REACTOR_SINGLETON_H +#define _REACTOR_SINGLETON_H + +#include "ace/Singleton.h" +#include "ace/Null_Mutex.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Reactor.h" + +// Our global Reactor Singleton. +typedef ACE_Singleton<ACE_Reactor, ACE_Null_Mutex> REACTOR; + +#endif /* _REACTOR_SINGLETON_H */ diff --git a/ACE/examples/Logger/simple-server/server_loggerd.cpp b/ACE/examples/Logger/simple-server/server_loggerd.cpp new file mode 100644 index 00000000000..f323a2f3826 --- /dev/null +++ b/ACE/examples/Logger/simple-server/server_loggerd.cpp @@ -0,0 +1,85 @@ +// $Id$ + +// This server daemon collects, formats, and displays logging +// information forwarded from client daemons running on other hosts in +// the network. +// +// In addition, it also illustrates how the ACE_Reactor framework is +// used. + +#include "ace/Get_Opt.h" +#include "ace/Log_Msg.h" +#include "ace/Signal.h" + +#include "Logging_Acceptor.h" +#include "Reactor_Singleton.h" + +ACE_RCSID(simple_server, server_loggerd, "$Id$") + +static sig_atomic_t finished = 0; + +extern "C" void +handler (int) +{ + finished = 1; +} + +// It doesn't get anymore const than this.... +static const u_short PORT = ACE_DEFAULT_SERVER_PORT; + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + // Register a signal handler. + ACE_Sig_Action sa ((ACE_SignalHandler) handler, SIGINT); + ACE_UNUSED_ARG (sa); + + Logging_Acceptor *peer_acceptor; + ACE_NEW_RETURN (peer_acceptor, + Logging_Acceptor, + 1); + + ACE_INET_Addr addr (PORT); + + ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("p:")); + + for (int c; (c = get_opt ()) != -1; ) + switch (c) + { + case 'p': + addr.set (ACE_OS::atoi (get_opt.opt_arg ())); + break; + default: + break; + } + + if (peer_acceptor->open (addr) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("open")), + -1); + else if (REACTOR::instance ()->register_handler + (peer_acceptor, + ACE_Event_Handler::ACCEPT_MASK) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("registering service with ACE_Reactor\n")), + -1); + + // Run forever, performing the logging service. + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) starting up server logging daemon\n"))); + + while (!finished) + REACTOR::instance ()->handle_events (); + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) shutting down server logging daemon\n"))); + return 0; +} + + +#if defined (ACE_HAS_EXPLICIT_STATIC_TEMPLATE_MEMBER_INSTANTIATION) +template ACE_Singleton<ACE_Reactor, ACE_Null_Mutex> * + ACE_Singleton<ACE_Reactor, ACE_Null_Mutex>::singleton_; +#endif /* ACE_HAS_EXPLICIT_STATIC_TEMPLATE_MEMBER_INSTANTIATION */ diff --git a/ACE/examples/Makefile.am b/ACE/examples/Makefile.am new file mode 100644 index 00000000000..1e8ba6f626f --- /dev/null +++ b/ACE/examples/Makefile.am @@ -0,0 +1,43 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +SUBDIRS = \ + APG \ + ASX \ + Bounded_Packet_Relay \ + C++NPv1 \ + C++NPv2 \ + Connection \ + DLL \ + Export \ + IOStream \ + IPC_SAP \ + Log_Msg \ + Logger \ + Map_Manager \ + Mem_Map \ + Misc \ + NT_Service \ + Naming \ + OS \ + QOS \ + Reactor \ + Registry \ + Service_Configurator \ + Shared_Malloc \ + Shared_Memory \ + Smart_Pointers \ + Synch \ + System_V_IPC \ + TMCast \ + Threads \ + Timer_Queue \ + Web_Crawler + diff --git a/ACE/examples/Map_Manager/Makefile.am b/ACE/examples/Map_Manager/Makefile.am new file mode 100644 index 00000000000..d5f39e68514 --- /dev/null +++ b/ACE/examples/Map_Manager/Makefile.am @@ -0,0 +1,33 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +ACE_BUILDDIR = $(top_builddir) +ACE_ROOT = $(top_srcdir) + +## Makefile.Map_Manager.am +noinst_PROGRAMS = Map_Manager + +Map_Manager_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +Map_Manager_SOURCES = \ + test_hash_map_manager.cpp + +Map_Manager_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Clean up template repositories, etc. +clean-local: + -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.* + -rm -f gcctemp.c gcctemp so_locations *.ics + -rm -rf cxx_repository ptrepository ti_files + -rm -rf templateregistry ir.out + -rm -rf ptrepository SunWS_cache Templates.DB diff --git a/ACE/examples/Map_Manager/Map_Manager.mpc b/ACE/examples/Map_Manager/Map_Manager.mpc new file mode 100644 index 00000000000..3a433cab0d4 --- /dev/null +++ b/ACE/examples/Map_Manager/Map_Manager.mpc @@ -0,0 +1,6 @@ +// -*- MPC -*- +// $Id$ + +project: aceexe { + exename = Map_Manager +} diff --git a/ACE/examples/Map_Manager/test_hash_map_manager.cpp b/ACE/examples/Map_Manager/test_hash_map_manager.cpp new file mode 100644 index 00000000000..91e08e5c58c --- /dev/null +++ b/ACE/examples/Map_Manager/test_hash_map_manager.cpp @@ -0,0 +1,80 @@ +// $Id$ + +#include "ace/OS_main.h" +#include "ace/Hash_Map_Manager.h" +#include "ace/ACE.h" +#include "ace/SString.h" +#include "ace/Synch.h" +#include "ace/Synch_Traits.h" +#include "ace/OS_NS_stdio.h" +#include "ace/os_include/os_assert.h" + +ACE_RCSID(Map_Manager, test_hash_map_manager, "$Id$") + +const int MAX_KEY_LEN = 1000; + +typedef ACE_Hash_Map_Manager<ACE_TString, ACE_TString, ACE_SYNCH_RW_MUTEX> MAP_MANAGER; + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + if (argc != 4) + ACE_ERROR_RETURN ((LM_ERROR, "usage: %s tablesize file1 file2\n", + argv[0]), -1); + else + { + int total = ACE_OS::atoi (argv[1]); + + if (!ACE_OS::freopen (argv[2], ACE_TEXT("r"), stdin)) + ACE_OS::perror (argv[0]), ACE_OS::exit (1); + + MAP_MANAGER hash (total); + + ACE_TCHAR key[MAX_KEY_LEN]; + + while (ACE_OS::fgets (key, sizeof key, stdin)) + // stream ops are just too slow!! + { + ACE_TString string (key); + hash.bind (string, string); + } + + fclose (stdin); + + MAP_MANAGER::ITERATOR iterator (hash); + + for (MAP_MANAGER::ENTRY *entry = 0; + iterator.next (entry) != 0; + iterator.advance ()) + ACE_DEBUG ((LM_DEBUG, "%s %s\n", + entry->ext_id_.fast_rep (), + entry->int_id_.fast_rep ())); + + if (!ACE_OS::freopen (argv[3], ACE_TEXT("r"), stdin)) + ACE_OS::perror (argv[0]), exit (1); + + while (ACE_OS::fgets (key, sizeof key, stdin)) + { + ACE_TString name (key); + ACE_TString value; + assert (hash.find (name, value) != -1); + assert (name == value); + } + + if (!ACE_OS::freopen (argv[3], ACE_TEXT("r"), stdin)) + ACE_OS::perror (argv[0]), exit (1); + + while (ACE_OS::fgets (key, sizeof key, stdin)) + { + ACE_TString string (key); + assert (hash.unbind (string) != -1); + } + + assert (hash.current_size () == 0); + + fclose (stdin); + } + + return 0; +} + diff --git a/ACE/examples/Mem_Map/IO-tests/.cvsignore b/ACE/examples/Mem_Map/IO-tests/.cvsignore new file mode 100644 index 00000000000..80ea1892dab --- /dev/null +++ b/ACE/examples/Mem_Map/IO-tests/.cvsignore @@ -0,0 +1,2 @@ +test_io +test_io diff --git a/ACE/examples/Mem_Map/IO-tests/IO_Test.cpp b/ACE/examples/Mem_Map/IO-tests/IO_Test.cpp new file mode 100644 index 00000000000..86f2596098e --- /dev/null +++ b/ACE/examples/Mem_Map/IO-tests/IO_Test.cpp @@ -0,0 +1,240 @@ +// $Id$ + +#if !defined(_WIN32) + +#include "ace/OS_NS_string.h" +#include "ace/OS_NS_unistd.h" +#include "ace/OS_NS_stdio.h" +#include "ace/Mem_Map.h" +#include "ace/Log_Msg.h" +#include "IO_Test.h" + +ACE_RCSID(IO_tests, IO_Test, "$Id$") + + + +IO_Test::IO_Test (const char *name, + ACE_Profile_Timer &tm) + : name_ (name), tm_ (tm) +{ +} + +IO_Test::~IO_Test (void) +{ +} + +const char * +IO_Test::name (void) +{ + return this->name_; +} + +Slow_Read_Write_Test::Slow_Read_Write_Test (const char *name, + ACE_Profile_Timer &tm) + : IO_Test (name, tm) +{ +} + +int +Slow_Read_Write_Test::run_test (int iterations, + FILE *input_fp, + FILE *output_fp) +{ + ACE_HANDLE ifd = fileno (input_fp); + ACE_HANDLE ofd = fileno (output_fp); + + this->tm_.start (); + + while (--iterations >= 0) + { + char c; + + while (ACE_OS::read (ifd, &c, sizeof c) > 0) + ::write (ofd, &c, sizeof c); + + ACE_OS::lseek (ifd, 0, SEEK_SET); + ACE_OS::lseek (ofd, 0, SEEK_SET); + } + + this->tm_.stop (); + return 0; +} + +Stdio_Test::Stdio_Test (const char *name, + ACE_Profile_Timer &tm) + : IO_Test (name, tm) +{ +} + +int +Stdio_Test::run_test (int iterations, + FILE *input_fp, + FILE *output_fp) +{ + this->tm_.start (); + + while (--iterations >= 0) + { + int c; + + while ((c = getc (input_fp)) != EOF) + putc (c, output_fp); + + ACE_OS::rewind (input_fp); + ACE_OS::rewind (output_fp); + } + this->tm_.stop (); + return 0; +} + +Block_Read_Write_Test::Block_Read_Write_Test (const char *name, + ACE_Profile_Timer &tm) + : IO_Test (name, tm) +{ +} + +int +Block_Read_Write_Test::run_test (int iterations, + FILE *input_fp, + FILE *output_fp) +{ + int ifd = fileno (input_fp); + int ofd = fileno (output_fp); + + this->tm_.start (); + + while (--iterations >= 0) + { + char buf[BUFSIZ]; + ssize_t n; + + while ((n = ACE_OS::read (ifd, + buf, + sizeof buf)) > 0) + ::write (ofd, buf, n); + + ACE_OS::lseek (ifd, 0, SEEK_SET); + ACE_OS::lseek (ofd, 0, SEEK_SET); + } + + this->tm_.stop (); + return 0; +} + +Block_Fread_Fwrite_Test::Block_Fread_Fwrite_Test (const char *name, + ACE_Profile_Timer &tm) + : IO_Test (name, tm) +{ +} + +int +Block_Fread_Fwrite_Test::run_test (int iterations, + FILE *input_fp, + FILE *output_fp) +{ + this->tm_.start (); + + while (--iterations >= 0) + { + char buf[BUFSIZ]; + ssize_t n; + + while ((n = ACE_OS::fread (buf, + 1, + sizeof buf, + input_fp)) != 0) + ::fwrite (buf, n, 1, output_fp); + + ACE_OS::rewind (input_fp); + ACE_OS::rewind (output_fp); + } + + this->tm_.stop (); + return 0; +} + +Mmap1_Test::Mmap1_Test (const char *name, + ACE_Profile_Timer &tm) + : IO_Test (name, tm) +{ +} + +int +Mmap1_Test::run_test (int iterations, + FILE *input_fp, + FILE *output_fp) +{ + ACE_Mem_Map map_input (fileno (input_fp)); + void *src = map_input.addr (); + + if (src == MAP_FAILED) + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%C"), this->name ()), -1); + else + { + this->tm_.start (); + + while (--iterations >= 0) + { + if (ACE_OS::write (fileno (output_fp), + src, + map_input.size ()) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%C"), + this->name ()), + -1); + ACE_OS::lseek (fileno (output_fp), + 0, + SEEK_SET); + } + + this->tm_.stop (); + } + + if (map_input.unmap () == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%C"), + this->name ()), + -1); + else + return 0; +} + +Mmap2_Test::Mmap2_Test (const char *name, + ACE_Profile_Timer &tm) + : IO_Test (name, tm) +{ +} + +int +Mmap2_Test::run_test (int iterations, + FILE *input_fp, + FILE *output_fp) +{ + ACE_Mem_Map map_input (fileno (input_fp)); + int size = map_input.size (); + ACE_Mem_Map map_output (fileno (output_fp), + size, + PROT_WRITE, + MAP_SHARED); + void *src = map_input.addr (); + void *dst = map_output.addr (); + + if (src == MAP_FAILED || dst == MAP_FAILED) + return -1; + else + { + this->tm_.start (); + + while (--iterations >= 0) + ACE_OS::memcpy (dst, src, size); + + this->tm_.stop (); + } + + if (map_input.unmap () == -1 + || map_output.unmap () == -1) + return -1; + else + return 0; +} +#endif diff --git a/ACE/examples/Mem_Map/IO-tests/IO_Test.h b/ACE/examples/Mem_Map/IO-tests/IO_Test.h new file mode 100644 index 00000000000..3c130b32363 --- /dev/null +++ b/ACE/examples/Mem_Map/IO-tests/IO_Test.h @@ -0,0 +1,100 @@ +/* -*- C++ -*- */ +// $Id$ + +/* Class hierarchy for the File I/O tests. */ + +#include "ace/Profile_Timer.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +/* Base class for all the File I/O tests. */ + +class IO_Test +{ +public: + + // Initialize the test name + IO_Test (const char *name, + ACE_Profile_Timer &tm); + + // Destructor. + virtual ~IO_Test (void); + + // Return the name of the test + const char *name (void); + + // Execute the IO test (note this is a pure virtual function...) + virtual int run_test (int iterations, + FILE *input_fp, + FILE *output_fp) = 0; + +protected: + // Name of the test + const char *name_; + + // Reference to a timer + ACE_Profile_Timer &tm_; +}; + +class Slow_Read_Write_Test : public IO_Test +{ +public: + Slow_Read_Write_Test (const char *name, + ACE_Profile_Timer &tm); + virtual int run_test (int iterations, + FILE *input_fp, + FILE *output_fp); +}; + +class Stdio_Test : public IO_Test +{ +public: + Stdio_Test (const char *name, + ACE_Profile_Timer &tm); + virtual int run_test (int iterations, + FILE *input_fp, + FILE *output_fp); +}; + +class Block_Read_Write_Test : public IO_Test +{ +public: + Block_Read_Write_Test (const char *name, + ACE_Profile_Timer &tm); + virtual int run_test (int iterations, + FILE *input_fp, + FILE *output_fp); +}; + +class Block_Fread_Fwrite_Test : public IO_Test +{ +public: + Block_Fread_Fwrite_Test (const char *name, + ACE_Profile_Timer &tm); + virtual int run_test (int iterations, + FILE *input_fp, + FILE *output_fp); +}; + +class Mmap1_Test : public IO_Test +{ +public: + Mmap1_Test (const char *name, + ACE_Profile_Timer &tm); + virtual int run_test (int iterations, + FILE *input_fp, + FILE *output_fp); +}; + +class Mmap2_Test : public IO_Test +{ +public: + Mmap2_Test (const char *name, + ACE_Profile_Timer &tm); + virtual int run_test (int iterations, + FILE *input_fp, + FILE *output_fp); +}; + diff --git a/ACE/examples/Mem_Map/IO-tests/Makefile.am b/ACE/examples/Mem_Map/IO-tests/Makefile.am new file mode 100644 index 00000000000..9a6e3638c29 --- /dev/null +++ b/ACE/examples/Mem_Map/IO-tests/Makefile.am @@ -0,0 +1,40 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +ACE_BUILDDIR = $(top_builddir) +ACE_ROOT = $(top_srcdir) + + +## Makefile.Mem_Map_IO_Tests.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS = test_io + +test_io_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +test_io_SOURCES = \ + IO_Test.cpp \ + test_io.cpp \ + IO_Test.h + +test_io_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Clean up template repositories, etc. +clean-local: + -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.* + -rm -f gcctemp.c gcctemp so_locations *.ics + -rm -rf cxx_repository ptrepository ti_files + -rm -rf templateregistry ir.out + -rm -rf ptrepository SunWS_cache Templates.DB diff --git a/ACE/examples/Mem_Map/IO-tests/Mem_Map_IO_Tests.mpc b/ACE/examples/Mem_Map/IO-tests/Mem_Map_IO_Tests.mpc new file mode 100644 index 00000000000..6e2bcc9f3aa --- /dev/null +++ b/ACE/examples/Mem_Map/IO-tests/Mem_Map_IO_Tests.mpc @@ -0,0 +1,6 @@ +// -*- MPC -*- +// $Id$ + +project : aceexe { + avoids += ace_for_tao +} diff --git a/ACE/examples/Mem_Map/IO-tests/test_io.cpp b/ACE/examples/Mem_Map/IO-tests/test_io.cpp new file mode 100644 index 00000000000..b60401cc813 --- /dev/null +++ b/ACE/examples/Mem_Map/IO-tests/test_io.cpp @@ -0,0 +1,211 @@ +// $Id$ + +// Test program for different methods of copying files. + +#include "ace/OS_NS_stdio.h" +#include "ace/OS_NS_unistd.h" +#include "ace/ACE.h" +#include "ace/Profile_Timer.h" +#include "ace/Get_Opt.h" +#include "ace/Signal.h" +#include "ace/Log_Msg.h" +#include "IO_Test.h" + +ACE_RCSID(IO_tests, test_io, "$Id$") + +#if !defined(_WIN32) + +// Name of program. +static const ACE_TCHAR *program_name; + +// Name of default input file. +static const ACE_TCHAR *input_filename = ACE_TEXT ("/usr/dict/words"); + +// Name of default output file. +static const ACE_TCHAR *output_filename = ACE_TEXT ("/tmp/foo"); + +// Check if removing output file upon completion... +static int remove_output = 1; + +// Count of the number of iterations to run the tests. +static int iteration_count = 100; + +// Profiler used to keep track of file I/O time. +static ACE_Profile_Timer profile_timer; + +// Explain usage and exit. + +static void +print_usage_and_die (void) +{ + ACE_OS::fprintf (stderr, "usage: %s" + " [-i input_file] [-o output_file] [-n iteration_count] [-r]\n", + ACE_TEXT_ALWAYS_CHAR (program_name)); + ACE_OS::exit (1); +} + +// Clean up the output file on exit from a signal. + +extern "C" void +cleanup (int = 0) +{ + if (remove_output) + ACE_OS::unlink (output_filename); + ACE_OS::exit (0); +} + +// Parse the command-line arguments and set options. + +static void +parse_args (int argc, ACE_TCHAR *argv[]) +{ + ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("i:n:o:r")); + + for (int c; ((c = get_opt ()) != -1); ) + switch (c) + { + case 'i': + input_filename = get_opt.opt_arg (); + break; + case 'n': + iteration_count = ACE_OS::atoi (get_opt.opt_arg ()); + break; + case 'o': + output_filename = get_opt.opt_arg (); + break; + case 'r': + remove_output = 0; + break; + default: + print_usage_and_die (); + break; + } +} + +// Vector of pointers to derived classes that inherit from IO_Test +// base class. + +static IO_Test *test_vector[100]; + +static int +run_tests (int iterations, FILE *input_fp, FILE *output_fp) +{ + int i = 0; + + ACE_NEW_RETURN (test_vector[i], + Stdio_Test ("Stdio_Test", + profile_timer), + -1); + i++; + ACE_NEW_RETURN (test_vector[i], + Block_Fread_Fwrite_Test ("Block_Fread_Fwrite_Test", + profile_timer), + -1); + i++; + ACE_NEW_RETURN (test_vector[i], + Block_Read_Write_Test ("Block_Read_Write_Test", + profile_timer), + -1); + i++; + ACE_NEW_RETURN (test_vector[i], + Mmap1_Test ("Mmap1_Test", + profile_timer), + -1); + i++; + ACE_NEW_RETURN (test_vector[i], + Mmap2_Test ("Mmap2_Test", + profile_timer), + -1); + i++; + ACE_NEW_RETURN (test_vector[i], + Slow_Read_Write_Test ("Slow_Read_Write_Test", + profile_timer), + -1); + i++; + + test_vector[i] = (IO_Test *) 0; + + for (i = 0; test_vector[i] != 0; i++) + { + ACE_HANDLE hfile = fileno (output_fp); + if (ACE_OS::ftruncate (hfile, 0) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%s\n"), + ACE_TEXT ("ftruncate")), + -1); + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("--------------------\n") + ACE_TEXT ("starting %C for %d iterations(s):\n"), + test_vector[i]->name (), + iterations)); + + test_vector[i]->run_test (iterations, + input_fp, + output_fp); + + ACE_Profile_Timer::ACE_Elapsed_Time et; + profile_timer.elapsed_time (et); + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("wallclock time = %f, user time = %f, system time = %f\n"), + et.real_time, + et.user_time, + et.system_time)); + + delete test_vector[i]; + } + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("--------------------\n"))); + return 0; +} + +int +main (int argc, ACE_TCHAR *argv[]) +{ + program_name = ACE::basename (argv[0], + ACE_DIRECTORY_SEPARATOR_CHAR); + parse_args (argc, argv); + + ACE_Sig_Action sa ((ACE_SignalHandler) cleanup, SIGINT); + ACE_UNUSED_ARG (sa); + + FILE *input_fp = + ACE_OS::fopen (input_filename, ACE_TEXT ("r")); + FILE *output_fp = + ACE_OS::fopen (output_filename, ACE_TEXT ("w+")); + + if (input_fp == 0) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + input_filename), + -1); + + if (output_fp == 0) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + output_filename), + -1); + + ACE_OS::unlink (output_filename); + + if (run_tests (iteration_count, + input_fp, + output_fp) == -1) + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("run_tests")), + -1); + + if (ACE_OS::fclose (input_fp) == -1 + || ACE_OS::fclose (output_fp) == -1) + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("fclose")), + -1); + cleanup (); + return 0; +} +#else +int ACE_TMAIN (int, ACE_TCHAR*[]) { + // not supported on win32 + return 0; +} +#endif diff --git a/ACE/examples/Mem_Map/Makefile.am b/ACE/examples/Mem_Map/Makefile.am new file mode 100644 index 00000000000..9d8830d2147 --- /dev/null +++ b/ACE/examples/Mem_Map/Makefile.am @@ -0,0 +1,14 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +SUBDIRS = \ + IO-tests \ + file-reverse + diff --git a/ACE/examples/Mem_Map/file-reverse/.cvsignore b/ACE/examples/Mem_Map/file-reverse/.cvsignore new file mode 100644 index 00000000000..cf791234c5e --- /dev/null +++ b/ACE/examples/Mem_Map/file-reverse/.cvsignore @@ -0,0 +1 @@ +file-reverse diff --git a/ACE/examples/Mem_Map/file-reverse/Makefile.am b/ACE/examples/Mem_Map/file-reverse/Makefile.am new file mode 100644 index 00000000000..02a081a6c88 --- /dev/null +++ b/ACE/examples/Mem_Map/file-reverse/Makefile.am @@ -0,0 +1,38 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +ACE_BUILDDIR = $(top_builddir) +ACE_ROOT = $(top_srcdir) + + +## Makefile.Mem_Map_File_Reverse.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS = file-reverse + +file_reverse_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +file_reverse_SOURCES = \ + file-reverse.cpp + +file_reverse_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Clean up template repositories, etc. +clean-local: + -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.* + -rm -f gcctemp.c gcctemp so_locations *.ics + -rm -rf cxx_repository ptrepository ti_files + -rm -rf templateregistry ir.out + -rm -rf ptrepository SunWS_cache Templates.DB diff --git a/ACE/examples/Mem_Map/file-reverse/Mem_Map_File_Reverse.mpc b/ACE/examples/Mem_Map/file-reverse/Mem_Map_File_Reverse.mpc new file mode 100644 index 00000000000..368866edb73 --- /dev/null +++ b/ACE/examples/Mem_Map/file-reverse/Mem_Map_File_Reverse.mpc @@ -0,0 +1,7 @@ +// -*- MPC -*- +// $Id$ + +project : aceexe { + avoids += ace_for_tao + exename = file-reverse +} diff --git a/ACE/examples/Mem_Map/file-reverse/file-reverse.cpp b/ACE/examples/Mem_Map/file-reverse/file-reverse.cpp new file mode 100644 index 00000000000..2e64c272c12 --- /dev/null +++ b/ACE/examples/Mem_Map/file-reverse/file-reverse.cpp @@ -0,0 +1,59 @@ +// $Id$ + +// Print a file in reverse by using the ACE memory mapped file +// wrapper. It is SO easy to do compared with alternatives! + +#include "ace/OS_main.h" +#include "ace/Mem_Map.h" +#include "ace/Log_Msg.h" + +ACE_RCSID(file_reverse, file_reverse, "$Id$") + +static void +putline (const char *s) +{ + while (putchar (*s++) != '\n') + continue; +} + +static void +print_array_in_reverse (char *array, + int size) +{ + if (size <= 0) + return; + + size--; + + if (array[size] == '\0') + array[size] = '\n'; + + while (--size >= 0) + if (array[size] == '\n') + putline (array + size + 1); + + putline (array); +} + +int +ACE_TMAIN (int argc, ACE_TCHAR **argv) +{ + ACE_LOG_MSG->open (argv[0]); + + if (argc != 2) + ACE_ERROR_RETURN ((LM_ERROR, + "usage: %n file\n"), + -1); + + ACE_Mem_Map mmap; + + if (mmap.map (argv[1], -1, O_RDWR) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%n: %p\n", + "mmap"), + -1); + + print_array_in_reverse ((char *) mmap.addr (), + mmap.size ()); + return 0; +} diff --git a/ACE/examples/Misc/.cvsignore b/ACE/examples/Misc/.cvsignore new file mode 100644 index 00000000000..a31a7786288 --- /dev/null +++ b/ACE/examples/Misc/.cvsignore @@ -0,0 +1,16 @@ +test_XtReactor1 +test_XtReactor2 +test_dump +test_dump +test_get_opt +test_get_opt +test_profile_timer +test_profile_timer +test_read_buffer +test_read_buffer +test_set +test_set +test_sstring +test_sstring +test_trace +test_trace diff --git a/ACE/examples/Misc/Makefile.am b/ACE/examples/Misc/Makefile.am new file mode 100644 index 00000000000..8bb0b8dc8d8 --- /dev/null +++ b/ACE/examples/Misc/Makefile.am @@ -0,0 +1,191 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +ACE_BUILDDIR = $(top_builddir) +ACE_ROOT = $(top_srcdir) + + +## Makefile.Misc_Test_Dump.am +noinst_PROGRAMS = test_dump + +test_dump_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +test_dump_SOURCES = \ + test_dump.cpp \ + test_dump.h + +test_dump_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Misc_Test_Get_Opt.am +noinst_PROGRAMS += test_get_opt + +test_get_opt_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +test_get_opt_SOURCES = \ + test_get_opt.cpp \ + test_dump.h + +test_get_opt_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Misc_Test_Profile_Timer.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS += test_profile_timer + +test_profile_timer_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +test_profile_timer_SOURCES = \ + test_profile_timer.cpp \ + test_dump.h + +test_profile_timer_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Makefile.Misc_Test_Read_Buffer.am +noinst_PROGRAMS += test_read_buffer + +test_read_buffer_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +test_read_buffer_SOURCES = \ + test_read_buffer.cpp \ + test_dump.h + +test_read_buffer_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Misc_Test_Set.am +noinst_PROGRAMS += test_set + +test_set_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +test_set_SOURCES = \ + test_set.cpp \ + test_dump.h + +test_set_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Misc_Test_Sstring.am +noinst_PROGRAMS += test_sstring + +test_sstring_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +test_sstring_SOURCES = \ + test_sstring.cpp \ + test_dump.h + +test_sstring_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Misc_Test_Trace.am +noinst_PROGRAMS += test_trace + +test_trace_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +test_trace_SOURCES = \ + test_trace.cpp \ + test_dump.h + +test_trace_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Misc_Test_XtReactor1.am + +if BUILD_ACE_XTREACTOR +if BUILD_MOTIF +if BUILD_X11 +if BUILD_XT + +noinst_PROGRAMS += test_XtReactor1 + +test_XtReactor1_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) \ + $(ACE_X11_CPPFLAGS) \ + $(ACE_XT_CPPFLAGS) + +test_XtReactor1_SOURCES = \ + test_XtReactor1.cpp \ + test_dump.h + +test_XtReactor1_LDFLAGS = \ + $(ACE_X11_LDFLAGS) $(ACE_XT_LDFLAGS) + +test_XtReactor1_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE_XtReactor.la \ + $(ACE_BUILDDIR)/ace/libACE.la \ + -lXm \ + $(ACE_XT_LIBS) \ + $(ACE_X11_LIBS) + +endif BUILD_XT +endif BUILD_X11 +endif BUILD_MOTIF +endif BUILD_ACE_XTREACTOR + +## Makefile.Misc_Test_XtReactor2.am + +if BUILD_ACE_XTREACTOR +if BUILD_MOTIF +if BUILD_X11 +if BUILD_XT + +noinst_PROGRAMS += test_XtReactor2 + +test_XtReactor2_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) \ + $(ACE_X11_CPPFLAGS) \ + $(ACE_XT_CPPFLAGS) + +test_XtReactor2_SOURCES = \ + test_XtReactor2.cpp \ + test_dump.h + +test_XtReactor2_LDFLAGS = \ + $(ACE_X11_LDFLAGS) $(ACE_XT_LDFLAGS) + +test_XtReactor2_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE_XtReactor.la \ + $(ACE_BUILDDIR)/ace/libACE.la \ + -lXm \ + $(ACE_XT_LIBS) \ + $(ACE_X11_LIBS) + +endif BUILD_XT +endif BUILD_X11 +endif BUILD_MOTIF +endif BUILD_ACE_XTREACTOR + +## Clean up template repositories, etc. +clean-local: + -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.* + -rm -f gcctemp.c gcctemp so_locations *.ics + -rm -rf cxx_repository ptrepository ti_files + -rm -rf templateregistry ir.out + -rm -rf ptrepository SunWS_cache Templates.DB diff --git a/ACE/examples/Misc/Misc.mpc b/ACE/examples/Misc/Misc.mpc new file mode 100644 index 00000000000..b0ed858efbd --- /dev/null +++ b/ACE/examples/Misc/Misc.mpc @@ -0,0 +1,66 @@ +// -*- MPC -*- +// $Id$ + +project(*test_dump) : aceexe { + exename = test_dump + Source_Files { + test_dump.cpp + } +} + +project(*test_get_opt) : aceexe { + exename = test_get_opt + Source_Files { + test_get_opt.cpp + } +} + +project(*test_profile_timer) : aceexe { + avoids += ace_for_tao + exename = test_profile_timer + Source_Files { + test_profile_timer.cpp + } +} + +project(*test_read_buffer) : aceexe { + exename = test_read_buffer + Source_Files { + test_read_buffer.cpp + } +} + +project(*test_set) : aceexe { + exename = test_set + Source_Files { + test_set.cpp + } +} + +project(*test_sstring) : aceexe { + exename = test_sstring + Source_Files { + test_sstring.cpp + } +} + +project(*test_trace) : aceexe { + exename = test_trace + Source_Files { + test_trace.cpp + } +} + +project(*test_XtReactor1) : aceexe, ace_xtreactor, ace_motif { + exename = test_XtReactor1 + Source_Files { + test_XtReactor1.cpp + } +} + +project(*test_XtReactor2) : aceexe, ace_xtreactor, ace_motif { + exename = test_XtReactor2 + Source_Files { + test_XtReactor2.cpp + } +} diff --git a/ACE/examples/Misc/test_XtReactor1.cpp b/ACE/examples/Misc/test_XtReactor1.cpp new file mode 100644 index 00000000000..f4bef54aeae --- /dev/null +++ b/ACE/examples/Misc/test_XtReactor1.cpp @@ -0,0 +1,173 @@ +// $Id$ + +// The following is another test that exercises the Eric C. Newton's +// <ecn@clark.net> XtReactor implementation. + +#include "ace/OS_main.h" +#include "ace/XtReactor.h" +#include "ace/Reactor.h" +#include "ace/Message_Block.h" +#include "ace/Log_Msg.h" +#include "ace/OS_NS_unistd.h" +#include "ace/OS_NS_fcntl.h" + +ACE_RCSID (Misc, + test_XtReactor1, + "$Id$") + +//#define String XtString +#include <Xm/PushB.h> + +class Stdout : public ACE_Event_Handler +{ +public: + Stdout (ACE_Reactor * r) + : reactor_ (r), + msg_ (1000000) // Make a very big message block. + { + int flags = ACE_OS::fcntl (ACE_STDOUT, F_GETFL); + + if (flags != -1 + && ACE_OS::fcntl (ACE_STDOUT, + F_SETFL, flags | O_NONBLOCK) != -1) + return; + else + ACE_DEBUG ((LM_DEBUG, + "Unable to set stdout to non-block.")); + } + + ACE_HANDLE get_handle (void) const { return ACE_STDOUT; } + + int handle_output (ACE_HANDLE) + { + char *s = msg_.rd_ptr (); + + if (ACE_OS::write (ACE_STDOUT, s, 1) == 1) + { + ACE_DEBUG ((LM_DEBUG, + "wrote output '%d'\n", + (int) *s)); + msg_.rd_ptr (1); + } + + if (msg_.length () == 0) + { + reactor_->remove_handler (this, + ACE_Event_Handler::WRITE_MASK); + msg_.rd_ptr (msg_.base ()); + msg_.wr_ptr (msg_.base ()); + } + return 0; + } + + void put (char c) + { + if (msg_.length () == 0) + reactor_->register_handler (this, + ACE_Event_Handler::WRITE_MASK); + + if (msg_.wr_ptr () < msg_.end ()) + { + *msg_.wr_ptr () = c; + msg_.wr_ptr (1); + } + else + ACE_DEBUG ((LM_DEBUG, + "Oops... data falling off the end of the buffer!\n")); + } + +private: + ACE_Reactor *reactor_; + ACE_Message_Block msg_; +}; + +class Stdin : public ACE_Event_Handler +{ +public: + Stdin (Stdout *out) + : out_ (out) {} + + ACE_HANDLE get_handle () const { return ACE_STDIN; } + + int handle_input (ACE_HANDLE) + { + char c; + + if (ACE_OS::read (ACE_STDIN, &c, 1) == 1) + out_->put (c); + + return 0; + } + + int handle_timeout (const ACE_Time_Value &tv, const void *) + { + ACE_DEBUG ((LM_DEBUG, + "Timeout! %f\n", + (double) (tv.msec () / 1000.))); + return 0; + } + +private: + Stdout *out_; +}; + +static void +ActivateCB (Widget, XtPointer, XtPointer) +{ + ACE_DEBUG ((LM_DEBUG, + "Button pushed!\n")); +} + +int +ACE_TMAIN (int argc, ACE_TCHAR**argv) +{ + // The worlds most useless user interface + Widget top_level = XtVaAppInitialize (NULL, + "buttontest", + NULL, + 0, + &argc, + argv, + NULL, + NULL); + char change[] = "change"; // XmCreatePushButton() wants a non-const + // string. + Widget button = XmCreatePushButton (top_level, + change, + 0, + 0); + XtManageChild (button); + XtAddCallback (button, + XmNactivateCallback, + ActivateCB, + NULL); + + // A reactor beastie. + ACE_XtReactor xreactor (XtWidgetToApplicationContext (top_level)); + ACE_Reactor reactor (&xreactor); + + // Print a message when data is recv'd on stdin... + ACE_Event_Handler *stdin_; + ACE_NEW_RETURN (stdin_, + Stdin (new Stdout (&reactor)), + -1); + reactor.register_handler (stdin_, + ACE_Event_Handler::READ_MASK); + + // Print a message every 10 seconds. + if (reactor.schedule_timer (stdin_, 0, + ACE_Time_Value (10), + ACE_Time_Value (10)) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "schedule_timer"), + -1); + + // Show the top_level widget. + XtRealizeWidget (top_level); + + // Demonstrate Reactor/Xt event loop unification. + XtAppMainLoop (XtWidgetToApplicationContext (top_level)); + + return 0; +} diff --git a/ACE/examples/Misc/test_XtReactor2.cpp b/ACE/examples/Misc/test_XtReactor2.cpp new file mode 100644 index 00000000000..2e2f4be0ba2 --- /dev/null +++ b/ACE/examples/Misc/test_XtReactor2.cpp @@ -0,0 +1,101 @@ +// $Id$ + +// The following test exercises the Eric C. Newton's <ecn@clark.net> +// XtReactor implementation. + +#include "ace/OS_main.h" +#include "ace/XtReactor.h" +#include "ace/Reactor.h" +#include "ace/Message_Block.h" +#include "ace/Log_Msg.h" +#include "ace/OS_NS_unistd.h" + +ACE_RCSID (Misc, + test_XtReactor2, + "$Id$") + + +#include <Xm/PushB.h> + +class Stdin : public ACE_Event_Handler +{ +public: + ACE_HANDLE get_handle (void) const { return ACE_STDIN; } + + int handle_input (ACE_HANDLE) + { + char c; + if (ACE_OS::read (ACE_STDIN, &c, 1)==1) + ACE_DEBUG ((LM_DEBUG, + "Got input '%d'\n", + (int) c)); + return 0; + } + + int handle_timeout (const ACE_Time_Value &tv, + const void *) + { + ACE_DEBUG ((LM_DEBUG, + "Timeout! %f\n", + (double) (tv.msec ()/1000.))); + return 0; + } +}; + +static void +ActivateCB (Widget, XtPointer, XtPointer) +{ + ACE_DEBUG ((LM_DEBUG, + "Button pushed!\n")); +} + +int +ACE_TMAIN (int argc, ACE_TCHAR**argv) +{ + // The worlds most useless user interface + Widget top_level = XtVaAppInitialize (NULL, + "buttontest", + NULL, + 0, + &argc, + argv, + NULL, + NULL); + char change[] = "change"; // XmCreatePushButton() wants a non-const + // string. + Widget button = XmCreatePushButton (top_level, + change, + 0, + 0); + XtManageChild (button); + XtAddCallback (button, + XmNactivateCallback, + ActivateCB, + NULL); + + // A reactor beastie. + ACE_XtReactor xreactor (XtWidgetToApplicationContext (top_level)); + ACE_Reactor reactor (&xreactor); + + // Print a message when data is recv'd on stdin... + ACE_Event_Handler * stdin_; + ACE_NEW_RETURN (stdin_, + Stdin, + -1); + reactor.register_handler (stdin_, + ACE_Event_Handler::READ_MASK); + + // Print a message every 10 seconds + if (reactor.schedule_timer (stdin_, 0, + ACE_Time_Value (10), + ACE_Time_Value (10)) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "schedule_timer"), -1); + + // Show the top_level widget + XtRealizeWidget (top_level); + + // Demonstrate Reactor/Xt event loop unification: + XtAppMainLoop (XtWidgetToApplicationContext (top_level)); +} diff --git a/ACE/examples/Misc/test_dump.cpp b/ACE/examples/Misc/test_dump.cpp new file mode 100644 index 00000000000..bbffe66a2bf --- /dev/null +++ b/ACE/examples/Misc/test_dump.cpp @@ -0,0 +1,33 @@ +// $Id$ + +// The following code illustrates how the ACE_Dumpable mechanisms are +// integrated into ACE components like the SOCK_Acceptor and +// SOCK_Stream. + +#include "ace/OS_main.h" +#include "ace/Dump.h" +#include "test_dump.h" + +#include "ace/Reactor.h" + +ACE_RCSID(Misc, test_dump, "$Id$") + +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + SOCK outer_sock; + // Note that the SOCK superclass is *not* printed. + SOCK_Stream outer_stream; + SOCK_Acceptor outer_acceptor; + ACE_ODB::instance ()->dump_objects (); + { + SOCK inner_sock; + // Note that the SOCK superclass is *not* printed. + SOCK_Stream inner_stream; + SOCK_Acceptor inner_acceptor; + ACE_ODB::instance ()->dump_objects (); + } + ACE_ODB::instance ()->dump_objects (); + return 0; +} + diff --git a/ACE/examples/Misc/test_dump.h b/ACE/examples/Misc/test_dump.h new file mode 100644 index 00000000000..9c7e0bb7de8 --- /dev/null +++ b/ACE/examples/Misc/test_dump.h @@ -0,0 +1,50 @@ +// $Id$ + +// Define the classes used with templates in test_dump.cpp + +#ifndef __TEST_DUMP_H +#define __TEST_DUMP_H + +#include "ace/Dump.h" +#include "ace/OS_NS_stdio.h" + +class SOCK +{ +public: + SOCK (void) { ACE_REGISTER_OBJECT (SOCK); } + ~SOCK (void) { ACE_REMOVE_OBJECT; } + + void dump (void) const { + ACE_OS::fprintf (stderr, "hello from SOCK = %lu\n", (u_long) this); + } + + // ... +}; + +class SOCK_Acceptor : public SOCK +{ +public: + SOCK_Acceptor (void) { ACE_REGISTER_OBJECT (SOCK_Acceptor); } + ~SOCK_Acceptor (void) { ACE_REMOVE_OBJECT; } + + void dump (void) const { + ACE_OS::fprintf (stderr, "hello from SOCK_Acceptor = %lu\n", (u_long) this); + } + + // ... +}; + +class SOCK_Stream : public SOCK +{ +public: + SOCK_Stream (void) { ACE_REGISTER_OBJECT (SOCK_Stream); } + ~SOCK_Stream (void) { ACE_REMOVE_OBJECT; } + + void dump (void) const { + ACE_OS::fprintf (stderr, "hello from SOCK_Stream = %lu\n", (u_long) this); + } + + // ... +}; + +#endif /* __TEST_DUMP_H */ diff --git a/ACE/examples/Misc/test_get_opt.cpp b/ACE/examples/Misc/test_get_opt.cpp new file mode 100644 index 00000000000..3fd0a16ac80 --- /dev/null +++ b/ACE/examples/Misc/test_get_opt.cpp @@ -0,0 +1,54 @@ +// $Id$ + +// Test the ACE_Get_Opt class. + +#include "ace/OS_main.h" +#include "ace/Get_Opt.h" +#include "ace/Log_Msg.h" + +ACE_RCSID(Misc, test_get_opt, "$Id$") + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + ACE_Get_Opt get_opt (argc, argv, ACE_TEXT("ab:cd:ef:gh:")); + int c; + + while ((c = get_opt ()) != EOF) + switch (c) + { + case 'a': + ACE_DEBUG ((LM_DEBUG, "got a\n")); + break; + case 'b': + ACE_DEBUG ((LM_DEBUG, "got b with arg %s\n", get_opt.opt_arg ())); + break; + case 'c': + ACE_DEBUG ((LM_DEBUG, "got c\n")); + break; + case 'd': + ACE_DEBUG ((LM_DEBUG, "got d with arg %s\n", get_opt.opt_arg ())); + break; + case 'e': + ACE_DEBUG ((LM_DEBUG, "got e\n")); + break; + case 'f': + ACE_DEBUG ((LM_DEBUG, "got f with arg %s\n", get_opt.opt_arg ())); + break; + case 'g': + ACE_DEBUG ((LM_DEBUG, "got g\n")); + break; + case 'h': + ACE_DEBUG ((LM_DEBUG, "got h with arg %s\n", get_opt.opt_arg ())); + break; + default: + ACE_DEBUG ((LM_DEBUG, "got %c, which is unrecognized!\n", c)); + break; + } + + for (int i = get_opt.opt_ind (); i < argc; i++) + ACE_DEBUG ((LM_DEBUG, "optind = %d, argv[optind] = %s\n", + i, argv[i])); + + return 0; +} diff --git a/ACE/examples/Misc/test_profile_timer.cpp b/ACE/examples/Misc/test_profile_timer.cpp new file mode 100644 index 00000000000..adb6f599f83 --- /dev/null +++ b/ACE/examples/Misc/test_profile_timer.cpp @@ -0,0 +1,38 @@ +// $Id$ + +#include "ace/OS_main.h" +#include "ace/Profile_Timer.h" +#include "ace/Log_Msg.h" +#include "ace/OS_NS_stdlib.h" +#include "ace/OS_NS_unistd.h" + +ACE_RCSID(Misc, test_profile_timer, "$Id$") + +static const int DEFAULT_ITERATIONS = 100000000; + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + ACE_Profile_Timer timer; + int iterations = argc > 1 ? ACE_OS::atoi (argv[1]) : DEFAULT_ITERATIONS; + + timer.start (); + + for (int i = 0; i < iterations; i++) + ACE_OS::getpid (); + + timer.stop (); + + ACE_Profile_Timer::ACE_Elapsed_Time et; + + timer.elapsed_time (et); + + ACE_DEBUG ((LM_DEBUG, "iterations = %d\n", iterations)); + ACE_DEBUG ((LM_DEBUG, "real time = %f secs, user time = %f secs, system time = %f secs\n", + et.real_time, et.user_time, et.system_time)); + + ACE_DEBUG ((LM_DEBUG, "time per call = %f usecs\n", + (et.real_time / double (iterations)) * 1000000)); + return 0; +} + diff --git a/ACE/examples/Misc/test_read_buffer.cpp b/ACE/examples/Misc/test_read_buffer.cpp new file mode 100644 index 00000000000..1c24aec98b7 --- /dev/null +++ b/ACE/examples/Misc/test_read_buffer.cpp @@ -0,0 +1,34 @@ +// $Id$ + +#include "ace/OS_main.h" +#include "ace/OS_NS_fcntl.h" +#include "ace/OS_NS_unistd.h" +#include "ace/Malloc_Base.h" +#include "ace/Service_Config.h" +#include "ace/Read_Buffer.h" +#include "ace/OS_NS_stdlib.h" + + +ACE_RCSID (Misc, + test_read_buffer, + "$Id$") + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + ACE_HANDLE handle = argc > 1 ? ACE_OS::open (argv[1], O_RDONLY) : ACE_STDIN; + int term = argc > 2 ? ACE_OS::atoi (argv[2]) : EOF; + int search = argc > 3 ? ACE_OS::atoi (argv[3]) : '\n'; + int replace = argc > 4 ? ACE_OS::atoi (argv[4]) : '\0'; + + ACE_Read_Buffer rb (handle); + + char *buf; + + while ((buf = rb.read (term, search, replace)) != 0) + { + ACE_OS::write (ACE_STDOUT, buf, rb.size ()); + ACE_Allocator::instance ()->free (buf); + } + return 0; +} diff --git a/ACE/examples/Misc/test_set.cpp b/ACE/examples/Misc/test_set.cpp new file mode 100644 index 00000000000..4b60d3b4b11 --- /dev/null +++ b/ACE/examples/Misc/test_set.cpp @@ -0,0 +1,57 @@ +// $Id$ + +#include "ace/OS_main.h" +#include "ace/Containers.h" +#include "ace/Log_Msg.h" + +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_Unbounded_Set<int> s1; + + ACE_ASSERT (s1.size () == 0); + s1.insert_tail (10); + s1.insert_tail (20); + ACE_ASSERT (s1.size () == 2); + + ACE_Unbounded_Set<int> s2 (s1); + ACE_ASSERT (s2.size () == 2); + + ACE_Unbounded_Set<int> s3; + ACE_ASSERT (s3.size () == 0); + + s3 = s2; + ACE_ASSERT (s3.size () == s2.size ()); + + ACE_Unbounded_Set<int> s4 (s3); + ACE_ASSERT (s4.size () == 2); + + int *ip = 0; + + ACE_DEBUG ((LM_DEBUG, "dumping s1\n")); + for (ACE_Unbounded_Set_Iterator<int> iter1 (s1); + iter1.next (ip) != 0; + iter1.advance ()) + ACE_DEBUG ((LM_DEBUG, "item = %d\n", *ip)); + + ACE_DEBUG ((LM_DEBUG, "dumping s2\n")); + for (ACE_Unbounded_Set_Iterator<int> iter2 (s2); + iter2.next (ip) != 0; + iter2.advance ()) + ACE_DEBUG ((LM_DEBUG, "item = %d\n", *ip)); + + ACE_DEBUG ((LM_DEBUG, "dumping s3\n")); + for (ACE_Unbounded_Set_Iterator<int> iter3 (s3); + iter3.next (ip) != 0; + iter3.advance ()) + ACE_DEBUG ((LM_DEBUG, "item = %d\n", *ip)); + + ACE_DEBUG ((LM_DEBUG, "dumping s4\n")); + for (ACE_Unbounded_Set_Iterator<int> iter4 (s4); + iter4.next (ip) != 0; + iter4.advance ()) + ACE_DEBUG ((LM_DEBUG, "item = %d\n", *ip)); + + return 0; +} + diff --git a/ACE/examples/Misc/test_sstring.cpp b/ACE/examples/Misc/test_sstring.cpp new file mode 100644 index 00000000000..75cfe8e1158 --- /dev/null +++ b/ACE/examples/Misc/test_sstring.cpp @@ -0,0 +1,26 @@ +// $Id$ + +#include "ace/OS_main.h" +#include "ace/SString.h" +#include "ace/Log_Msg.h" + +ACE_RCSID(Misc, test_sstring, "$Id$") + +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_CString s1 ("hello"); + ACE_CString s2 ("world"); + ACE_CString s3 ("el"); + ACE_NS_WString s4 ("hello"); + ACE_NS_WString s5 ("world"); + ACE_NS_WString s6 ("el"); + + ACE_ASSERT (s1 != s2); + ACE_ASSERT (s1.strstr (s2) == ACE_CString::npos); + ACE_ASSERT (s1.strstr (s2) == ACE_CString::npos); + ACE_ASSERT (s1.strstr (s3)); + ACE_ASSERT (s4.strstr (s5) == ACE_NS_WString::npos); + ACE_ASSERT (s5.strstr (s6)); + return 0; +} diff --git a/ACE/examples/Misc/test_trace.cpp b/ACE/examples/Misc/test_trace.cpp new file mode 100644 index 00000000000..c400d94ec7f --- /dev/null +++ b/ACE/examples/Misc/test_trace.cpp @@ -0,0 +1,114 @@ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// examples/Misc +// +// = FILENAME +// test_trace.cpp +// +// = DESCRIPTION +// This example illustrates how to use the ACE tracing feature and +// the ACE_TRACE macro. It also shows the use of the ACE_Task_Base +// class running as an "active object". +// +// = AUTHOR +// Douglas C. Schmidt <schmidt@cs.wustl.edu> and +// Irfan Pyarali <irfan@cs.wustl.edu> +// +// ============================================================================ + +// Enable tracing +#define ACE_NTRACE 0 + +#include "ace/OS_main.h" +#include "ace/Signal.h" +#include "ace/Task.h" + +ACE_RCSID(Misc, test_trace, "$Id$") + +class My_Task : public ACE_Task_Base +{ +public: + My_Task (size_t depth) + : depth_ (depth) + { + } + + int recursive (size_t depth); + + virtual int svc (void) + { + return this->recursive (this->depth_); + } + +private: + size_t depth_; + // Depth of the recursion. +}; + +int +My_Task::recursive (size_t depth) +{ + ACE_TRACE ("My_Task::recursive"); + + if (depth > 0) + return recursive (depth - 1); + else + return 0; + // Destructor of <ACE_Trace> automatically called. +} + +extern "C" +void +exithook (void) +{ + ACE_TRACE ("void exithook (void)"); + + ACE_DEBUG ((LM_DEBUG, + "we're outta here!\n")); +} + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + const size_t MAX_DEPTH = argc == 1 ? 10 : ACE_OS::atoi (argv[1]); + + ACE_OS::atexit (exithook); + + if (argc > 2) + ACE_Trace::set_nesting_indent (ACE_OS::atoi (argv[2])); + + ACE_TRACE ("int ACE_TMAIN (int argc, ACE_TCHAR *argv[])"); + + ACE_Sig_Action sig1 ((ACE_SignalHandler) ACE_Trace::start_tracing, + SIGUSR1); + ACE_UNUSED_ARG (sig1); + ACE_Sig_Action sig2 ((ACE_SignalHandler) ACE_Trace::stop_tracing, + SIGUSR2); + ACE_UNUSED_ARG (sig2); + + My_Task task (MAX_DEPTH); + +#if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0) + int n_threads = argc > 3 ? ACE_OS::atoi (argv[3]) : 4; + + if (task.activate (THR_BOUND | THR_DETACHED, n_threads) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "activate"), + -1); + + // Wait for all the threads to exit. + ACE_Thread_Manager::instance ()->wait (); +#else + const int MAX_ITERATIONS = argc > 3 ? ACE_OS::atoi (argv[3]) : 10; + + for (int i = 0; i < MAX_ITERATIONS; i++) + task.svc (); +#endif /* ACE_MT_SAFE */ + + // Destructor automatically called. + return 0; +} diff --git a/ACE/examples/NT_Service/Makefile.am b/ACE/examples/NT_Service/Makefile.am new file mode 100644 index 00000000000..fbc93c45f6d --- /dev/null +++ b/ACE/examples/NT_Service/Makefile.am @@ -0,0 +1,44 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +ACE_BUILDDIR = $(top_builddir) +ACE_ROOT = $(top_srcdir) + + +## Makefile.NT_Service.am + +if BUILD_WINREGISTRY +if !BUILD_ACE_FOR_TAO +if !BUILD_WINCE +noinst_PROGRAMS = main + +main_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +main_SOURCES = \ + main.cpp \ + ntsvc.cpp \ + ntsvc.h + +main_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_WINCE +endif !BUILD_ACE_FOR_TAO +endif BUILD_WINREGISTRY + +## Clean up template repositories, etc. +clean-local: + -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.* + -rm -f gcctemp.c gcctemp so_locations *.ics + -rm -rf cxx_repository ptrepository ti_files + -rm -rf templateregistry ir.out + -rm -rf ptrepository SunWS_cache Templates.DB diff --git a/ACE/examples/NT_Service/NT_Service.mpc b/ACE/examples/NT_Service/NT_Service.mpc new file mode 100644 index 00000000000..4fdbe054dfe --- /dev/null +++ b/ACE/examples/NT_Service/NT_Service.mpc @@ -0,0 +1,7 @@ +// -*- MPC -*- +// $Id$ + +project : aceexe, winregistry { + avoids += wince + exename = main +} diff --git a/ACE/examples/NT_Service/README b/ACE/examples/NT_Service/README new file mode 100644 index 00000000000..a1d4175e126 --- /dev/null +++ b/ACE/examples/NT_Service/README @@ -0,0 +1,45 @@ +$Id$ + +How to use the NT_Service example. + +The NT_Service program has the following usage: -in -r -s -k -tn -d + -i: Install this program as an NT service, with specified startup + -r: Remove this program from the Service Manager + -s: Start the service + -k: Kill the service + -t: Set startup for an existing service + -d: Debug; run as a regular application + +In order to see different stages of an NT service application, +you have to run the program several times, with different options. +Please note: run with only one option at a time. + +1. Make executable NT_Service. + +2. First, you must initialize the service in the NT SCM database. + Run NT_Service with -in, where n is one of the following startup options: + + // + // Start Type (from WinNT.h) + // + #define SERVICE_SYSTEM_START 0x00000001 + #define SERVICE_AUTO_START 0x00000002 + #define SERVICE_DEMAND_START 0x00000003 + #define SERVICE_DISABLED 0x00000004 + + If only -i is specified, SERVICE_AUTO_START is default option. + +3. Now you are ready to run the actual service. Run NT_Service again, + this time with -s option. If the service starts successfully, it will + ring the system bell every second or so until the service is stopped. + +4. To stop service execution, run NT_Service with the -k option. + +5. To remove the service from the Service Control Manager database, run + NT_Service with -r. + +In addition, once you have initialized this service (by using the -i option) +you can change its startup type to one of the other values above. To do +this, run NT_Service with -tn option. n is as explained above for -i. + +In order to debug the service's execution itself, use the -d option. diff --git a/ACE/examples/NT_Service/main.cpp b/ACE/examples/NT_Service/main.cpp new file mode 100644 index 00000000000..fbbf4a60cf4 --- /dev/null +++ b/ACE/examples/NT_Service/main.cpp @@ -0,0 +1,256 @@ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// examples/NT_Service +// +// = FILENAME +// main.cpp +// +// = DESCRIPTION +// This is the main program - it just hands control off to the +// process instance to figure out what to do. This program only +// runs on Win32. +// +// = AUTHOR +// Gonzalo Diethelm <gonzo@cs.wustl.edu> +// and Steve Huston <shuston@riverace.com> +// +// ============================================================================ + +#include "ace/Get_Opt.h" +#include "ntsvc.h" +// FUZZ: disable check_for_streams_include +#include "ace/streams.h" +#include "ace/OS_NS_errno.h" + +// Default for the -i (install) option +#define DEFAULT_SERVICE_INIT_STARTUP SERVICE_AUTO_START + +class Process +{ +public: + Process (void); + ~Process (void); + + int run(int argc, ACE_TCHAR* argv[]); + +private: + void parse_args (int argc, + ACE_TCHAR* argv[]); + void print_usage_and_die (void); + +private: + char progname[128]; + + int opt_install; + int opt_remove; + int opt_start; + int opt_kill; + int opt_type; + int opt_debug; + + int opt_startup; +}; + +typedef ACE_Singleton<Process, ACE_Mutex> PROCESS; + +Process::Process (void) + : opt_install (0), + opt_remove (0), + opt_start (0), + opt_kill (0), + opt_type (0), + opt_debug (0), + opt_startup (0) +{ + ACE_OS::strcpy (progname, + "service"); + ACE::init (); +} + +Process::~Process (void) +{ + ACE::fini (); +} + +void +Process::print_usage_and_die (void) +{ + ACE_DEBUG ((LM_INFO, + "Usage: %s" + " -in -r -s -k -tn -d\n" + " -i: Install this program as an NT service, with specified startup\n" + " -r: Remove this program from the Service Manager\n" + " -s: Start the service\n" + " -k: Kill the service\n" + " -t: Set startup for an existing service\n" + " -d: Debug; run as a regular application\n", + progname, + 0)); + ACE_OS::exit(1); +} + +void +Process::parse_args (int argc, ACE_TCHAR* argv[]) +{ + ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("i:rskt:d")); + int c; + + while ((c = get_opt ()) != -1) + switch (c) + { + case 'i': + opt_install = 1; + opt_startup = ACE_OS::atoi (get_opt.opt_arg ()); + if (opt_startup <= 0) + print_usage_and_die (); + break; + case 'r': + opt_remove = 1; + break; + case 's': + opt_start = 1; + break; + case 'k': + opt_kill = 1; + break; + case 't': + opt_type = 1; + opt_startup = ACE_OS::atoi (get_opt.opt_arg ()); + if (opt_startup <= 0) + print_usage_and_die (); + break; + case 'd': + opt_debug = 1; + break; + default: + // -i can also be given without a value - if so, it defaults + // to defined value. + if (ACE_OS::strcmp (get_opt.argv ()[get_opt.opt_ind () - 1], ACE_TEXT ("-i")) == 0) + { + opt_install = 1; + opt_startup = DEFAULT_SERVICE_INIT_STARTUP; + } + else + { + print_usage_and_die (); + } + break; + } +} + +// Define a function to handle Ctrl+C to cleanly shut this down. + +static BOOL __stdcall +ConsoleHandler (DWORD ctrlType) +{ + ACE_UNUSED_ARG (ctrlType); + SERVICE::instance ()->handle_control (SERVICE_CONTROL_STOP); + return TRUE; +} + +ACE_NT_SERVICE_DEFINE (Beeper, + Service, + ACE_TEXT ("Annoying Beeper Service")); + +int +Process::run (int argc, ACE_TCHAR* argv[]) +{ + SERVICE::instance ()->name (ACE_TEXT ("Beeper"), + ACE_TEXT ("Annoying Beeper Service")); + + parse_args (argc, argv); + + if (opt_install && !opt_remove) + { + if (-1 == SERVICE::instance ()->insert (opt_startup)) + { + ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("insert"))); + return -1; + } + return 0; + } + + if (opt_remove && !opt_install) + { + if (-1 == SERVICE::instance ()->remove ()) + { + ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("remove"))); + return -1; + } + return 0; + } + + if (opt_start && opt_kill) + print_usage_and_die (); + + if (opt_start) + { + if (-1 == SERVICE::instance ()->start_svc ()) + { + ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("start"))); + return -1; + } + return 0; + } + + if (opt_kill) + { + if (-1 == SERVICE::instance ()->stop_svc ()) + { + ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("stop"))); + return -1; + } + return 0; + } + + if (opt_type) + { + if (-1 == SERVICE::instance ()->startup (opt_startup)) + { + ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("set startup"))); + return -1; + } + return 0; + } + + // If we get here, we either run the app in debug mode (-d) or are + // being called from the service manager to start the service. + + if (opt_debug) + { + SetConsoleCtrlHandler (&ConsoleHandler, 1); + SERVICE::instance ()->svc (); + } + else + { + ofstream *output_file = new ofstream("ntsvc.log", ios::out); + if (output_file && output_file->rdstate() == ios::goodbit) + ACE_LOG_MSG->msg_ostream(output_file, 1); + ACE_LOG_MSG->open(argv[0], + ACE_Log_Msg::STDERR | ACE_Log_Msg::OSTREAM, + 0); + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("%T (%t): Starting service.\n"))); + + ACE_NT_SERVICE_RUN (Beeper, + SERVICE::instance (), + ret); + if (ret == 0) + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("Couldn't start service"))); + else + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("%T (%t): Service stopped.\n"))); + } + + return 0; +} + +int +ACE_TMAIN (int argc, ACE_TCHAR* argv[]) +{ + return PROCESS::instance ()->run (argc, argv); +} + diff --git a/ACE/examples/NT_Service/ntsvc.cpp b/ACE/examples/NT_Service/ntsvc.cpp new file mode 100644 index 00000000000..f21dec5dad7 --- /dev/null +++ b/ACE/examples/NT_Service/ntsvc.cpp @@ -0,0 +1,113 @@ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// examples/NT_Service +// +// = FILENAME +// ntsvc.cpp +// +// = DESCRIPTION +// This is the implementation of the NT service. It beeps every 2 +// seconds until the service is stopped. +// +// = AUTHOR +// Gonzalo Diethelm <gonzo@cs.wustl.edu> +// and Steve Huston <shuston@riverace.com> +// +// ============================================================================ + +#include "ace/Reactor.h" +#include "ntsvc.h" + +Service::Service (void) +{ + // Remember the Reactor instance. + reactor (ACE_Reactor::instance ()); +} + +Service::~Service (void) +{ + if (ACE_Reactor::instance ()->cancel_timer(this) == -1) + ACE_ERROR ((LM_ERROR, + "Service::~Service failed to cancel_timer.\n")); +} + +// This method is called when the service gets a control request. It +// handles requests for stop and shutdown by calling terminate (). +// All others get handled by calling up to inherited::handle_control. + +void +Service::handle_control (DWORD control_code) +{ + if (control_code == SERVICE_CONTROL_SHUTDOWN + || control_code == SERVICE_CONTROL_STOP) + { + report_status (SERVICE_STOP_PENDING); + + ACE_DEBUG ((LM_INFO, + ACE_TEXT ("Service control stop requested\n"))); + stop_ = 1; + reactor ()->notify (this, + ACE_Event_Handler::EXCEPT_MASK); + } + else + inherited::handle_control (control_code); +} + +// This is just here to be the target of the notify from above... it +// doesn't do anything except aid on popping the reactor off its wait +// and causing a drop out of handle_events. + +int +Service::handle_exception (ACE_HANDLE) +{ + return 0; +} + +// Beep every two seconds. This is what this NT service does... + +int +Service::handle_timeout (const ACE_Time_Value &tv, + const void *) +{ + ACE_UNUSED_ARG (tv); + MessageBeep (MB_OK); + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("%T (%t): Beep...\n"))); + return 0; +} + +// This is the main processing function for the Service. It sets up +// the initial configuration and runs the event loop until a shutdown +// request is received. + +int +Service::svc (void) +{ + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("Service::svc\n"))); + + // As an NT service, we come in here in a different thread than the + // one which created the reactor. So in order to do anything, we + // need to own the reactor. If we are not a service, report_status + // will return -1. + if (report_status (SERVICE_RUNNING) == 0) + reactor ()->owner (ACE_Thread::self ()); + + this->stop_ = 0; + + // Schedule a timer every two seconds. + ACE_Time_Value tv (2, 0); + ACE_Reactor::instance ()->schedule_timer (this, 0, tv, tv); + + while (!this->stop_) + reactor ()->handle_events (); + + // Cleanly terminate connections, terminate threads. + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("Shutting down\n"))); + reactor ()->cancel_timer (this); + return 0; +} + diff --git a/ACE/examples/NT_Service/ntsvc.h b/ACE/examples/NT_Service/ntsvc.h new file mode 100644 index 00000000000..cecc91b34c5 --- /dev/null +++ b/ACE/examples/NT_Service/ntsvc.h @@ -0,0 +1,65 @@ +/* -*- C++ -*- */ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// examples/NT_Service +// +// = FILENAME +// ntsvc.h +// +// = DESCRIPTION +// This is the definition of the sample NT Service class. This example +// only runs on Win32 platforms. +// +// = AUTHOR +// Gonzalo Diethelm and Steve Huston +// +// ============================================================================ + +#ifndef NTSVC_H_ +#define NTSVC_H_ + +#include "ace/Event_Handler.h" +#include "ace/NT_Service.h" +#include "ace/Singleton.h" +#include "ace/Mutex.h" + +class Service : public ACE_NT_Service +{ +public: + Service (void); + + ~Service (void); + + virtual void handle_control (DWORD control_code); + // We override <handle_control> because it handles stop requests + // privately. + + virtual int handle_exception (ACE_HANDLE h); + // We override <handle_exception> so a 'stop' control code can pop + // the reactor off of its wait. + + virtual int svc (void); + // This is a virtual method inherited from ACE_NT_Service. + + virtual int handle_timeout (const ACE_Time_Value& tv, + const void *arg = 0); + // Where the real work is done: + +private: + typedef ACE_NT_Service inherited; + +private: + int stop_; +}; + +// Define a singleton class as a way to insure that there's only one +// Service instance in the program, and to protect against access from +// multiple threads. The first reference to it at runtime creates it, +// and the ACE_Object_Manager deletes it at run-down. + +typedef ACE_Singleton<Service, ACE_Mutex> SERVICE; + +#endif /* #ifndef NTSVC_H_ */ diff --git a/ACE/examples/Naming/.cvsignore b/ACE/examples/Naming/.cvsignore new file mode 100644 index 00000000000..5e535209538 --- /dev/null +++ b/ACE/examples/Naming/.cvsignore @@ -0,0 +1,4 @@ +multiple_contexts +non_existent +open +writers diff --git a/ACE/examples/Naming/Makefile.am b/ACE/examples/Naming/Makefile.am new file mode 100644 index 00000000000..de8e2353f18 --- /dev/null +++ b/ACE/examples/Naming/Makefile.am @@ -0,0 +1,90 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +ACE_BUILDDIR = $(top_builddir) +ACE_ROOT = $(top_srcdir) + +noinst_PROGRAMS = + +## Makefile.Naming_Multiple_Contexts.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS += multiple_contexts + +multiple_contexts_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +multiple_contexts_SOURCES = \ + test_multiple_contexts.cpp + +multiple_contexts_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Makefile.Naming_Non_Existent.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS += non_existent + +non_existent_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +non_existent_SOURCES = \ + test_non_existent.cpp + +non_existent_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Makefile.Naming_Open.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS += open + +open_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +open_SOURCES = \ + test_open.cpp + +open_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Makefile.Naming_Writers.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS += writers + +writers_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +writers_SOURCES = \ + test_writers.cpp + +writers_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Clean up template repositories, etc. +clean-local: + -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.* + -rm -f gcctemp.c gcctemp so_locations *.ics + -rm -rf cxx_repository ptrepository ti_files + -rm -rf templateregistry ir.out + -rm -rf ptrepository SunWS_cache Templates.DB diff --git a/ACE/examples/Naming/Naming.mpc b/ACE/examples/Naming/Naming.mpc new file mode 100644 index 00000000000..f8365ffe07d --- /dev/null +++ b/ACE/examples/Naming/Naming.mpc @@ -0,0 +1,34 @@ +// -*- MPC -*- +// $Id$ + +project(*multiple_contexts) : aceexe { + avoids += ace_for_tao + exename = multiple_contexts + Source_Files { + test_multiple_contexts.cpp + } +} + +project(*non_existent) : aceexe { + avoids += ace_for_tao + exename = non_existent + Source_Files { + test_non_existent.cpp + } +} + +project(*writers) : aceexe { + avoids += ace_for_tao + exename = writers + Source_Files { + test_writers.cpp + } +} + +project(*open) : aceexe { + avoids += ace_for_tao + exename = open + Source_Files { + test_open.cpp + } +} diff --git a/ACE/examples/Naming/test_multiple_contexts.cpp b/ACE/examples/Naming/test_multiple_contexts.cpp new file mode 100644 index 00000000000..06cb4d1c376 --- /dev/null +++ b/ACE/examples/Naming/test_multiple_contexts.cpp @@ -0,0 +1,86 @@ +// $Id$ + +#include "ace/OS_main.h" +#include "ace/Naming_Context.h" +#include "ace/Log_Msg.h" +#include "ace/OS_NS_stdio.h" + +ACE_RCSID(Naming, test_multiple_contexts, "$Id$") + +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + static u_long ACE_DEFAULT_BASE_ADDR_1 = (1 * 64 * 1024 * 1024); + static u_long ACE_DEFAULT_BASE_ADDR_2 = (2 * 64 * 1024 * 1024); + + int i; + + ACE_STATIC_SVC_REGISTER(ACE_Naming_Context); + + ACE_Naming_Context *ns_ptr; + ACE_NEW_RETURN (ns_ptr, + ACE_Naming_Context, + 1); + ACE_Name_Options *name_options = + ns_ptr->name_options (); + + ACE_Naming_Context *ns_ptr1; + ACE_NEW_RETURN (ns_ptr1, + ACE_Naming_Context, + 1); + ACE_Name_Options *name_options1 = + ns_ptr1->name_options (); + + ACE_TCHAR address_arg1[BUFSIZ]; + ACE_TCHAR address_arg2[BUFSIZ]; + ACE_OS::sprintf (address_arg1, + ACE_TEXT("-b%ld"), + ACE_DEFAULT_BASE_ADDR_1); + + const ACE_TCHAR *m_argv[] = + { + ACE_TEXT("MyName1"), + ACE_TEXT("-cNODE_LOCAL"), + address_arg1, + NULL + }; + int m_argc = + sizeof (m_argv) / sizeof (ACE_TCHAR *) -1; + + ACE_OS::sprintf (address_arg2, + ACE_TEXT("-b%ld"), + ACE_DEFAULT_BASE_ADDR_2); + const ACE_TCHAR *n_argv[] = + { + ACE_TEXT("MyName2"), + ACE_TEXT("-cNODE_LOCAL"), + address_arg2, + NULL + }; + + int n_argc = + sizeof (n_argv) / sizeof (ACE_TCHAR *) -1; + + name_options->parse_args (m_argc, + (ACE_TCHAR **) m_argv); + i = ns_ptr->open (ACE_Naming_Context::NODE_LOCAL); + + ACE_DEBUG ((LM_DEBUG, + "(%P) opened with %d\n", + i)); + + if (i != 0) + return -1; + + name_options1->parse_args (n_argc, + (ACE_TCHAR **) n_argv); + + i = ns_ptr1->open (ACE_Naming_Context::NODE_LOCAL); + + ACE_DEBUG ((LM_DEBUG, + "(%P) 1 opened with %d\n", + i)); + if (i != 0) + return -1; + + return 0; +} diff --git a/ACE/examples/Naming/test_non_existent.cpp b/ACE/examples/Naming/test_non_existent.cpp new file mode 100644 index 00000000000..448594bd969 --- /dev/null +++ b/ACE/examples/Naming/test_non_existent.cpp @@ -0,0 +1,54 @@ +// $Id$ + +#include "ace/OS_main.h" +#include "ace/Naming_Context.h" +#include "ace/Log_Msg.h" + +ACE_RCSID(Naming, test_non_existent, "$Id$") + +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + int i; + + ACE_STATIC_SVC_REGISTER(ACE_Naming_Context); + + ACE_Naming_Context *ns_ptr; + ACE_NEW_RETURN (ns_ptr, + ACE_Naming_Context, + 1); + + ACE_Name_Options *name_options = ns_ptr->name_options (); + + const ACE_TCHAR *m_argv[] = + { + ACE_TEXT("MyName"), + ACE_TEXT("-cNODE_LOCAL") , +#if defined (ACE_WIN32) + ACE_TEXT("-lC:\\temp\\non_existent"), +#else + ACE_TEXT("-l/tmp/foobar.mine"), +#endif /* ACE_WIN32 */ + 0 + }; + + int m_argc = + sizeof (m_argv) / sizeof (ACE_TCHAR *) -1; + + name_options->parse_args (m_argc, (ACE_TCHAR**)m_argv); + + i = ns_ptr->open (ACE_Naming_Context::NODE_LOCAL); + ACE_DEBUG ((LM_DEBUG, + "(%P) opened with %d\n", + i)); + if (i != 0) + return -1; + + i = ns_ptr->bind ("Key_Value", + "Val_Value", + "-"); + + ACE_DEBUG ((LM_DEBUG, + "(%P) bound with %d\n", + i)); + return 0; +} diff --git a/ACE/examples/Naming/test_open.cpp b/ACE/examples/Naming/test_open.cpp new file mode 100644 index 00000000000..247f3987112 --- /dev/null +++ b/ACE/examples/Naming/test_open.cpp @@ -0,0 +1,83 @@ +// $Id$ + +#include "ace/OS_main.h" +#include "ace/Naming_Context.h" +#include "ace/Log_Msg.h" +#include "ace/OS_NS_stdio.h" +#include "ace/OS_NS_unistd.h" + +ACE_RCSID(Naming, test_open, "$Id$") + +int +ACE_TMAIN (int argc, ACE_TCHAR **argv) +{ + const ACE_TCHAR *host = argc > 1 ? argv[1] : ACE_TEXT("-hlocalhost"); + const ACE_TCHAR *port = argc > 2 ? argv[2] : ACE_TEXT("-p20012"); + + ACE_STATIC_SVC_REGISTER(ACE_Naming_Context); + + ACE_Naming_Context ns; + ACE_Name_Options *name_options = ns.name_options (); + + const ACE_TCHAR *m_argv[] = + { + ACE_TEXT("MyName"), + ACE_TEXT("-cNET_LOCAL"), + host, + port, + 0 + }; + int m_argc = + sizeof (m_argv) / sizeof (ACE_TCHAR *) -1; + + name_options->parse_args (m_argc, + (ACE_TCHAR **) m_argv); + + int result = ns.open (ACE_Naming_Context::NET_LOCAL); + ACE_DEBUG ((LM_DEBUG, + "ACE_Naming_Context::open returned %d\n", + result)); + if (result != 0) + return result; + else + { + char key[128]; + char val[32]; + char type[2]; + + type[0] = '-'; + type[1] = '\0'; + + int i = 0; + + for (int l = 1; l <= 1000 ; l++) + { + ACE_OS::sprintf (key, + "K_%05d_%05d", + (int) ACE_OS::getpid (), + l); + ACE_OS::sprintf (val, + "Val%05d", + l); + i = ns.bind (key, + val, + type); + ACE_DEBUG ((LM_DEBUG, + "%d: bind of %s: %d\n", + ACE_OS::getpid (), + key, + i)); + + if (i != 0) + return -1; + + } + + result = ns.close (); + ACE_DEBUG ((LM_DEBUG, + "ACE_Naming_Context::close returned %d\n", + result)); + } + + return result; +} diff --git a/ACE/examples/Naming/test_writers.cpp b/ACE/examples/Naming/test_writers.cpp new file mode 100644 index 00000000000..7277003ed2d --- /dev/null +++ b/ACE/examples/Naming/test_writers.cpp @@ -0,0 +1,76 @@ +// $Id$ + +#include "ace/OS_main.h" +#include "ace/Naming_Context.h" +#include "ace/Log_Msg.h" +#include "ace/OS_NS_stdio.h" +#include "ace/OS_NS_unistd.h" + +ACE_RCSID(Naming, test_writers, "$Id$") + +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + int i; + + ACE_STATIC_SVC_REGISTER(ACE_Naming_Context); + + ACE_Naming_Context *ns_ptr; + ACE_NEW_RETURN (ns_ptr, + ACE_Naming_Context, + 1); + ACE_Name_Options *name_options = + ns_ptr->name_options (); + + const ACE_TCHAR *m_argv[] = + { + ACE_TEXT("MyName"), + ACE_TEXT("-cNODE_LOCAL"), + NULL + }; + + int m_argc = sizeof (m_argv) / sizeof (ACE_TCHAR *) -1; + + name_options->parse_args (m_argc, + (ACE_TCHAR **) m_argv); + i = ns_ptr->open (ACE_Naming_Context::NODE_LOCAL); + ACE_DEBUG ((LM_DEBUG, + "(%P) opened with %d\n", + i)); + if (i != 0) + return -1; + else + { + char key[128]; + char val[32]; + char type[2]; + + type[0] = '-'; + type[1] = '\0'; + + int i = 0; + + for (int l = 1; l <= 1000 ; l++) + { + ACE_OS::sprintf (key, + "K_%05d_%05d", + (int) ACE_OS::getpid (), + l); + ACE_OS::sprintf (val, + "Val%05d", + l); + i = ns_ptr->bind (key, + val, + type); + ACE_DEBUG ((LM_DEBUG, + "%d: bind of %s: %d\n", + ACE_OS::getpid (), + key, + i)); + + if (i != 0) + return -1; + + } + } + return 0; +} diff --git a/ACE/examples/OS/Makefile.am b/ACE/examples/OS/Makefile.am new file mode 100644 index 00000000000..73458dccc45 --- /dev/null +++ b/ACE/examples/OS/Makefile.am @@ -0,0 +1,13 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +SUBDIRS = \ + Process + diff --git a/ACE/examples/OS/Process/.cvsignore b/ACE/examples/OS/Process/.cvsignore new file mode 100644 index 00000000000..c52eac932e5 --- /dev/null +++ b/ACE/examples/OS/Process/.cvsignore @@ -0,0 +1,4 @@ +imore +imore +process +process diff --git a/ACE/examples/OS/Process/Makefile.am b/ACE/examples/OS/Process/Makefile.am new file mode 100644 index 00000000000..88eac9e35bd --- /dev/null +++ b/ACE/examples/OS/Process/Makefile.am @@ -0,0 +1,52 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +ACE_BUILDDIR = $(top_builddir) +ACE_ROOT = $(top_srcdir) + +noinst_PROGRAMS = + +## Makefile.OS_Process_Imore.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS += imore + +imore_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +imore_SOURCES = \ + imore.cpp + +imore_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Makefile.OS_Process_Process.am +noinst_PROGRAMS += process + +process_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +process_SOURCES = \ + process.cpp + +process_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Clean up template repositories, etc. +clean-local: + -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.* + -rm -f gcctemp.c gcctemp so_locations *.ics + -rm -rf cxx_repository ptrepository ti_files + -rm -rf templateregistry ir.out + -rm -rf ptrepository SunWS_cache Templates.DB diff --git a/ACE/examples/OS/Process/OS_Process.mpc b/ACE/examples/OS/Process/OS_Process.mpc new file mode 100644 index 00000000000..082f7133301 --- /dev/null +++ b/ACE/examples/OS/Process/OS_Process.mpc @@ -0,0 +1,16 @@ +// -*- MPC -*- +// $Id$ + +project(*imore) : aceexe { + avoids += ace_for_tao + exename = imore + Source_Files { + imore.cpp + } +} +project(*process) : aceexe { + exename = process + Source_Files { + process.cpp + } +} diff --git a/ACE/examples/OS/Process/README b/ACE/examples/OS/Process/README new file mode 100644 index 00000000000..c22757eb73f --- /dev/null +++ b/ACE/examples/OS/Process/README @@ -0,0 +1,54 @@ +This directory contains two examples: <imore> and <process>. They +show how you can play with various features of ACE_Process to create +new processes. + +imore: +----- +This example shows how to redirect the output of one process (in our +case, the parent process) to another process (child process.) This is +very similiar what a UNIX shell does when we "pipe" command together. +You can select whether you want to use named pipes or a unnamed pipe. + + +process: +-------- + +This example shows how to use ACE_Process to "portably" create new +processes. The ACE_Process_Options class allows applications to +portably specify path, command-line arguments, environment variable +values. It also allows applications to set the new process' standard +handles (stdin, stdout, and stderr). ACE_Process is created with the +ACE_Process_Options and can be used to perform operations on the +running process. + +Notice that this example uses NT version's UNIX utilities like +"DATE.EXE," and "ls.exe." You can find where to get them from +Microsoft's NT page on the Web. + +Run the application as ./process -u to get all the command-line +options. + +Here's an example output: + +lambada:OS/Process> ./process -a +starting... +starting... +Sun May 11 15:06:51 CDT 1997 +date succeeded. +starting... +checking ACE_PROCESS_TEST +ACE_PROCESS_TEST = here's a large number 4294967295. +ACE_PROCESS_TEST2 = ophilli. +total 600 +drwxr-xr-x 5 harrison doc 512 May 11 15:06 . +drwxr-xr-x 4 harrison doc 512 Apr 21 15:32 .. +drwx------ 2 harrison doc 512 May 8 22:33 .obj +drwx------ 2 harrison doc 512 May 8 22:33 .shobj +drwxr-xr-x 2 harrison doc 512 May 11 15:05 CVS +-rw-r--r-- 1 harrison doc 1717 Oct 21 1996 Makefile +-rw-r--r-- 1 harrison doc 10048 Oct 21 1996 Process.mak +-rw-r--r-- 1 harrison doc 44032 Oct 21 1996 Process.mdp +-rw-r--r-- 1 harrison doc 1452 May 11 15:05 README +-rwx--x--x 1 harrison doc 212992 May 11 15:06 process +-rw-r--r-- 1 harrison doc 10172 May 10 19:38 process.cpp +-rw------- 1 harrison doc 1380 May 10 19:19 process.wst diff --git a/ACE/examples/OS/Process/imore.cpp b/ACE/examples/OS/Process/imore.cpp new file mode 100644 index 00000000000..181254e0cb4 --- /dev/null +++ b/ACE/examples/OS/Process/imore.cpp @@ -0,0 +1,267 @@ +// ============================================================================ +// $Id$ +// +// = LIBRARY +// examples +// +// = FILENAME +// imore.cpp (imore stands for indirect more.) +// +// = DESCRIPTION +// This program demonstrates how to redirect stdout of a parent +// process to the stdin of its child process using either unnamed pipe +// or named pipes to relay data to subprocess which runs "more" to +// display data on the screen. Run imore to see how to use this +// program. +// +// Unfortunately, on Win32, this program doesn't use any pipe at all because +// using pipes confuses MORE.COM on Win32 and it just acts like "cat" on Unix. +// +// = AUTHOR +// Nanbor Wang <nanbor@cs.wustl.edu> +// +// ============================================================================ + +#include "ace/OS_NS_stdio.h" +#include "ace/OS_NS_errno.h" +#include "ace/OS_NS_unistd.h" +#include "ace/OS_NS_fcntl.h" +#include "ace/FIFO_Recv.h" +#include "ace/FIFO_Send.h" +#include "ace/Pipe.h" +#include "ace/Get_Opt.h" +#include "ace/Log_Msg.h" +#include "ace/Process.h" +#include "ace/Signal.h" + +ACE_RCSID(Process, imore, "$Id$") + +#if defined (ACE_WIN32) +static const ACE_TCHAR *executable = ACE_TEXT("MORE.COM"); +static const ACE_TCHAR *rendezvous_dir = ACE_TEXT("c:/temp"); +static const ACE_TCHAR *rendezvous_pfx = ACE_TEXT("imore"); +#else +static const char * executable = "more"; // I like less better. +static const ACE_TCHAR *rendezvous_dir = ACE_TEXT("/tmp"); +static const ACE_TCHAR *rendezvous_pfx = ACE_TEXT("imore"); +#endif /* ACE_WIN32 */ + +static ACE_TCHAR *fname = 0; // File you want to view. +static int use_named_pipe = 0; // Do we want to use named pipe? + +static void +usage (void) +{ + ACE_ERROR ((LM_ERROR, "Usage: imore [-n|-u] <filename>\n" + "\t-n Use named pipe.\n" + "\t-u Use unnamed pipe.\n")); +} + +static int +parse_args (int argc, ACE_TCHAR **argv) +{ + ACE_Get_Opt get_opt (argc, argv, ACE_TEXT("un")); + int c; + + while ((c = get_opt ()) != -1) + { + switch (c) + { + case 'n': // We want to use named pipe. +#if !defined (ACE_WIN32) + use_named_pipe = 1; +#else + ACE_ERROR_RETURN ((LM_ERROR, "Named pipes not supported on Win32\n"), -1); +#endif /* !ACE_WIN32 */ + break; + case 'u': // Use unnamed pipe. + use_named_pipe = 0; + break; + default: // What are you talking about? + usage (); + return -1; + } + } + + if (get_opt.opt_ind () >= argc) // Do you forget to give me a filename to "more?" + { + usage (); + return -1; + } + else + fname = argv[get_opt.opt_ind ()]; // Alright. + + return 0; +} + +static int +setup_named_pipes (ACE_Process_Options &opt) +{ + // Create a unique temporary name for named pipe. + ACE_TCHAR *rendezvous = ACE_OS::tempnam (rendezvous_dir, + rendezvous_pfx); + + // Out of memory? + if (rendezvous == NULL) + return -1; + + // Alright, this is indeed strange. Named pipes are meant to be + // used for unrelated processes. Because of the constraints in + // ACE_Process, I have to pre-open the named pipes here. + ACE_FIFO_Recv rfifo; // read end fifo. + ACE_FIFO_Send wfifo; // write end fifo. + + // Check if the pipes are created successfully. + if (rfifo.open (rendezvous) == -1 || wfifo.open (rendezvous) == -1) + { + ACE_OS::free (rendezvous); + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "fifo.open"), -1); + } + + // Remove (rm, del) the file after no one uses it any more. + ACE_OS::unlink (rendezvous); + ACE_OS::free (rendezvous); + + // Setting up pipe between parent and child process. Use the read + // end of the named pipe as child process'es ACE_STDIN. + // ACE_Process_Options will keep copies (by dup) of fd's that we + // pass in. Notice that we have to specify child process to use + // ACE_STDOUT for output explicitly because we'll close it down in + // the line after. Child process will use whatever we use to dup2 + // ACE_STDOUT as its stdout. + opt.set_handles (rfifo.get_handle (), ACE_STDOUT); + + // The previous keep a copy of original ACE_STDOUT fd, now we + // can replace ACE_STDOUT of parent process to the write end + // of the named pipe. + ACE_OS::dup2 (wfifo.get_handle (), ACE_STDOUT); + + // Close unused fd's. Notice ACE_FIFO doesn't close the fd + // when it goes out of scope. + rfifo.close (); + wfifo.close (); + return 0; +} + +static int +setup_unnamed_pipe (ACE_Process_Options &opt) +{ + // Create an unnamed pipe instance. + ACE_Pipe pipe; + + // Check if the pipe is created successfully. + if (pipe.open () == -1) + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "pipe.open"), -1); + + // Setting up pipe between parent and child process. Use the pipe + // as child process'es ACE_STDIN. ACE_Process_Options will keep + // copies (by dup) of fd's that we pass in. Notice that we have to + // specify child process to use ACE_STDOUT for output explicitly + // because we'll close it down in the line after. Child process + // will use whatever we use to dup2 ACE_STDOUT as its stdout. + opt.set_handles (pipe.read_handle (), ACE_STDOUT); + + // The previous keep a copy of original ACE_STDOUT fd, now we + // can replace ACE_STDOUT of parent process to the pipe. + ACE_OS::dup2 (pipe.write_handle (), ACE_STDOUT); + + // Don't forget to close the unused fd. + pipe.close (); + return 0; +} + +static int +print_file (ACE_HANDLE infd) +{ + char buffer[BUFSIZ]; + ssize_t len; + + while ((len = ACE_OS::read (infd, buffer, BUFSIZ)) > 0) + { + if ((ACE_OS::write (ACE_STDOUT, buffer, len) != len)) + if (errno == EPIPE) + { + // I tried to "produce" EPIPE warning to test + // the program but never seen one. (odd.) + // ACE_ERROR ((LM_ERROR, "\n\nEPIPE\n")); + break; + } + else + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "write"), -1); + } + return 0; +} + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + // Ignore SIGPIPE signal on Unix platforms in case + // child process (more) terminates before we finish + // writing to stdout. +#if !defined (ACE_WIN32) + ACE_Sig_Action sig_act (SIG_IGN); + if (sig_act.register_action (SIGPIPE) == -1) + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "ACE_Sig_Action::register_action"), -1); +#endif /* ACE_WIN32 */ + + // Alright, what you want me to do now? + if (::parse_args (argc, argv) == -1) + return -1; + + // Can I find the file you want? + ACE_HANDLE infile = ACE_OS::open (fname, O_RDONLY); + if (infile == ACE_INVALID_HANDLE) + ACE_ERROR_RETURN ((LM_DEBUG, "%p\n", fname), -1); + + ACE_Process new_process; + + // Notice that we must enclose ACE_Process_Options in the block + // so the file handlers it keeps can be close elegantly. +#if !defined (ACE_WIN32) + { + ACE_Process_Options options; + + if ((use_named_pipe ? ::setup_named_pipes : + ::setup_unnamed_pipe) (options) == -1) + ACE_ERROR_RETURN ((LM_ERROR, "Error, bailing out!\n"), -1); + + options.command_line (executable); + if (new_process.spawn (options) == -1) + { + int error = ACE_OS::last_error (); + ACE_ERROR_RETURN ((LM_ERROR, "%p errno = %d.\n", + "test_more", error), -1); + } + } + + // write file to ACE_STDOUT. + if (::print_file (infile) == -1) + ACE_ERROR_RETURN ((LM_ERROR, "Error, bailing out!\n"), -1); + + // Close the STDOUT to inform child eof. + ACE_OS::close (ACE_STDOUT); +#else + // We can only pass a file handler directly to child process + // otherwise "more" doesn't act quite the way we want. Nonetheless, + // if your child process don't need to interact with the terminal, + // we can use the exact code for Unixes on NT. + ACE_Process_Options options; + options.command_line (executable); + options.set_handles (infile); + if (new_process.spawn (options) == -1) + { + int error = ACE_OS::last_error (); + ACE_ERROR_RETURN ((LM_ERROR, "%p errno = %d.\n", + "test_more", error), -1); + } +#endif /* ! ACE_WIN32 */ + + // Wait till we are done. + ACE_exitcode status; + new_process.wait (&status); + ACE_DEBUG ((LM_DEBUG, "Process exit with status %d\n", status)); + + ACE_OS::close (infile); + + return 0; +} diff --git a/ACE/examples/OS/Process/process.cpp b/ACE/examples/OS/Process/process.cpp new file mode 100644 index 00000000000..de0f2db0d57 --- /dev/null +++ b/ACE/examples/OS/Process/process.cpp @@ -0,0 +1,577 @@ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// examples +// +// = FILENAME +// process.cpp +// +// = DESCRIPTION +// This example tests the <ACE_Process>. For more info, check the +// README file in this directory. +// +// = AUTHOR +// Tim Harrison <harrison@cs.wustl.edu>. +// +// ============================================================================ + +#include "ace/OS_NS_errno.h" +#include "ace/OS_NS_fcntl.h" +#include "ace/OS_NS_stdlib.h" +#include "ace/OS_NS_stdio.h" +#include "ace/OS_NS_string.h" +#include "ace/OS_NS_unistd.h" +#include "ace/Get_Opt.h" +#include "ace/Process.h" +#include "ace/Log_Msg.h" +#include "ace/Time_Value.h" +#include "ace/SString.h" + +ACE_RCSID(Process, process, "$Id$") + +#if defined (ACE_WIN32) +#define EXEC_NAME ACE_TEXT ("MORE.COM") +const ACE_TCHAR *DATE_PATH = ACE_TEXT ("date.exe"); +const ACE_TCHAR *LS_PATH = ACE_TEXT ("ls.exe"); +const ACE_TCHAR *SLEEP_PATH = ACE_TEXT ("sleep.exe"); +#else +#define EXEC_NAME ACE_TEXT ("less") +const ACE_TCHAR *DATE_PATH = ACE_TEXT ("date"); +const ACE_TCHAR *LS_PATH = ACE_TEXT ("ls"); +const ACE_TCHAR *SLEEP_PATH = ACE_TEXT ("sleep"); +#endif /* ACE_WIN32 */ + +static const ACE_TCHAR *executable = EXEC_NAME; +static ACE_TCHAR *print_file = 0; +static ACE_TCHAR *environment_string = 0; +static int get_env = 0; +static int run_date = 0; +static int run_ls = 0; +static int run_all = 0; +static int run_setenv = 0; +static int run_tokenizer = 0; +static int run_wait = 0; + +// Parse the command-line arguments and set options. +static int +parse_args (int argc, ACE_TCHAR **argv) +{ + ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("dlx:p:e:gastuw")); + int c; + + while ((c = get_opt ()) != -1) + { + switch (c) + { + case 't': + run_tokenizer = 1; + break; + case 's': + run_setenv = 1; + break; + case 'a': + run_all = 1; + break; + case 'd': + run_date = 1; + break; + case 'l': + run_ls = 1; + break; + case 'x': + executable = get_opt.opt_arg (); + break; + case 'p': + print_file = get_opt.opt_arg (); + break; + case 'e': + environment_string = get_opt.opt_arg (); + break; + case 'g': + get_env = 1; + break; + case 'w': + run_wait = 1; + break; + case 'u': + default: + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("Usage:\n") + ACE_TEXT ("-d print date\n") + ACE_TEXT ("-l run ls\n") + ACE_TEXT ("-x <executable=more.com>\n") + ACE_TEXT ("-p print <file_name>\n") + ACE_TEXT ("-e <env variable message>\n") + ACE_TEXT ("-s setenv ACE_PROCESS_ENV and spawn -g\n") + ACE_TEXT ("-g get_env ACE_PROCESS_ENV\n") + ACE_TEXT ("-t test tokenizer\n") + ACE_TEXT ("-w test wait functions\n") + ACE_TEXT ("-a run all (d,l,e \"running\")\n")), + -1); + break; + } + } + + return 0; +} + +// This shows how to set handles. +static void +test_more (void) +{ + ACE_HANDLE infile = ACE_OS::open (print_file, O_RDONLY); + + if (infile == ACE_INVALID_HANDLE) + { + ACE_ERROR ((LM_DEBUG, ACE_TEXT ("%p\n"), print_file)); + return; + } + + ACE_Process new_process; + ACE_Process_Options options; + options.command_line (executable); + options.set_handles (infile); + + if (new_process.spawn (options) == -1) + { + int error = ACE_OS::last_error (); + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("%p errno = %d.\n"), + ACE_TEXT ("test_more"), + error)); + } + + ACE_exitcode status; + new_process.wait (&status); + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("Process exit with status %d\n"), + status)); + ACE_OS::close (infile); + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("More succeeded.\n"))); +} + +// This is a simple usage of ACE_Process. + +static void +test_date (void) +{ + ACE_Process_Options options; + options.command_line (DATE_PATH); + + // Try to create a new process running date. + ACE_Process new_process; + if (new_process.spawn (options) == -1) + { + int error = ACE_OS::last_error (); + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("%p errno = %d.\n"), + ACE_TEXT ("test_date"), + error)); + return; + } + + ACE_exitcode status; + new_process.wait (&status); + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("Process exit with status %d\n"), + status)); + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("date succeeded.\n"))); +} + +static void +test_ls (void) +{ + ACE_Process_Options options; +#if defined (ACE_WIN32) || !defined (ACE_USES_WCHAR) + options.command_line (ACE_TEXT ("%s -al"), LS_PATH); +#else + options.command_line (ACE_TEXT ("%ls -al"), LS_PATH); +#endif + ACE_Process new_process; + if (new_process.spawn (options) == -1) + { + int error = ACE_OS::last_error (); + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("%p errno = %d.\n"), + ACE_TEXT ("test_ls"), + error)); + } + + ACE_exitcode status; + new_process.wait (&status); + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("Process exit with status %d\n"), + status)); +} + +static void +test_wait (void) +{ + ACE_Process_Options options; +#if defined (ACE_WIN32) || !defined (ACE_USES_WCHAR) + options.command_line (ACE_TEXT ("%s 10"), SLEEP_PATH); +#else + options.command_line (ACE_TEXT ("%ls 10"), SLEEP_PATH); +#endif + ACE_Process process1; + if (process1.spawn (options) == -1) + { + int error = ACE_OS::last_error (); + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("%p errno = %d.\n"), + ACE_TEXT ("test_ls"), + error)); + } + + int result; + ACE_exitcode status; + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("[%T] New process sleeping 10; try wait(2)\n"))); + + result = process1.wait (ACE_Time_Value (2), &status); + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("[%T] wait(2) returns %d(%d)...now try regular wait\n"), + result, + status)); + + result = process1.wait (&status); + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("[%T] wait() returns %d(%d)\n"), + result, + status)); + + ACE_Process process2; + if (process2.spawn (options) == -1) + { + int error = ACE_OS::last_error (); + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("%p errno = %d.\n"), + ACE_TEXT ("test_ls"), + error)); + } + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("[%T] New process sleeping 10; try wait(12)\n"), + status)); + + result = process2.wait (ACE_Time_Value (12), &status); + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("[%T] wait(12) returns %d(%d)...now try regular wait\n"), + result, + status)); + + result = process2.wait (&status); + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("[%T] wait returns %d(%d)\n"), + result, + status)); +} + +#if defined (ACE_WIN32) +// This is just to test the direct usage of CreateProcess. I use this +// occasionally as a sanity check when ACE_Process breaks. +static void +win32_test_ls (void) +{ + PROCESS_INFORMATION process_info; + ACE_TEXT_STARTUPINFO startup_info; + ACE_OS::memset ((void *) &startup_info, + 0, + sizeof startup_info); + ACE_OS::memset ((void *) &process_info, + 0, + sizeof process_info); + startup_info.cb = sizeof startup_info; + startup_info.dwFlags = STARTF_USESTDHANDLES; + + ACE_HANDLE std_out = ACE_STDOUT; + + if (!::DuplicateHandle (::GetCurrentProcess (), + std_out, + ::GetCurrentProcess (), + &startup_info.hStdOutput, + 0, + TRUE, + DUPLICATE_SAME_ACCESS)) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("%p duplicate failed.\n"), + ACE_TEXT ("test_ls"))); + return; + } + + BOOL fork_result = + ACE_TEXT_CreateProcess (ACE_TEXT ("c:\\Utils\\bin\\ls.exe"), + ACE_TEXT ("-a"), + NULL, // No process attributes. + NULL, // No thread attributes. + TRUE, // Allow handle inheritance. + 0, // CREATE_NEW_CONSOLE, // Create a new console window. + NULL, + 0, // Current directory to start in. + &startup_info, + &process_info); + + ::CloseHandle (startup_info.hStdOutput); + + if (fork_result == 0) + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("%p CreateProcess failed.\n"), + ACE_TEXT ("test_ls"))); + else + { + ::WaitForSingleObject (process_info.hProcess, + INFINITE); + ACE_DEBUG ((LM_ERROR, ACE_TEXT ("ls succeeded.\n"))); + } +} + +// This code spawns a new process. The new process inherits our +// existing environment, plus one more. This has to be done by hand +// since CreateProcess does not allow us to inherit AND add +// environment variables. + +static void +win32_spawn_environment_process (void) +{ + PROCESS_INFORMATION process_info; + ACE_TEXT_STARTUPINFO startup_info; + ACE_OS::memset ((void *) &startup_info, + 0, + sizeof startup_info); + ACE_OS::memset ((void *) &process_info, + 0, + sizeof process_info); + startup_info.cb = sizeof (startup_info); + startup_info.dwFlags = STARTF_USESTDHANDLES; + + ACE_HANDLE std_in = ACE_STDIN; + ACE_HANDLE std_out = ACE_STDOUT; + ACE_HANDLE std_err = ACE_STDERR; + + if (!::DuplicateHandle (::GetCurrentProcess(), + std_out, + ::GetCurrentProcess(), + &startup_info.hStdOutput, + 0, + TRUE, + DUPLICATE_SAME_ACCESS)) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("%p duplicate failed.\n"), + ACE_TEXT ("spawn_environment_process"))); + return; + } + + if (!::DuplicateHandle (::GetCurrentProcess(), + std_err, + ::GetCurrentProcess(), + &startup_info.hStdError, + 0, + TRUE, + DUPLICATE_SAME_ACCESS)) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("%p duplicate failed.\n"), + ACE_TEXT ("spawn_environment_process"))); + return; + } + + if (!::DuplicateHandle (::GetCurrentProcess(), + std_in, + ::GetCurrentProcess(), + &startup_info.hStdInput, + 0, + TRUE, + DUPLICATE_SAME_ACCESS)) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("%p duplicate failed.\n"), + ACE_TEXT ("spawn_environment_process"))); + return; + } + + // Normally, this would be just GetEnvironmentStrings, but it + // doesn't follow the same rules as the rest of the Win32 API + ACE_TCHAR *existing_environment = ACE_OS::getenvstrings (); + ACE_TCHAR environment[10240]; + ACE_OS::sprintf (environment, + ACE_TEXT("ACE_PROCESS_TEST=%s"), + environment_string); + + int size = 0; + while (existing_environment[size] != '\0') + size += ACE_OS::strlen (existing_environment + size) + 1; + + ACE_OS::memcpy (environment + (ACE_OS::strlen (environment) + 1), + existing_environment, + size); + + ACE_TEXT_FreeEnvironmentStrings (existing_environment); + + BOOL fork_result = + ACE_TEXT_CreateProcess (ACE_TEXT ("d:\\harrison\\ACE_wrappers\\examples\\OS\\Process\\process.exe"), + ACE_TEXT ("process -g"), + NULL, // No process attributes. + NULL, // No thread attributes. + TRUE, // Allow handle inheritance. + 0, // CREATE_NEW_CONSOLE, // Create a new console window. + environment, // Environment. + //"d:\\harrison\\ACE_wrappers\\examples\\OS\\Process\\", + 0, + &startup_info, + &process_info); + + ::CloseHandle (startup_info.hStdOutput); + ::CloseHandle (startup_info.hStdError); + + if (fork_result == 0) + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("%p.\n"), + ACE_TEXT ("spawn_environment_process"))); + else + { + ::WaitForSingleObject (process_info.hProcess, + INFINITE); + ACE_DEBUG ((LM_ERROR, + ACE_TEXT ("spawn_environment_process succeeded.\n"))); + } +} +#endif + +static void +test_setenv (const ACE_TCHAR *argv0) +{ + ACE_Process_Options options; + // options.setenv ("ACE_PROCESS_TEST", "here's a really large number: %u", 0 - 1); + options.setenv (ACE_TEXT ("ACE_PROCESS_TEST= here's a large number %u"), + 0 - 1); + options.setenv (ACE_TEXT ("ACE_PROCESS_TEST2"), ACE_TEXT ("ophilli")); +#if defined (ACE_WIN32) || !defined (ACE_USES_WCHAR) + options.command_line ("%s -g", argv0); +#else + options.command_line ("%ls -g", argv0); +#endif + ACE_Process process; + if (process.spawn (options) == -1) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("%p.\n"), + ACE_TEXT ("test_setenv"))); + return; + } + + ACE_exitcode status; + process.wait (&status); + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("Process exit with status %d\n"), + status)); +} + +// Tests the ACE_Tokenizer. +static void +tokenize (ACE_TCHAR *buffer) +{ + // This tokenizer will replace all spaces with end-of-string + // characters and will preserve text between "" and '' pairs. + ACE_Tokenizer parser (buffer); + parser.delimiter_replace (' ', '\0'); + parser.preserve_designators ('\"', '\"'); // " This quote is for emacs + parser.preserve_designators ('\'', '\''); + + for (const ACE_TCHAR *temp; ;) + { + temp = parser.next (); + if (temp == 0) + break; + ACE_DEBUG ((LM_DEBUG, temp)); + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\n"))); + } +} + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + if (ACE_LOG_MSG->open (argv[0]) == -1) + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("cannot open logger!!!\n"))); + + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("starting...\n"))); + + if (::parse_args (argc, argv) == -1) + return -1; + + if (run_all) + { +#if defined (ACE_WIN32) || !defined (ACE_USES_WCHAR) + const ACE_TCHAR *cmdline = ACE_TEXT ("%s -d -l -s -w"); +#else + const ACE_TCHAR *cmdline = ACE_TEXT ("%ls -d -l -s -w"); +#endif + ACE_Process_Options options; + options.command_line (cmdline, argv[0]); + ACE_Process process; + if (process.spawn (options) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p.\n"), + ACE_TEXT ("main")), + -1); + ACE_exitcode status; + process.wait (&status); + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("Process exit with status %d\n"), + status)); + } + + if (run_date) + ::test_date (); + + if (run_setenv) + ::test_setenv (argv[0]); + + if (get_env) + { + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("checking ACE_PROCESS_TEST\n"))); + char *value = ACE_OS::getenv ("ACE_PROCESS_TEST"); + char *value2 = ACE_OS::getenv ("ACE_PROCESS_TEST2"); + ACE_DEBUG ((LM_DEBUG, + "ACE_PROCESS_TEST = %C.\n" + "ACE_PROCESS_TEST2 = %C.\n", + value == 0 ? "no value" : value, + value2 == 0 ? "no value" : value2)); + } + + if (run_ls) + ::test_ls (); + + if (run_wait) + ::test_wait (); + +#if defined (ACE_WIN32) + if (environment_string != 0) + win32_spawn_environment_process (); +#endif /* ACE_WIN32 */ + + if (print_file != 0) + test_more (); + + ACE_TCHAR buf1[30]; + ACE_TCHAR buf2[30]; + ACE_OS::strcpy(buf1, ACE_TEXT (" -f hi honey -g \"I\'m home\"")); + ACE_OS::strcpy(buf2, ACE_TEXT ("\"token 1\"\'token 2\'\"token 3\" ")); + + if (run_tokenizer) + { + tokenize (buf1); + tokenize (buf2); + } + + return 0; +} diff --git a/ACE/examples/QOS/Change_Receiver_FlowSpec/Fill_ACE_QoS.cpp b/ACE/examples/QOS/Change_Receiver_FlowSpec/Fill_ACE_QoS.cpp new file mode 100644 index 00000000000..20c03f40fa6 --- /dev/null +++ b/ACE/examples/QOS/Change_Receiver_FlowSpec/Fill_ACE_QoS.cpp @@ -0,0 +1,99 @@ +// Fill_ACE_QoS.cpp +// $Id$ + +#include "Fill_ACE_QoS.h" + +ACE_RCSID(QOS, Fill_ACE_QoS,"$Id$") + +const iovec Fill_ACE_QoS::iov_ = {0,0}; + +Fill_ACE_QoS::Fill_ACE_QoS (void) +{ + ACE_NEW (this->default_traffic_, + ACE_Flow_Spec (ACE_QOS_NOT_SPECIFIED, + ACE_QOS_NOT_SPECIFIED, + ACE_QOS_NOT_SPECIFIED, + ACE_QOS_NOT_SPECIFIED, + ACE_QOS_NOT_SPECIFIED, + ACE_SERVICETYPE_NOTRAFFIC, + ACE_QOS_NOT_SPECIFIED, + ACE_QOS_NOT_SPECIFIED, + 25, + 1)); +} + +// destructor. +Fill_ACE_QoS::~Fill_ACE_QoS (void) +{} + +int +Fill_ACE_QoS::fill_simplex_receiver_qos (ACE_QoS &ace_qos, + const ACE_CString &recv_flow_name) +{ + ACE_Flow_Spec *recv_flow_spec = 0; + + if (this->map ().find (recv_flow_name, recv_flow_spec) != 0) + ACE_ERROR_RETURN ((LM_DEBUG, + "Unable to find a FlowSpec with name %s", + recv_flow_name.c_str ()), + -1); + ace_qos.receiving_flowspec (recv_flow_spec); + ace_qos.sending_flowspec ((this->default_traffic_)); + ace_qos.provider_specific (Fill_ACE_QoS::iov_); + + return 0; +} + + +int +Fill_ACE_QoS::fill_simplex_sender_qos (ACE_QoS &ace_qos, + const ACE_CString &send_flow_name) +{ + ACE_Flow_Spec *send_flow_spec = 0; + + if (this->map ().find (send_flow_name, send_flow_spec) != 0) + ACE_ERROR_RETURN ((LM_DEBUG, + "Unable to find a FlowSpec with name %s", + send_flow_name.c_str ()), + -1); + + ace_qos.receiving_flowspec ((this->default_traffic_)); + ace_qos.sending_flowspec (send_flow_spec); + ace_qos.provider_specific (Fill_ACE_QoS::iov_); + + return 0; +} + +int +Fill_ACE_QoS::fill_duplex_qos (ACE_QoS &ace_qos, + const ACE_CString &recv_flow_name, + const ACE_CString &send_flow_name) +{ + ACE_Flow_Spec *send_flow_spec = 0; + ACE_Flow_Spec *recv_flow_spec = 0; + + if (this->map ().find (recv_flow_name, recv_flow_spec) != 0) + ACE_ERROR_RETURN ((LM_DEBUG, + "Unable to find a FlowSpec with name %s", + recv_flow_name.c_str ()), + -1); + + if (this->map ().find (send_flow_name, send_flow_spec) != 0) + ACE_ERROR_RETURN ((LM_DEBUG, + "Unable to find a FlowSpec with name %s", + send_flow_name.c_str ()), + -1); + + ace_qos.receiving_flowspec (recv_flow_spec); + ace_qos.sending_flowspec (send_flow_spec); + ace_qos.provider_specific (Fill_ACE_QoS::iov_); + + return 0; +} + +Fill_ACE_QoS::FLOW_SPEC_HASH_MAP& +Fill_ACE_QoS::map (void) +{ + return this->flow_spec_map_; +} + diff --git a/ACE/examples/QOS/Change_Receiver_FlowSpec/Fill_ACE_QoS.h b/ACE/examples/QOS/Change_Receiver_FlowSpec/Fill_ACE_QoS.h new file mode 100644 index 00000000000..cdc06cea422 --- /dev/null +++ b/ACE/examples/QOS/Change_Receiver_FlowSpec/Fill_ACE_QoS.h @@ -0,0 +1,76 @@ +/* -*- C++ -*- */ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// ACE_wrappers/examples/QOS +// +// = FILENAME +// Fill_ACE_QoS.h +// +// = AUTHOR +// Vishal Kachroo <vishal@cs.wustl.edu> +// +// ============================================================================ + +#ifndef FILL_ACE_QOS_H +#define FILL_ACE_QOS_H + +#include "ace/SString.h" +#include "ace/Hash_Map_Manager.h" +#include "ace/Synch_Traits.h" +#include "ace/Null_Mutex.h" +#include "ace/ACE.h" +#include "ace/OS_QoS.h" + +class Fill_ACE_QoS +{ + // TITLE + // This class helps users to add new flow specs and provides + // utility functions for filling up the flow specs for simplex/duplex + // sessions. + +public: + typedef ACE_Hash_Map_Manager <ACE_CString, ACE_Flow_Spec *, ACE_Null_Mutex> FLOW_SPEC_HASH_MAP; + + //Initialization and termination methods. + Fill_ACE_QoS (void); + // constructor. + + ~Fill_ACE_QoS (void); + // destructor. + + int fill_simplex_receiver_qos (ACE_QoS &ace_qos, + const ACE_CString &recv_flow_name); + // To be used by receivers. Fills the receiver qos and sets the + // sender qos to NO_TRAFFIC. + + int fill_simplex_sender_qos (ACE_QoS &ace_qos, + const ACE_CString &send_flow_name); + // To be used by senders. Fills the sender qos and sets the receiver + // qos to NO_TRAFFIC. + + int fill_duplex_qos (ACE_QoS &ace_qos, + const ACE_CString &recv_flow_name, + const ACE_CString &send_flow_name); + // To be used by applications that wish to be both receivers and + // senders. + + FLOW_SPEC_HASH_MAP& map (void); + // Returns the hash map of flowspecs indexed by flowspec name. + +private: + + // The Service Provider is currently set to NULL for all ACE_QoS. + static const iovec iov_; + + // A NO_TRAFFIC flow spec. Senders set the receiving qos to this + // while the receivers set the sending qos to this. + ACE_Flow_Spec *default_traffic_; + + // A list of flowspecs indexed by the flowspec name. + FLOW_SPEC_HASH_MAP flow_spec_map_; +}; + +#endif /* FILL_ACE_QOS_H */ diff --git a/ACE/examples/QOS/Change_Receiver_FlowSpec/FlowSpec_Dbase.h b/ACE/examples/QOS/Change_Receiver_FlowSpec/FlowSpec_Dbase.h new file mode 100644 index 00000000000..fc382048c13 --- /dev/null +++ b/ACE/examples/QOS/Change_Receiver_FlowSpec/FlowSpec_Dbase.h @@ -0,0 +1,52 @@ +/* -*- C++ -*- */ +//$Id$ + +// ============================================================================ +// +// = LIBRARY +// ACE_wrappers/examples/QOS +// +// = FILENAME +// FlowSpec_Dbase.h +// +// = AUTHOR +// Vishal Kachroo <vishal@cs.wustl.edu> +// +// ============================================================================ + +#ifndef FLOWSPEC_DBASE_H +#define FLOWSPEC_DBASE_H + +// This file contains the different FlowSpecs that the QoS enabled +// application uses. Its a good idea to list them all here so the +// application code is clean. + +ACE_Flow_Spec notraffic (ACE_QOS_NOT_SPECIFIED, + ACE_QOS_NOT_SPECIFIED, + ACE_QOS_NOT_SPECIFIED, + ACE_QOS_NOT_SPECIFIED, + ACE_QOS_NOT_SPECIFIED, + ACE_SERVICETYPE_NOTRAFFIC, + ACE_QOS_NOT_SPECIFIED, + ACE_QOS_NOT_SPECIFIED, + 25, + 1); + +ACE_Flow_Spec g711 (9200, + 708, + 18400, + 0, + 0, + ACE_SERVICETYPE_CONTROLLEDLOAD, + 368, + 368, + 25, + 1); + +// The default session address is macarena.cs.wustl.edu. I am using macarena +// as my receiver for testing. +#define DEFAULT_QOS_SESSION_MACHINE "128.252.165.127" +#define DEFAULT_QOS_SESSION_PORT 8001 + +#endif /* FLOWSPEC_DBASE_H */ + diff --git a/ACE/examples/QOS/Change_Receiver_FlowSpec/Makefile.am b/ACE/examples/QOS/Change_Receiver_FlowSpec/Makefile.am new file mode 100644 index 00000000000..c4d51897787 --- /dev/null +++ b/ACE/examples/QOS/Change_Receiver_FlowSpec/Makefile.am @@ -0,0 +1,76 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +ACE_BUILDDIR = $(top_builddir) +ACE_ROOT = $(top_srcdir) + +noinst_PROGRAMS = + +## Makefile.QOS_Change_Receiver_FlowSpec_Receiver.am + +if BUILD_QOS +noinst_PROGRAMS += receiver + +receiver_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) \ + -DACE_HAS_QOS + +receiver_SOURCES = \ + Fill_ACE_QoS.cpp \ + QoS_Signal_Handler.cpp \ + QoS_Util.cpp \ + Receiver_QoS_Event_Handler.cpp \ + receiver.cpp \ + Fill_ACE_QoS.h \ + QoS_Signal_Handler.h \ + QoS_Util.h \ + Receiver_QoS_Event_Handler.h + +receiver_LDADD = \ + $(ACE_BUILDDIR)/ace/QoS/libACE_QoS.la \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif BUILD_QOS + +## Makefile.QOS_Change_Receiver_FlowSpec_Sender.am + +if BUILD_QOS +noinst_PROGRAMS += sender + +sender_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) \ + -DACE_HAS_QOS + +sender_SOURCES = \ + Fill_ACE_QoS.cpp \ + QoS_Signal_Handler.cpp \ + QoS_Util.cpp \ + Sender_QoS_Event_Handler.cpp \ + sender.cpp \ + Fill_ACE_QoS.h \ + QoS_Signal_Handler.h \ + QoS_Util.h \ + Sender_QoS_Event_Handler.h + +sender_LDADD = \ + $(ACE_BUILDDIR)/ace/QoS/libACE_QoS.la \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif BUILD_QOS + +## Clean up template repositories, etc. +clean-local: + -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.* + -rm -f gcctemp.c gcctemp so_locations *.ics + -rm -rf cxx_repository ptrepository ti_files + -rm -rf templateregistry ir.out + -rm -rf ptrepository SunWS_cache Templates.DB diff --git a/ACE/examples/QOS/Change_Receiver_FlowSpec/QOS_Change_Receiver_FlowSpec.mpc b/ACE/examples/QOS/Change_Receiver_FlowSpec/QOS_Change_Receiver_FlowSpec.mpc new file mode 100644 index 00000000000..9767bd6fdb9 --- /dev/null +++ b/ACE/examples/QOS/Change_Receiver_FlowSpec/QOS_Change_Receiver_FlowSpec.mpc @@ -0,0 +1,25 @@ +// -*- MPC -*- +// $Id$ + +project(*receiver) : aceexe, qos { + exename = receiver + requires += qos + Source_Files { + Fill_ACE_QoS.cpp + QoS_Signal_Handler.cpp + QoS_Util.cpp + receiver.cpp + Receiver_QoS_Event_Handler.cpp + } +} +project(*sender) : aceexe, qos { + exename = sender + requires += qos + Source_Files { + Fill_ACE_QoS.cpp + QoS_Signal_Handler.cpp + QoS_Util.cpp + sender.cpp + Sender_QoS_Event_Handler.cpp + } +} diff --git a/ACE/examples/QOS/Change_Receiver_FlowSpec/QoS_Signal_Handler.cpp b/ACE/examples/QOS/Change_Receiver_FlowSpec/QoS_Signal_Handler.cpp new file mode 100644 index 00000000000..9f07ad5b378 --- /dev/null +++ b/ACE/examples/QOS/Change_Receiver_FlowSpec/QoS_Signal_Handler.cpp @@ -0,0 +1,34 @@ +// QoS_Signal_Handler.cpp +// $Id$ + +#include "ace/Log_Msg.h" +#include "QoS_Signal_Handler.h" + +ACE_RCSID(QOS, QoS_Signal_Handler,"$Id$") + +// constructor. +QoS_Signal_Handler::QoS_Signal_Handler (ACE_QoS_Session *qos_session) + : qos_session_ (qos_session) +{ +} + +// Releases the QoS sessions gracefully. +int +QoS_Signal_Handler::handle_signal (int signum, siginfo_t *, ucontext_t*) +{ + if (signum == SIGINT) + { + if (this->qos_session_->close () == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "Unable to close the QoS session.\n"), + -1); + else + ACE_DEBUG ((LM_DEBUG, + "QoS Session with id %d closed successfully.\n", + this->qos_session_->session_id ())); + } + else + ACE_DEBUG ((LM_DEBUG, + "A signal other than SIGINT received.\nIgnoring.\n")); + return 0; +} diff --git a/ACE/examples/QOS/Change_Receiver_FlowSpec/QoS_Signal_Handler.h b/ACE/examples/QOS/Change_Receiver_FlowSpec/QoS_Signal_Handler.h new file mode 100644 index 00000000000..35b9f3a19e7 --- /dev/null +++ b/ACE/examples/QOS/Change_Receiver_FlowSpec/QoS_Signal_Handler.h @@ -0,0 +1,45 @@ +/* -*- C++ -*- */ +// $Id$ + +// ===================================================================== +// +// = LIBRARY +// ACE_wrappers/examples/QOS +// +// = FILENAME +// QoS_Signal_Handler.h +// +// = AUTHOR +// Vishal Kachroo <vishal@cs.wustl.edu> +// +// ===================================================================== + +#ifndef QOS_SIGNAL_HANDLER_H +#define QOS_SIGNAL_HANDLER_H + +#include "ace/Event_Handler.h" +#include "ace/QoS/QoS_Session.h" + +class QoS_Signal_Handler : public ACE_Event_Handler +{ + // TITLE + // This class Handles the SIGINT signal through the Reactor. + // Useful to gracefully release QoS sessions. + +public: + + QoS_Signal_Handler (ACE_QoS_Session *qos_session); + // constructor. + + int handle_signal(int signum, siginfo_t*,ucontext_t*); + // Override this method to implement graceful shutdown. + +private: + + ACE_QoS_Session *qos_session_; + // Session to be gracefully shutdown. + +}; + +#endif /* QOS_SIGNAL_HANDLER_H */ + diff --git a/ACE/examples/QOS/Change_Receiver_FlowSpec/QoS_Util.cpp b/ACE/examples/QOS/Change_Receiver_FlowSpec/QoS_Util.cpp new file mode 100644 index 00000000000..0ef3b353248 --- /dev/null +++ b/ACE/examples/QOS/Change_Receiver_FlowSpec/QoS_Util.cpp @@ -0,0 +1,122 @@ +// QoS_Session_Impl.cpp +// $Id$ + +#define SENDER_PORT 10001 + +#include "ace/Log_Msg.h" +#include "ace/Get_Opt.h" +#include "QoS_Util.h" +#include "ace/OS_NS_strings.h" + +ACE_RCSID(QOS, QoS_Util,"$Id$") + +// constructor. +QoS_Util::QoS_Util (int argc, + ACE_TCHAR *argv[]) + : argc_ (argc), + argv_ (argv), + source_port_ (SENDER_PORT), + protocol_ (IPPROTO_UDP), + multicast_flag_ (0) +{ + ACE_NEW (this->mult_session_addr_, + ACE_INET_Addr (ACE_DEFAULT_MULTICAST_PORT)); + + ACE_NEW (this->dest_addr_, + ACE_INET_Addr (ACE_DEFAULT_SERVER_PORT)); +} + +// destructor. +QoS_Util::~QoS_Util (void) +{ + delete this->mult_session_addr_; + delete this->dest_addr_; +} + +int +QoS_Util::parse_args (void) +{ + ACE_Get_Opt get_opts (this->argc_, this->argv_, ACE_TEXT("m:n:p:P:c")); + int c = 0; + + while ((c = get_opts ()) != -1) + switch (c) + { + case 'm': // multicast session address. + this->multicast_flag_ = 1; + this->mult_session_addr_->set (get_opts.opt_arg ()); + break; + case 'n': // to be used by Senders only to specify the destination. + this->dest_addr_->set (get_opts.opt_arg ()); + break; + case 'p': // protocol. + if (ACE_OS::strcasecmp (get_opts.opt_arg (), ACE_TEXT("tcp")) == 0) + this->protocol_ = IPPROTO_TCP; + else + if (ACE_OS::strcasecmp (get_opts.opt_arg (), ACE_TEXT("udp")) == 0) + this->protocol_ = IPPROTO_UDP; + else + ACE_DEBUG ((LM_DEBUG, + "Unknown protocol specified\n" + "UDP assumed\n")); + break; + case 'P': // sender source port. + this->source_port_ = ACE_OS::atoi (get_opts.opt_arg ()); + break; + case 'h': // display help for different options. + default: + ACE_ERROR_RETURN ((LM_ERROR, + "usage: %s" + " [-m host:port] QoS multicast session address" + " Overides the receiver address specified in the -n option" + " [-n host:port] Use for a unicast sender. " + " Follow by receiver addr" + " [-p tcp|udp] specify protocol to be used" + " [-P port] source sender port" + " [-h] <help>" + "\n", + argv_ [0]), + -1); + } + + // If multicast address is specified then ignore the unicast sender + // destination address and force the protocol to be UDP. + if (this->multicast_flag_ == 1) + { + this->dest_addr_ = this->mult_session_addr_; + this->protocol_ = IPPROTO_UDP; + } + + // Indicates successful parsing of command line. + return 0; +} + +ACE_INET_Addr * +QoS_Util::mult_session_addr (void) const +{ + return this->mult_session_addr_; +} + +ACE_INET_Addr * +QoS_Util::dest_addr (void) const +{ + return this->dest_addr_; +} + +u_short +QoS_Util::source_port (void) const +{ + return this->source_port_; +} + +ACE_Protocol_ID +QoS_Util::protocol (void) const +{ + return this->protocol_; +} + +int +QoS_Util::multicast_flag (void) const +{ + return this->multicast_flag_; +} diff --git a/ACE/examples/QOS/Change_Receiver_FlowSpec/QoS_Util.h b/ACE/examples/QOS/Change_Receiver_FlowSpec/QoS_Util.h new file mode 100644 index 00000000000..ae347de68f6 --- /dev/null +++ b/ACE/examples/QOS/Change_Receiver_FlowSpec/QoS_Util.h @@ -0,0 +1,75 @@ +/* -*- C++ -*- */ +// $Id$ + +// ===================================================================== +// +// = LIBRARY +// ACE_wrappers/examples/QOS +// +// = FILENAME +// QoS_Util.h +// +// = AUTHOR +// Vishal Kachroo <vishal@cs.wustl.edu> +// +// ===================================================================== + +#ifndef QOS_UTIL_H +#define QOS_UTIL_H + +#include "ace/INET_Addr.h" +#include "ace/QoS/QoS_Session.h" + +class QoS_Util +{ + // = TITLE + // This class provides the utility functions like parse_args () + // required by a QoS enabled application. + +public: + + // constructor. + QoS_Util (int argc, ACE_TCHAR *argv[]); + + // destructor. + ~QoS_Util (void); + + // Parse command-line arguments. + int parse_args (void); + + // GET methods. + ACE_INET_Addr *mult_session_addr (void) const; + + ACE_INET_Addr *dest_addr (void) const; + + u_short source_port (void) const; + + ACE_Protocol_ID protocol (void) const; + + int multicast_flag (void) const; + +private: + + // Command line arguments. + int argc_; + ACE_TCHAR **argv_; + + // Multicast session address. + ACE_INET_Addr *mult_session_addr_; + + // Unicast destination address of the receiver. + ACE_INET_Addr *dest_addr_; + + // Source port for the sender. + u_short source_port_; + + // Protocol. + ACE_Protocol_ID protocol_; + + // Multicast Flag. + int multicast_flag_; + +}; + +#endif /* QOS_UTIL_H */ + diff --git a/ACE/examples/QOS/Change_Receiver_FlowSpec/README b/ACE/examples/QOS/Change_Receiver_FlowSpec/README new file mode 100644 index 00000000000..58320ef8def --- /dev/null +++ b/ACE/examples/QOS/Change_Receiver_FlowSpec/README @@ -0,0 +1,127 @@ +$Id$ + +A Regression test for ACE QoS features. +--------------------------------------- + +This test implements a simple Receiver-Sender program that ensures +Quality of Service (QoS) guarantees on the underlying network before +transmitting data. The program tests the ACE QoS APIs/features. The +test works for Winsock2 APIs on Win2K as well as RAPI on Solaris. + +In addition it dynamically changes the receiver flow spec which in +turn changes the RESV messages sent. + + +------------------------------------------------------------------------ +WIN2K : + +Build Requirements : +-------------------- +1. Two Win2K machines. +2. June98 Platform SDK or later. +3. Link with ws2_32.lib + +The test consists of a server (which is the receiver) and a client + (which is the sender). + + The receiver is started first (though it is not mandatory) as : + + server -m merengue.cs.wustl.edu:9091 + + -m: specifies the multicast session address that both client and + server subscribe to for QoS events. + + -p: Protocol to be used. Could be udp or tcp. Default is udp. + + -P: Sender source port. If not specified, DEFAULT_SOURCE_SENDER_PORT + (10001) will be used. + + -h: Displays the help on various options. + +The sample Sender is started next as : + + client -m merengue.cs.wustl.edu:9091 -P 10004 + + -m: specifies the multicast session address that both client and + server subscribe to for QoS events. + + -n: Option to be used by senders only to specify the destination + address. This option is overriden if a multicast address is also + specified through the -m option. + + -p: Protocol to be used. Could be udp or tcp. Default is udp. + + -P: Sender source port. If not specified, DEFAULT_SOURCE_SENDER_PORT + (10001) will be used. + + -h: Displays the help on various options. + +On Win2K the user must have administrative access to the machine to +run this program. It seems to be a pre-requisite to opening QoS +sockets. + +The sender and receiver should be run on different Win2K machines. + +The test demonstrates how to GQOS enable an application using the ACE QoS APIs. +It concentrates on the use of various ACE QoS APIs and their correctness. + +------------------------------------------------------------------------------- + +RAPI : + +0. The $ACE_ROOT/include/makeinclude/platform_macros.GNU should be the +following : + +include /project/doc/vishal/ACE_wrappers/include/makeinclude/platform_sunos5_sunc++.GNU +PLATFORM_RAPI_CPPFLAGS += -I/project/doc/vishal/rapi/rel4.2a4/rsvpd/ +PLATFORM_RAPI_LIBS += -lrsvp +PLATFORM_RAPI_LDFLAGS += -L/project/doc/vishal/rapi/rel4.2a4/rsvpd/ + +assuming that RAPI library is installed in /project/doc/vishal/rapi/rel4.2a4/ + +1. Compile ACE with + + make rapi=1 static_libs_only=1 + + Static library option is used because the RAPI library that we have + does not compile as a shared object. + +2. Run the RSVP Daemon on two machines: (merengue.cs and macarena.cs) + + /project/doc/vishal/rapi/rel4.2a4/rsvpd/rsvpd -D + + The current version of the daemon comes with an inbuilt rtap + application to test the various reservation commands and RAPI APIs. + + Typical values for rtap would be : + + sender merengue/5000 [ t 2000000 100000 2000000 512 1024 ] + reserve wf [ cl 4000000 200000 4000000 256 2024 ] + + + + From ACE: + dest udp macarena/5000 + sender ace/5000 [ t 2000000 100000 2000000 512 1024 ] + sender macarena/5022 [ t 2000000 100000 2000000 512 1024 ] + sender beguine/6000 [ t 2000000 100000 2000000 512 1024 ] + + From Macarena: + wait until done with ACE + dest udp macarena/5000 <session name> + reserve wf [ cl 2000000 100000 2000000 512 1024 ] + + + +3. If RTAP runs fine and the daemons show the debug messages about + RESV, PATH and other RSVP messages, run the QoS example, making sure + that rtap session is released on both machines. + +------------------------------------------------------------------------------- + +If you run into any problems with this test please contact Vishal +Kachroo <vishal@cs.wustl.edu>. + +This README last updated on 20th July, 2000. + +------------------------------------------------------------------------------- diff --git a/ACE/examples/QOS/Change_Receiver_FlowSpec/Receiver_QoS_Event_Handler.cpp b/ACE/examples/QOS/Change_Receiver_FlowSpec/Receiver_QoS_Event_Handler.cpp new file mode 100644 index 00000000000..33176ba4da3 --- /dev/null +++ b/ACE/examples/QOS/Change_Receiver_FlowSpec/Receiver_QoS_Event_Handler.cpp @@ -0,0 +1,216 @@ +/* -*- C++ -*- */ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// ACE_wrappers/examples/QOS +// +// = FILENAME +// Receiver_QoS_Event_Handler.cpp +// +// = AUTHOR +// Vishal Kachroo <vishal@cs.wustl.edu> +// +// ============================================================================ + +#include "Receiver_QoS_Event_Handler.h" +#include "ace/Log_Msg.h" +#include "ace/SString.h" +#include "Fill_ACE_QoS.h" + +// Constructor. +Receiver_QoS_Event_Handler::Receiver_QoS_Event_Handler (void) +{ +} + +Receiver_QoS_Event_Handler::Receiver_QoS_Event_Handler (const ACE_SOCK_Dgram_Mcast_QoS + &dgram_mcast_qos, + ACE_QoS_Session *qos_session) + : dgram_mcast_qos_ (dgram_mcast_qos), + qos_session_ (qos_session) +{ +} + +// Destructor. +Receiver_QoS_Event_Handler::~Receiver_QoS_Event_Handler (void) +{ +} + +// Return the handle of the Dgram_Mcast. This method is called +// internally by the reactor. +ACE_HANDLE +Receiver_QoS_Event_Handler::get_handle (void) const +{ + return this->dgram_mcast_qos_.get_handle (); +} + +// Called when there is a READ activity on the dgram_mcast_qos handle. +int +Receiver_QoS_Event_Handler::handle_input (ACE_HANDLE) +{ + char buf[BUFSIZ]; + + iovec iov; + iov.iov_base = buf; + iov.iov_len = BUFSIZ; + + ACE_OS::memset (iov.iov_base, + 0, + BUFSIZ); + + ACE_DEBUG ((LM_DEBUG, + "Inside handle_input () of Receiver_QoS_Event_Handler ()\n")); + + // Receive message from multicast group. + ssize_t result = + this->dgram_mcast_qos_.recv (&iov, + 1, + this->remote_addr_); + + if (result != -1) + { + ACE_DEBUG ((LM_DEBUG, + "Message Received : %s", + iov.iov_base)); + return 0; + } + else + return -1; +} + +// Called when there is a QoS Event. +int +Receiver_QoS_Event_Handler::handle_qos (ACE_HANDLE fd) +{ + ACE_UNUSED_ARG (fd); + + ACE_DEBUG ((LM_DEBUG, + "\nReceived a QOS event. Inside handle_qos ()\n")); + + // We have received an RSVP event. The following update_qos () call + // calls rapi_dispatch () in case of RAPI and WSAIoctl (GET_QOS) in + // case of W2K. It then does the QoS parameter translation and updates + // the QoS session object with the latest QoS. This call replaces the + // direct call that was being made to WSAIoctl (GET_QOS) here for the + // Win2K example. + + if (this->qos_session_->update_qos () == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "Error in updating QoS\n"), + -1); + else + ACE_DEBUG ((LM_DEBUG, + " Updating QOS succeeds.\n")); + + // Now proactively query the QoS object for QoS. + ACE_QoS ace_get_qos = this->qos_session_->qos (); + + ACE_DEBUG ((LM_DEBUG, + "\nReceiving Flowspec :\t\t\tSending Flowspec :\n\n" + "\tToken Rate = %d\t\t\tToken Rate = %d\n" + "\tToken Bucket Size = %d\t\t\tToken Bucket Size = %d\n" + "\tPeak Bandwidth = %d\t\t\tPeak Bandwidth = %d\n" + "\tLatency = %d\t\t\t\tLatency = %d\n" + "\tDelay Variation = %d\t\t\tDelay Variation = %d\n" + "\tService Type = %d\t\t\tService Type = %d\n" + "\tMax SDU Size = %d\t\t\tMax SDU Size = %d\n" + "\tMinimum Policed Size = %d\t\tMinimum Policed Size = %d\n\n", + ace_get_qos.receiving_flowspec ()->token_rate (), + ace_get_qos.sending_flowspec ()->token_rate (), + ace_get_qos.receiving_flowspec ()->token_bucket_size (), + ace_get_qos.sending_flowspec ()->token_bucket_size (), + ace_get_qos.receiving_flowspec ()->peak_bandwidth (), + ace_get_qos.sending_flowspec ()->peak_bandwidth (), + ace_get_qos.receiving_flowspec ()->latency (), + ace_get_qos.sending_flowspec ()->latency (), + ace_get_qos.receiving_flowspec ()->delay_variation (), + ace_get_qos.sending_flowspec ()->delay_variation (), + ace_get_qos.receiving_flowspec ()->service_type (), + ace_get_qos.sending_flowspec ()->service_type (), + ace_get_qos.receiving_flowspec ()->max_sdu_size (), + ace_get_qos.sending_flowspec ()->max_sdu_size (), + ace_get_qos.receiving_flowspec ()->minimum_policed_size (), + ace_get_qos.sending_flowspec ()->minimum_policed_size ())); + + + // + // create a dynamic flow spec on each callback to test QoS retransmits + // + ACE_CString flow_id ("flow_id"); + + Fill_ACE_QoS flow_spec_list; + ACE_DEBUG ((LM_DEBUG, + "\nA new flow spec! in QoS handler.")); + + static int token_rate = 9400; + ++token_rate; + static int peak_bw = 18500; + ++peak_bw; + switch (flow_spec_list.map ().bind (flow_id, + new ACE_Flow_Spec (token_rate, + 708, + peak_bw, + 0, + 0, + ACE_SERVICETYPE_CONTROLLEDLOAD, + 368, + 368, + 25, + 1))) + { + case 1 : + ACE_ERROR_RETURN ((LM_ERROR, + "Unable to bind the new flow spec\n" + "The Flow Spec name already exists\n"), + -1); + break; + case -1 : + ACE_ERROR_RETURN ((LM_ERROR, + "Unable to bind the new flow spec\n"), + -1); + break; + } + + // + // set up the new qos + // + ACE_QoS another_qos_receiver; + if (flow_spec_list.fill_simplex_receiver_qos (another_qos_receiver, + flow_id) !=0) + ACE_ERROR_RETURN ((LM_ERROR, + "Unable to fill handler-simplex receiver qos\n"), + -1); + else + ACE_DEBUG ((LM_DEBUG, + "Successfully built a new flowspec in handle_qos!\n")); + + // + // change the qos for the current session + // + ACE_QoS_Manager qos_manager = this->dgram_mcast_qos_.qos_manager (); + + ACE_DEBUG ((LM_DEBUG, + "QoS Manager was built in handle_qos!\n")); + + // Set the QoS for the session. Replaces the ioctl () call that + // was being made previously. + if (this->qos_session_->qos (&this->dgram_mcast_qos_, + &qos_manager, + another_qos_receiver) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "Unable to set QoS\n"), + -1); + else + ACE_DEBUG ((LM_DEBUG, + "Setting QOS succeeds.\n")); + +return 0; + +} + + + + + + diff --git a/ACE/examples/QOS/Change_Receiver_FlowSpec/Receiver_QoS_Event_Handler.h b/ACE/examples/QOS/Change_Receiver_FlowSpec/Receiver_QoS_Event_Handler.h new file mode 100644 index 00000000000..874d628e3c1 --- /dev/null +++ b/ACE/examples/QOS/Change_Receiver_FlowSpec/Receiver_QoS_Event_Handler.h @@ -0,0 +1,61 @@ +/* -*- C++ -*- */ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// ACE_wrappers/examples/QOS +// +// = FILENAME +// Receiver_QoS_Event_Handler.h +// +// = AUTHOR +// Vishal Kachroo <vishal@cs.wustl.edu> +// +// ============================================================================ + +#ifndef RECEIVER_QOS_EVENT_HANDLER_H +#define RECEIVER_QOS_EVENT_HANDLER_H + +#include "ace/Reactor.h" +#include "ace/INET_Addr.h" +#include "ace/Event_Handler.h" +#include "ace/QoS/QoS_Session.h" +#include "ace/QoS/SOCK_Dgram_Mcast_QoS.h" + +ACE_RCSID(Receiver_QoS_Event_Handler, Receiver_QoS_Event_Handler, "$Id$") + + class Receiver_QoS_Event_Handler : public ACE_Event_Handler + { + public: + // = Initialization and Termination methods. + Receiver_QoS_Event_Handler (void); + // Constructor. + + Receiver_QoS_Event_Handler::Receiver_QoS_Event_Handler (const ACE_SOCK_Dgram_Mcast_QoS &dgram_mcast_qos, + ACE_QoS_Session *qos_session); + // Constructor. + + ~Receiver_QoS_Event_Handler (void); + // Destructor. + + virtual ACE_HANDLE get_handle (void) const; + // Override this to return the handle of the Dgram_Mcast + // that we are using. + + virtual int handle_input (ACE_HANDLE fd); + // Handles a READ event. + + virtual int handle_qos (ACE_HANDLE fd); + // Handles a QoS event. + + private: + ACE_SOCK_Dgram_Mcast_QoS dgram_mcast_qos_; + ACE_QoS_Session *qos_session_; + ACE_INET_Addr remote_addr_; + }; + +#endif /* RECEIVER_QOS_EVENT_HANDLER_H */ + + + diff --git a/ACE/examples/QOS/Change_Receiver_FlowSpec/Sender_QoS_Event_Handler.cpp b/ACE/examples/QOS/Change_Receiver_FlowSpec/Sender_QoS_Event_Handler.cpp new file mode 100644 index 00000000000..561746a3641 --- /dev/null +++ b/ACE/examples/QOS/Change_Receiver_FlowSpec/Sender_QoS_Event_Handler.cpp @@ -0,0 +1,146 @@ +/* -*- C++ -*- */ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// ACE_wrappers/examples/QOS +// +// = FILENAME +// Sender_QoS_Event_Handler.cpp +// +// = AUTHOR +// Vishal Kachroo <vishal@cs.wustl.edu> +// +// ============================================================================ + +#include "Sender_QoS_Event_Handler.h" +#include "ace/Log_Msg.h" + +#include "Fill_ACE_QoS.h" + +// Constructor. +Sender_QoS_Event_Handler::Sender_QoS_Event_Handler (void) +{ +} + +// Constructor. +Sender_QoS_Event_Handler::Sender_QoS_Event_Handler (const ACE_SOCK_Dgram_Mcast_QoS + &dgram_mcast_qos, + ACE_QoS_Session *qos_session) + : dgram_mcast_qos_ (dgram_mcast_qos), + qos_session_ (qos_session) +{ +} + +// Destructor. +Sender_QoS_Event_Handler::~Sender_QoS_Event_Handler (void) +{ +} + +// Return the handle of the Dgram_Mcast. This method is called +// internally by the reactor. + +ACE_HANDLE +Sender_QoS_Event_Handler::get_handle (void) const +{ + return this->dgram_mcast_qos_.get_handle (); +} + +// Handle the QoS Event. In this case send data to the receiver +// using WSASendTo() that uses overlapped I/O. + +int +Sender_QoS_Event_Handler::handle_qos (ACE_HANDLE) +{ + ACE_DEBUG ((LM_DEBUG, + "\nReceived a QOS event. Inside handle_qos ()\n")); + + // We have received an RSVP event. The following update_qos () call + // calls rapi_dispatch () in case of RAPI and WSAIoctl (GET_QOS) in + // case of W2K. It then does the QoS parameter translation and updates + // the QoS session object with the latest QoS. This call replaces the + // direct call that was being made to WSAIoctl (GET_QOS) here for the + // Win2K example. + + if (this->qos_session_->update_qos () == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "Error in updating QoS\n"), + -1); + else + ACE_DEBUG ((LM_DEBUG, + " Updating QOS succeeds.\n")); + + // Now proactively query the QoS object for QoS. + ACE_QoS ace_get_qos = this->qos_session_->qos (); + + ACE_DEBUG ((LM_DEBUG, + "\nReceiving Flowspec :\t\t\tSending Flowspec :\n\n" + "\tToken Rate = %d\t\t\tToken Rate = %d\n" + "\tToken Bucket Size = %d\t\t\tToken Bucket Size = %d\n" + "\tPeak Bandwidth = %d\t\t\tPeak Bandwidth = %d\n" + "\tLatency = %d\t\t\t\tLatency = %d\n" + "\tDelay Variation = %d\t\t\tDelay Variation = %d\n" + "\tService Type = %d\t\t\tService Type = %d\n" + "\tMax SDU Size = %d\t\t\tMax SDU Size = %d\n" + "\tMinimum Policed Size = %d\t\tMinimum Policed Size = %d\n\n", + ace_get_qos.receiving_flowspec ()->token_rate (), + ace_get_qos.sending_flowspec ()->token_rate (), + ace_get_qos.receiving_flowspec ()->token_bucket_size (), + ace_get_qos.sending_flowspec ()->token_bucket_size (), + ace_get_qos.receiving_flowspec ()->peak_bandwidth (), + ace_get_qos.sending_flowspec ()->peak_bandwidth (), + ace_get_qos.receiving_flowspec ()->latency (), + ace_get_qos.sending_flowspec ()->latency (), + ace_get_qos.receiving_flowspec ()->delay_variation (), + ace_get_qos.sending_flowspec ()->delay_variation (), + ace_get_qos.receiving_flowspec ()->service_type (), + ace_get_qos.sending_flowspec ()->service_type (), + ace_get_qos.receiving_flowspec ()->max_sdu_size (), + ace_get_qos.sending_flowspec ()->max_sdu_size (), + ace_get_qos.receiving_flowspec ()->minimum_policed_size (), + ace_get_qos.sending_flowspec ()->minimum_policed_size ())); + + // This is SPECIFIC TO WIN2K and should be done in the qos_update function. + +// ACE_QoS ace_get_qos; +// u_long dwBytes; + +// if (ACE_OS::ioctl (this->dgram_mcast_qos_.get_handle (), +// ACE_SIO_GET_QOS, +// ace_get_qos, +// &dwBytes) == -1) +// ACE_ERROR ((LM_ERROR, +// "Error in Qos get ACE_OS::ioctl ()\n" +// "Bytes Returned = %d\n", +// dwBytes)); +// else +// ACE_DEBUG ((LM_DEBUG, +// "Getting QOS using ACE_OS::ioctl () succeeds.\n")); + + char* msg = "Hello sent on a QoS enabled session !!\n"; + iovec iov[1]; + iov[0].iov_base = msg; + iov[0].iov_len = ACE_OS::strlen(msg); + + size_t bytes_sent = 0; + + // Send "Hello" to the QoS session address to which the receiver has + // subscribed. + if (this->dgram_mcast_qos_.send (iov, + 1, + bytes_sent, + 0, + this->qos_session_->dest_addr (), + 0, + 0) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "Error in dgram_mcast.send ()\n"), + -1); + else + ACE_DEBUG ((LM_DEBUG, + "Using ACE_OS::sendto () : Bytes sent : %d", + bytes_sent)); + + return 0; +} diff --git a/ACE/examples/QOS/Change_Receiver_FlowSpec/Sender_QoS_Event_Handler.h b/ACE/examples/QOS/Change_Receiver_FlowSpec/Sender_QoS_Event_Handler.h new file mode 100644 index 00000000000..b691bbd0615 --- /dev/null +++ b/ACE/examples/QOS/Change_Receiver_FlowSpec/Sender_QoS_Event_Handler.h @@ -0,0 +1,61 @@ +/* -*- C++ -*- */ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// ACE_wrappers/examples/QOS +// +// = FILENAME +// Sender_QoS_Event_Handler.h +// +// = AUTHOR +// Vishal Kachroo <vishal@cs.wustl.edu> +// +// ============================================================================ + +#ifndef SENDER_QOS_EVENT_HANDLER_H +#define SENDER_QOS_EVENT_HANDLER_H + +#include "ace/Event_Handler.h" +#include "ace/Reactor.h" +#include "ace/INET_Addr.h" +#include "ace/QoS/SOCK_Dgram_Mcast_QoS.h" +#include "ace/QoS/QoS_Session.h" + +//#define MY_DEFPORT 5001 +//#define DEFAULT_MULTICASTGROUP "234.5.6.7" + +ACE_RCSID(Sender_QoS_Event_Handler, Sender_QoS_Event_Handler, "$Id$") + +class Sender_QoS_Event_Handler : public ACE_Event_Handler +{ +public: + // = Initialization and Termination methods. + Sender_QoS_Event_Handler (void); + // Constructor. + + Sender_QoS_Event_Handler::Sender_QoS_Event_Handler (const ACE_SOCK_Dgram_Mcast_QoS + &dgram_mcast_qos, + ACE_QoS_Session *qos_session + ); + // Constructor. + + ~Sender_QoS_Event_Handler (void); + // Destructor. + + virtual ACE_HANDLE get_handle (void) const; + // Override this to return the handle of the Dgram_Mcast + // that we are using. + + virtual int handle_qos (ACE_HANDLE fd); + // Handles a QoS event. Right now, just + // prints a message. + +private: + + ACE_SOCK_Dgram_Mcast_QoS dgram_mcast_qos_; + ACE_QoS_Session *qos_session_; +}; + +#endif /* SENDER_QOS_EVENT_HANDLER_H */ diff --git a/ACE/examples/QOS/Change_Receiver_FlowSpec/receiver.cpp b/ACE/examples/QOS/Change_Receiver_FlowSpec/receiver.cpp new file mode 100644 index 00000000000..8ef43514e9b --- /dev/null +++ b/ACE/examples/QOS/Change_Receiver_FlowSpec/receiver.cpp @@ -0,0 +1,300 @@ +/* -*- C++ -*- */ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// ACE_wrappers/examples/QOS +// +// = FILENAME +// server.cpp +// +// = AUTHOR +// Vishal Kachroo <vishal@cs.wustl.edu> +// +// ============================================================================ + +#define QOSEVENT_MAIN + +#include "ace/QoS/QoS_Session.h" +#include "ace/QoS/QoS_Session_Factory.h" +#include "ace/QoS/QoS_Decorator.h" +#include "ace/QoS/SOCK_Dgram_Mcast_QoS.h" + +#include "QoS_Util.h" +#include "Fill_ACE_QoS.h" +#include "QoS_Signal_Handler.h" +#include "Receiver_QoS_Event_Handler.h" + +// To open QOS sockets administrative access is required on the +// machine. Fill in default values for QoS structure. The default +// values were simply choosen from existing QOS templates available +// via WSAGetQosByName. Notice that ProviderSpecific settings are +// being allowed when picking the "default" template but not for +// "well-known" QOS templates. Also notice that since data is only +// flowing from sender to receiver, different flowspecs are filled in +// depending upon whether this application is acting as a sender or +// receiver. + + +// This function fills up the ACE_QoS_Params with the supplied iovec +// and ACE_QoS. + +int +FillQoSParams (ACE_QoS_Params &qos_params, + iovec* iov, + ACE_QoS* qos) +{ + qos_params.callee_data (iov); + qos_params.caller_data (0); + qos_params.socket_qos (qos); + qos_params.group_socket_qos (0); + qos_params.flags (ACE_JL_BOTH); + + return 0; +} + +int +ACE_TMAIN (int argc, ACE_TCHAR * argv[]) +{ + + QoS_Util qos_util(argc, argv); + + if (qos_util.parse_args () == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "Error in parsing args\n"), + -1); + + // This is a multicast application. + if (qos_util.multicast_flag ()) + { + Fill_ACE_QoS fill_ace_qos; + + // The application adds the flow specs that it wants into the + // Fill_ACE_QoS. The Fill_ACE_QoS indexes the flow specs by the + // flow spec names. Here the new flowspec being added is g_711. + ACE_CString g_711 ("g_711"); + + switch (fill_ace_qos.map ().bind (g_711, + new ACE_Flow_Spec (9200, + 708, + 18400, + 0, + 0, + ACE_SERVICETYPE_CONTROLLEDLOAD, + 368, + 368, + 25, + 1))) + { + case 1 : + ACE_ERROR_RETURN ((LM_ERROR, + "Unable to bind the new flow spec\n" + "The Flow Spec name already exists\n"), + -1); + break; + case -1 : + ACE_ERROR_RETURN ((LM_ERROR, + "Unable to bind the new flow spec\n"), + -1); + break; + } + + ACE_DEBUG ((LM_DEBUG, + "g_711 Flow Spec bound successfully\n")); + + // This is a receiver. So we fill in the receiving QoS parameters. + ACE_QoS ace_qos_receiver; + if (fill_ace_qos.fill_simplex_receiver_qos (ace_qos_receiver, + g_711) !=0) + ACE_ERROR_RETURN ((LM_ERROR, + "Unable to fill simplex receiver qos\n"), + -1); + else + ACE_DEBUG ((LM_DEBUG, + "Filled up the Receiver QoS parameters\n")); + + // Opening a new Multicast Datagram. + ACE_SOCK_Dgram_Mcast_QoS dgram_mcast_qos; + + // Multicast Session Address specified by user at command line. + // If this address is not specified, + // <localhost:ACE_DEFAULT_MULTICAST_PORT> is assumed. + ACE_INET_Addr mult_addr (*(qos_util.mult_session_addr ())); + + // Fill the ACE_QoS_Params to be passed to the <ACE_OS::join_leaf> + // through subscribe. + + ACE_QoS_Params qos_params; + FillQoSParams (qos_params, 0, &ace_qos_receiver); + + // Create a QoS Session Factory. + ACE_QoS_Session_Factory session_factory; + + // Ask the factory to create a QoS session. + ACE_QoS_Session *qos_session = + session_factory.create_session (); + + // Create a destination address for the QoS session. The same + // address should be used for the subscribe call later. A copy + // is made below only to distinguish the two usages of the dest + // address. + + ACE_INET_Addr dest_addr (mult_addr); + + // A QoS session is defined by the 3-tuple [DestAddr, DestPort, + // Protocol]. Initialize the QoS session. + if (qos_session->open (mult_addr, + IPPROTO_UDP) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "Error in opening the QoS session\n"), + -1); + else + ACE_DEBUG ((LM_DEBUG, + "QoS session opened successfully\n")); + + // The following call opens the Dgram_Mcast and calls the + // <ACE_OS::join_leaf> with the qos_params supplied here. Note + // the QoS session object is passed into this call. This + // subscribes the underlying socket to the passed in QoS + // session. For joining multiple multicast sessions, the + // following subscribe call should be made with different + // multicast addresses and a new QoS session object should be + // passed in for each such call. The QoS session objects can be + // created only through the session factory. Care should be + // taken that the mult_addr for the subscribe() call matches the + // dest_addr of the QoS session object. If this is not done, the + // subscribe call will fail. A more abstract version of + // subscribe will be added that constrains the various features + // of GQoS like different flags etc. + + if (dgram_mcast_qos.subscribe (mult_addr, + qos_params, + 1, + 0, + AF_INET, + // ACE_FROM_PROTOCOL_INFO, + 0, + 0, // ACE_Protocol_Info, + 0, + ACE_OVERLAPPED_SOCKET_FLAG + | ACE_FLAG_MULTIPOINT_C_LEAF + | ACE_FLAG_MULTIPOINT_D_LEAF, + qos_session) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "Error in subscribe\n"), + -1); + else + ACE_DEBUG ((LM_DEBUG, + "Dgram_Mcast subscribe succeeds \n")); + + int nIP_TTL = 25; + char achInBuf [BUFSIZ]; + u_long dwBytes; + + // Should this be abstracted into QoS objects ?? Doesnt seem to have + // to do anything directly with QoS. + if (ACE_OS::ioctl (dgram_mcast_qos.get_handle (), // Socket. + ACE_SIO_MULTICAST_SCOPE, // IO control code. + &nIP_TTL, // In buffer. + sizeof (nIP_TTL), // Length of in buffer. + achInBuf, // Out buffer. + BUFSIZ, // Length of Out buffer. + &dwBytes, // bytes returned. + 0, // Overlapped. + 0) == -1) // Func. + ACE_ERROR ((LM_ERROR, + "Error in Multicast scope ACE_OS::ioctl() \n")); + else + ACE_DEBUG ((LM_DEBUG, + "Setting TTL with Multicast scope ACE_OS::ioctl call succeeds \n")); + + int bFlag = 0; + + // Should this be abstracted into QoS objects ?? Doesnt seem to have + // to do anything directly with QoS. + if (ACE_OS::ioctl (dgram_mcast_qos.get_handle (), // Socket. + ACE_SIO_MULTIPOINT_LOOPBACK, // IO control code. + &bFlag, // In buffer. + sizeof (bFlag), // Length of in buffer. + achInBuf, // Out buffer. + BUFSIZ, // Length of Out buffer. + &dwBytes, // bytes returned. + 0, // Overlapped. + 0) == -1) // Func. + ACE_ERROR ((LM_ERROR, + "Error in Loopback ACE_OS::ioctl() \n")); + else + ACE_DEBUG ((LM_DEBUG, + "Disable Loopback with ACE_OS::ioctl call succeeds \n")); + + // This is a receiver. + qos_session->flags (ACE_QoS_Session::ACE_QOS_RECEIVER); + + ACE_QoS_Manager qos_manager = dgram_mcast_qos.qos_manager (); + + // Set the QoS for the session. Replaces the ioctl () call that + // was being made previously. + if (qos_session->qos (&dgram_mcast_qos, + &qos_manager, + ace_qos_receiver) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "Unable to set QoS\n"), + -1); + else + ACE_DEBUG ((LM_DEBUG, + "Setting QOS succeeds.\n")); + + // Register a signal handler that helps to gracefully close the + // open QoS sessions. + QoS_Signal_Handler qos_signal_handler (qos_session); + + // Register the usual SIGINT signal handler with the Reactor for + // the application to gracefully release the QoS session and + // shutdown. + if (ACE_Reactor::instance ()->register_handler + (SIGINT, &qos_signal_handler) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "Error in registering the Signal Handler.\n"), + -1); + + // Handler to process QoS and Data events for the reciever. + Receiver_QoS_Event_Handler qos_event_handler (dgram_mcast_qos, + qos_session); + + // Decorate the above handler with QoS functionality. + ACE_QoS_Decorator qos_decorator (&qos_event_handler, + qos_session); + + // Initialize the Decorator. + if (qos_decorator.init () != 0) + ACE_ERROR_RETURN ((LM_ERROR, + "QoS Decorator init () failed.\n"), + -1); + + // Register the decorated Event Handler with the Reactor. + if (ACE_Reactor::instance ()->register_handler (&qos_decorator, + ACE_Event_Handler::QOS_MASK | + ACE_Event_Handler::READ_MASK) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "Error in registering the Decorator with the Reactor\n"), + -1); + + + // Start the event loop. + ACE_DEBUG ((LM_DEBUG, + "Running the Event Loop ... \n")); + + ACE_Reactor::instance ()->run_event_loop (); + + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) shutting down server logging daemon\n")); + } + else + ACE_DEBUG ((LM_DEBUG, + "Specify a -m option for multicast application\n")); + return 0; +} + + + diff --git a/ACE/examples/QOS/Change_Receiver_FlowSpec/sender.cpp b/ACE/examples/QOS/Change_Receiver_FlowSpec/sender.cpp new file mode 100644 index 00000000000..c721aa810c4 --- /dev/null +++ b/ACE/examples/QOS/Change_Receiver_FlowSpec/sender.cpp @@ -0,0 +1,316 @@ +/* -*- C++ -*- */ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// ACE_wrappers/examples/QOS +// +// = FILENAME +// client.cpp +// +// = AUTHOR +// Vishal Kachroo <vishal@cs.wustl.edu> +// +// ============================================================================ + + +#include "ace/QoS/QoS_Session.h" +#include "ace/QoS/QoS_Session_Factory.h" +#include "ace/QoS/QoS_Session_Impl.h" +#include "ace/QoS/QoS_Decorator.h" +#include "ace/QoS/SOCK_Dgram_Mcast_QoS.h" + +#include "QoS_Util.h" +#include "Fill_ACE_QoS.h" +#include "QoS_Signal_Handler.h" +#include "Sender_QoS_Event_Handler.h" + +// To open QOS sockets administrative access is required on the +// machine. Fill in default values for QoS structure. The default +// values were simply choosen from existing QOS templates available +// via WSAGetQosByName. Notice that ProviderSpecific settings are +// being allowed when picking the "default" template but not for +// "well-known" QOS templates. Also notice that since data is only +// flowing from sender to receiver, different flowspecs are filled in +// depending upon whether this application is acting as a sender or +// receiver. + +// This function fills up the ACE_QoS_Params with the supplied iovec and ACE_QoS. + +int +FillQoSParams (ACE_QoS_Params &qos_params, + iovec* iov, + ACE_QoS* qos) +{ + qos_params.callee_data (iov); + qos_params.caller_data (0); + qos_params.socket_qos (qos); + qos_params.group_socket_qos (0); + qos_params.flags (ACE_JL_BOTH); + + return 0; +} + +int +ACE_TMAIN (int argc, ACE_TCHAR * argv[]) +{ + + ACE_DEBUG ((LM_DEBUG, + "Sender\n")); + + QoS_Util qos_util(argc, argv); + + if (qos_util.parse_args () == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "Error in parsing args\n"), + -1); + + // This is a multicast application. + if (qos_util.multicast_flag ()) + { + Fill_ACE_QoS fill_ace_qos; + + // The application adds the flow specs that it wants into the + // Fill_ACE_QoS. The Fill_ACE_QoS indexes the flow specs by the flow + // spec names. Here the new flowspec being added is g_711. + ACE_CString g_711 ("g_711"); + + switch (fill_ace_qos.map ().bind (g_711, + new ACE_Flow_Spec (9200, + 708, + 18400, + 0, + 0, + ACE_SERVICETYPE_CONTROLLEDLOAD, + 368, + 368, + 25, + 1))) + { + case 1 : + ACE_ERROR_RETURN ((LM_ERROR, + "Unable to bind the new flow spec\n" + "The Flow Spec name already exists\n"), + -1); + break; + case -1 : + ACE_ERROR_RETURN ((LM_ERROR, + "Unable to bind the new flow spec\n"), + -1); + break; + } + + ACE_DEBUG ((LM_DEBUG, + "g_711 Flow Spec bound successfully\n")); + + // This is a sender. So we fill in the sending QoS parameters. + ACE_QoS ace_qos_sender; + + if (fill_ace_qos.fill_simplex_sender_qos (ace_qos_sender, + g_711) !=0) + ACE_ERROR_RETURN ((LM_ERROR, + "Unable to fill simplex sender qos\n"), + -1); + else + ACE_DEBUG ((LM_DEBUG, + "Filled up the Sender QoS parameters\n")); + + // Opening a new Multicast Datagram. It is absolutely necessary that + // the sender and the receiver subscribe to the same multicast + // addresses to make sure the "multicast sessions" for the two are + // the same. This is used to match the RESV<->PATH states. + ACE_SOCK_Dgram_Mcast_QoS dgram_mcast_qos; + + // Multicast Session Address specified by user at command line. + // If this address is not specified, + // <localhost:ACE_DEFAULT_MULTICAST_PORT> is assumed. + ACE_INET_Addr mult_addr (*(qos_util.mult_session_addr ())); + + // Fill the ACE_QoS_Params to be passed to the <ACE_OS::join_leaf> + // through subscribe. + + ACE_QoS_Params qos_params; + FillQoSParams (qos_params, 0, &ace_qos_sender); + + // Create a QoS Session Factory. + ACE_QoS_Session_Factory session_factory; + + // Ask the factory to create a QoS session. + ACE_QoS_Session *qos_session = + session_factory.create_session (); + + // Create a destination address for the QoS session. The same + // address should be used for the subscribe call later. A copy is + // made below only to distinguish the two usages of the dest + // address. + + ACE_INET_Addr dest_addr (mult_addr); + + // A QoS session is defined by the 3-tuple [DestAddr, DestPort, + // Protocol]. Initialize the QoS session. + if (qos_session->open (mult_addr, + IPPROTO_UDP) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "Error in opening the QoS session\n"), + -1); + else + ACE_DEBUG ((LM_DEBUG, + "QoS session opened successfully\n")); + + // The following call opens the Dgram_Mcast and calls the + // <ACE_OS::join_leaf> with the qos_params supplied here. Note the + // QoS session object is passed into this call. This subscribes the + // underlying socket to the passed in QoS session. For joining + // multiple multicast sessions, the following subscribe call should + // be made with different multicast addresses and a new QoS session + // object should be passed in for each such call. The QoS session + // objects can be created only through the session factory. Care + // should be taken that the mult_addr for the subscribe() call + // matches the dest_addr of the QoS session object. If this is not + // done, the subscribe call will fail. A more abstract version of + // subscribe will be added that constrains the various features of + // GQoS like different flags etc. + + if (dgram_mcast_qos.subscribe (mult_addr, + qos_params, + 1, + 0, + AF_INET, + // ACE_FROM_PROTOCOL_INFO, + 0, + 0, // ACE_Protocol_Info, + 0, + ACE_OVERLAPPED_SOCKET_FLAG + | ACE_FLAG_MULTIPOINT_C_LEAF + | ACE_FLAG_MULTIPOINT_D_LEAF, + qos_session) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "Error in subscribe\n"), + -1); + else + ACE_DEBUG ((LM_DEBUG, + "Dgram_Mcast subscribe succeeds \n")); + + int nIP_TTL = 25; + char achInBuf [BUFSIZ]; + u_long dwBytes; + + // Should this be abstracted into QoS objects ?? Doesnt seem to have + // to do anything directly with QoS. + if (ACE_OS::ioctl (dgram_mcast_qos.get_handle (), // Socket. + ACE_SIO_MULTICAST_SCOPE, // IO control code. + &nIP_TTL, // In buffer. + sizeof (nIP_TTL), // Length of in buffer. + achInBuf, // Out buffer. + BUFSIZ, // Length of Out buffer. + &dwBytes, // bytes returned. + 0, // Overlapped. + 0) == -1) // Func. + ACE_ERROR ((LM_ERROR, + "Error in Multicast scope ACE_OS::ioctl() \n")); + else + ACE_DEBUG ((LM_DEBUG, + "Setting TTL with Multicast scope ACE_OS::ioctl call succeeds \n")); + + int bFlag = 0; + + // Should this be abstracted into QoS objects ?? Doesnt seem to have + // to do anything directly with QoS. + if (ACE_OS::ioctl (dgram_mcast_qos.get_handle (), // Socket. + ACE_SIO_MULTIPOINT_LOOPBACK, // IO control code. + &bFlag, // In buffer. + sizeof (bFlag), // Length of in buffer. + achInBuf, // Out buffer. + BUFSIZ, // Length of Out buffer. + &dwBytes, // bytes returned. + 0, // Overlapped. + 0) == -1) // Func. + ACE_ERROR ((LM_ERROR, + "Error in Loopback ACE_OS::ioctl() \n")); + else + ACE_DEBUG ((LM_DEBUG, + "Disable Loopback with ACE_OS::ioctl call succeeds \n")); + + // This is a sender. + qos_session->flags (ACE_QoS_Session::ACE_QOS_SENDER); + + ACE_QoS_Manager qos_manager = dgram_mcast_qos.qos_manager (); + + // Since we are using RSVP, it is imperative that the client + // application have the option of supplying the source sender + // port for the RSVP messages. A default will be chosen by the + // ACE API if this is not done. + qos_session->source_port (qos_util.source_port ()); + + // Set the QoS for the session. Replaces the ioctl () call that + // was being made previously. + if (qos_session->qos (&dgram_mcast_qos, + &qos_manager, + ace_qos_sender) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "Unable to set QoS\n"), + -1); + else + ACE_DEBUG ((LM_DEBUG, + "Setting QOS succeeds.\n")); + + // Register a signal handler that helps to gracefully close the open + // QoS sessions. + QoS_Signal_Handler qos_signal_handler (qos_session); + + // Register the usual SIGINT signal handler with the Reactor for + // the application to gracefully release the QoS session and + // shutdown. + if (ACE_Reactor::instance ()->register_handler + (SIGINT, &qos_signal_handler) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "Error in registering the Signal Handler.\n"), + -1); + + // Handler to process QoS and Data events for the reciever. + Sender_QoS_Event_Handler qos_event_handler (dgram_mcast_qos, + qos_session); + + // Decorate the above handler with QoS functionality. + ACE_QoS_Decorator qos_decorator (&qos_event_handler, + qos_session); + + // Initialize the Decorator. + if (qos_decorator.init () != 0) + ACE_ERROR_RETURN ((LM_ERROR, + "QoS Decorator init () failed.\n"), + -1); + + // Register the decorated Event Handler with the Reactor. + if (ACE_Reactor::instance ()->register_handler (&qos_decorator, + ACE_Event_Handler::QOS_MASK | + ACE_Event_Handler::READ_MASK) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "Error in registering the Decorator with the Reactor\n"), + -1); + + + + + // Start the event loop. + ACE_DEBUG ((LM_DEBUG, + "Running the Event Loop ... \n")); + + ACE_Reactor::instance ()->run_event_loop (); + + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) shutting down server logging daemon\n")); + } + else + ACE_DEBUG ((LM_DEBUG, + "Specify a -m option for multicast application\n")); + return 0; +} + + + + + + + diff --git a/ACE/examples/QOS/Change_Sender_TSpec/Fill_ACE_QoS.cpp b/ACE/examples/QOS/Change_Sender_TSpec/Fill_ACE_QoS.cpp new file mode 100644 index 00000000000..20c03f40fa6 --- /dev/null +++ b/ACE/examples/QOS/Change_Sender_TSpec/Fill_ACE_QoS.cpp @@ -0,0 +1,99 @@ +// Fill_ACE_QoS.cpp +// $Id$ + +#include "Fill_ACE_QoS.h" + +ACE_RCSID(QOS, Fill_ACE_QoS,"$Id$") + +const iovec Fill_ACE_QoS::iov_ = {0,0}; + +Fill_ACE_QoS::Fill_ACE_QoS (void) +{ + ACE_NEW (this->default_traffic_, + ACE_Flow_Spec (ACE_QOS_NOT_SPECIFIED, + ACE_QOS_NOT_SPECIFIED, + ACE_QOS_NOT_SPECIFIED, + ACE_QOS_NOT_SPECIFIED, + ACE_QOS_NOT_SPECIFIED, + ACE_SERVICETYPE_NOTRAFFIC, + ACE_QOS_NOT_SPECIFIED, + ACE_QOS_NOT_SPECIFIED, + 25, + 1)); +} + +// destructor. +Fill_ACE_QoS::~Fill_ACE_QoS (void) +{} + +int +Fill_ACE_QoS::fill_simplex_receiver_qos (ACE_QoS &ace_qos, + const ACE_CString &recv_flow_name) +{ + ACE_Flow_Spec *recv_flow_spec = 0; + + if (this->map ().find (recv_flow_name, recv_flow_spec) != 0) + ACE_ERROR_RETURN ((LM_DEBUG, + "Unable to find a FlowSpec with name %s", + recv_flow_name.c_str ()), + -1); + ace_qos.receiving_flowspec (recv_flow_spec); + ace_qos.sending_flowspec ((this->default_traffic_)); + ace_qos.provider_specific (Fill_ACE_QoS::iov_); + + return 0; +} + + +int +Fill_ACE_QoS::fill_simplex_sender_qos (ACE_QoS &ace_qos, + const ACE_CString &send_flow_name) +{ + ACE_Flow_Spec *send_flow_spec = 0; + + if (this->map ().find (send_flow_name, send_flow_spec) != 0) + ACE_ERROR_RETURN ((LM_DEBUG, + "Unable to find a FlowSpec with name %s", + send_flow_name.c_str ()), + -1); + + ace_qos.receiving_flowspec ((this->default_traffic_)); + ace_qos.sending_flowspec (send_flow_spec); + ace_qos.provider_specific (Fill_ACE_QoS::iov_); + + return 0; +} + +int +Fill_ACE_QoS::fill_duplex_qos (ACE_QoS &ace_qos, + const ACE_CString &recv_flow_name, + const ACE_CString &send_flow_name) +{ + ACE_Flow_Spec *send_flow_spec = 0; + ACE_Flow_Spec *recv_flow_spec = 0; + + if (this->map ().find (recv_flow_name, recv_flow_spec) != 0) + ACE_ERROR_RETURN ((LM_DEBUG, + "Unable to find a FlowSpec with name %s", + recv_flow_name.c_str ()), + -1); + + if (this->map ().find (send_flow_name, send_flow_spec) != 0) + ACE_ERROR_RETURN ((LM_DEBUG, + "Unable to find a FlowSpec with name %s", + send_flow_name.c_str ()), + -1); + + ace_qos.receiving_flowspec (recv_flow_spec); + ace_qos.sending_flowspec (send_flow_spec); + ace_qos.provider_specific (Fill_ACE_QoS::iov_); + + return 0; +} + +Fill_ACE_QoS::FLOW_SPEC_HASH_MAP& +Fill_ACE_QoS::map (void) +{ + return this->flow_spec_map_; +} + diff --git a/ACE/examples/QOS/Change_Sender_TSpec/Fill_ACE_QoS.h b/ACE/examples/QOS/Change_Sender_TSpec/Fill_ACE_QoS.h new file mode 100644 index 00000000000..776d713e5e5 --- /dev/null +++ b/ACE/examples/QOS/Change_Sender_TSpec/Fill_ACE_QoS.h @@ -0,0 +1,75 @@ +/* -*- C++ -*- */ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// ACE_wrappers/examples/QOS +// +// = FILENAME +// Fill_ACE_QoS.h +// +// = AUTHOR +// Vishal Kachroo <vishal@cs.wustl.edu> +// +// ============================================================================ + +#ifndef FILL_ACE_QOS_H +#define FILL_ACE_QOS_H + +#include "ace/SString.h" +#include "ace/Hash_Map_Manager.h" +#include "ace/Null_Mutex.h" +#include "ace/ACE.h" +#include "ace/OS_QoS.h" + +class Fill_ACE_QoS +{ + // TITLE + // This class helps users to add new flow specs and provides + // utility functions for filling up the flow specs for simplex/duplex + // sessions. + +public: + typedef ACE_Hash_Map_Manager <ACE_CString, ACE_Flow_Spec *, ACE_Null_Mutex> FLOW_SPEC_HASH_MAP; + + //Initialization and termination methods. + Fill_ACE_QoS (void); + // constructor. + + ~Fill_ACE_QoS (void); + // destructor. + + int fill_simplex_receiver_qos (ACE_QoS &ace_qos, + const ACE_CString &recv_flow_name); + // To be used by receivers. Fills the receiver qos and sets the + // sender qos to NO_TRAFFIC. + + int fill_simplex_sender_qos (ACE_QoS &ace_qos, + const ACE_CString &send_flow_name); + // To be used by senders. Fills the sender qos and sets the receiver + // qos to NO_TRAFFIC. + + int fill_duplex_qos (ACE_QoS &ace_qos, + const ACE_CString &recv_flow_name, + const ACE_CString &send_flow_name); + // To be used by applications that wish to be both receivers and + // senders. + + FLOW_SPEC_HASH_MAP& map (void); + // Returns the hash map of flowspecs indexed by flowspec name. + +private: + + // The Service Provider is currently set to NULL for all ACE_QoS. + static const iovec iov_; + + // A NO_TRAFFIC flow spec. Senders set the receiving qos to this + // while the receivers set the sending qos to this. + ACE_Flow_Spec *default_traffic_; + + // A list of flowspecs indexed by the flowspec name. + FLOW_SPEC_HASH_MAP flow_spec_map_; +}; + +#endif /* FILL_ACE_QOS_H */ diff --git a/ACE/examples/QOS/Change_Sender_TSpec/FlowSpec_Dbase.h b/ACE/examples/QOS/Change_Sender_TSpec/FlowSpec_Dbase.h new file mode 100644 index 00000000000..fc382048c13 --- /dev/null +++ b/ACE/examples/QOS/Change_Sender_TSpec/FlowSpec_Dbase.h @@ -0,0 +1,52 @@ +/* -*- C++ -*- */ +//$Id$ + +// ============================================================================ +// +// = LIBRARY +// ACE_wrappers/examples/QOS +// +// = FILENAME +// FlowSpec_Dbase.h +// +// = AUTHOR +// Vishal Kachroo <vishal@cs.wustl.edu> +// +// ============================================================================ + +#ifndef FLOWSPEC_DBASE_H +#define FLOWSPEC_DBASE_H + +// This file contains the different FlowSpecs that the QoS enabled +// application uses. Its a good idea to list them all here so the +// application code is clean. + +ACE_Flow_Spec notraffic (ACE_QOS_NOT_SPECIFIED, + ACE_QOS_NOT_SPECIFIED, + ACE_QOS_NOT_SPECIFIED, + ACE_QOS_NOT_SPECIFIED, + ACE_QOS_NOT_SPECIFIED, + ACE_SERVICETYPE_NOTRAFFIC, + ACE_QOS_NOT_SPECIFIED, + ACE_QOS_NOT_SPECIFIED, + 25, + 1); + +ACE_Flow_Spec g711 (9200, + 708, + 18400, + 0, + 0, + ACE_SERVICETYPE_CONTROLLEDLOAD, + 368, + 368, + 25, + 1); + +// The default session address is macarena.cs.wustl.edu. I am using macarena +// as my receiver for testing. +#define DEFAULT_QOS_SESSION_MACHINE "128.252.165.127" +#define DEFAULT_QOS_SESSION_PORT 8001 + +#endif /* FLOWSPEC_DBASE_H */ + diff --git a/ACE/examples/QOS/Change_Sender_TSpec/Makefile.am b/ACE/examples/QOS/Change_Sender_TSpec/Makefile.am new file mode 100644 index 00000000000..980d5cf3422 --- /dev/null +++ b/ACE/examples/QOS/Change_Sender_TSpec/Makefile.am @@ -0,0 +1,76 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +ACE_BUILDDIR = $(top_builddir) +ACE_ROOT = $(top_srcdir) + +noinst_PROGRAMS = + +## Makefile.QOS_Change_Sender_TSpec_Receiver.am + +if BUILD_QOS +noinst_PROGRAMS += receiver + +receiver_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) \ + -DACE_HAS_QOS + +receiver_SOURCES = \ + Fill_ACE_QoS.cpp \ + QoS_Signal_Handler.cpp \ + QoS_Util.cpp \ + Receiver_QoS_Event_Handler.cpp \ + receiver.cpp \ + Fill_ACE_QoS.h \ + QoS_Signal_Handler.h \ + QoS_Util.h \ + Receiver_QoS_Event_Handler.h + +receiver_LDADD = \ + $(ACE_BUILDDIR)/ace/QoS/libACE_QoS.la \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif BUILD_QOS + +## Makefile.QOS_Change_Sender_TSpec_Sender.am + +if BUILD_QOS +noinst_PROGRAMS += sender + +sender_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) \ + -DACE_HAS_QOS + +sender_SOURCES = \ + Fill_ACE_QoS.cpp \ + QoS_Signal_Handler.cpp \ + QoS_Util.cpp \ + Sender_QoS_Event_Handler.cpp \ + sender.cpp \ + Fill_ACE_QoS.h \ + QoS_Signal_Handler.h \ + QoS_Util.h \ + Sender_QoS_Event_Handler.h + +sender_LDADD = \ + $(ACE_BUILDDIR)/ace/QoS/libACE_QoS.la \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif BUILD_QOS + +## Clean up template repositories, etc. +clean-local: + -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.* + -rm -f gcctemp.c gcctemp so_locations *.ics + -rm -rf cxx_repository ptrepository ti_files + -rm -rf templateregistry ir.out + -rm -rf ptrepository SunWS_cache Templates.DB diff --git a/ACE/examples/QOS/Change_Sender_TSpec/QOS_Change_Sender_TSpec.mpc b/ACE/examples/QOS/Change_Sender_TSpec/QOS_Change_Sender_TSpec.mpc new file mode 100644 index 00000000000..9767bd6fdb9 --- /dev/null +++ b/ACE/examples/QOS/Change_Sender_TSpec/QOS_Change_Sender_TSpec.mpc @@ -0,0 +1,25 @@ +// -*- MPC -*- +// $Id$ + +project(*receiver) : aceexe, qos { + exename = receiver + requires += qos + Source_Files { + Fill_ACE_QoS.cpp + QoS_Signal_Handler.cpp + QoS_Util.cpp + receiver.cpp + Receiver_QoS_Event_Handler.cpp + } +} +project(*sender) : aceexe, qos { + exename = sender + requires += qos + Source_Files { + Fill_ACE_QoS.cpp + QoS_Signal_Handler.cpp + QoS_Util.cpp + sender.cpp + Sender_QoS_Event_Handler.cpp + } +} diff --git a/ACE/examples/QOS/Change_Sender_TSpec/QoS_Signal_Handler.cpp b/ACE/examples/QOS/Change_Sender_TSpec/QoS_Signal_Handler.cpp new file mode 100644 index 00000000000..9f07ad5b378 --- /dev/null +++ b/ACE/examples/QOS/Change_Sender_TSpec/QoS_Signal_Handler.cpp @@ -0,0 +1,34 @@ +// QoS_Signal_Handler.cpp +// $Id$ + +#include "ace/Log_Msg.h" +#include "QoS_Signal_Handler.h" + +ACE_RCSID(QOS, QoS_Signal_Handler,"$Id$") + +// constructor. +QoS_Signal_Handler::QoS_Signal_Handler (ACE_QoS_Session *qos_session) + : qos_session_ (qos_session) +{ +} + +// Releases the QoS sessions gracefully. +int +QoS_Signal_Handler::handle_signal (int signum, siginfo_t *, ucontext_t*) +{ + if (signum == SIGINT) + { + if (this->qos_session_->close () == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "Unable to close the QoS session.\n"), + -1); + else + ACE_DEBUG ((LM_DEBUG, + "QoS Session with id %d closed successfully.\n", + this->qos_session_->session_id ())); + } + else + ACE_DEBUG ((LM_DEBUG, + "A signal other than SIGINT received.\nIgnoring.\n")); + return 0; +} diff --git a/ACE/examples/QOS/Change_Sender_TSpec/QoS_Signal_Handler.h b/ACE/examples/QOS/Change_Sender_TSpec/QoS_Signal_Handler.h new file mode 100644 index 00000000000..35b9f3a19e7 --- /dev/null +++ b/ACE/examples/QOS/Change_Sender_TSpec/QoS_Signal_Handler.h @@ -0,0 +1,45 @@ +/* -*- C++ -*- */ +// $Id$ + +// ===================================================================== +// +// = LIBRARY +// ACE_wrappers/examples/QOS +// +// = FILENAME +// QoS_Signal_Handler.h +// +// = AUTHOR +// Vishal Kachroo <vishal@cs.wustl.edu> +// +// ===================================================================== + +#ifndef QOS_SIGNAL_HANDLER_H +#define QOS_SIGNAL_HANDLER_H + +#include "ace/Event_Handler.h" +#include "ace/QoS/QoS_Session.h" + +class QoS_Signal_Handler : public ACE_Event_Handler +{ + // TITLE + // This class Handles the SIGINT signal through the Reactor. + // Useful to gracefully release QoS sessions. + +public: + + QoS_Signal_Handler (ACE_QoS_Session *qos_session); + // constructor. + + int handle_signal(int signum, siginfo_t*,ucontext_t*); + // Override this method to implement graceful shutdown. + +private: + + ACE_QoS_Session *qos_session_; + // Session to be gracefully shutdown. + +}; + +#endif /* QOS_SIGNAL_HANDLER_H */ + diff --git a/ACE/examples/QOS/Change_Sender_TSpec/QoS_Util.cpp b/ACE/examples/QOS/Change_Sender_TSpec/QoS_Util.cpp new file mode 100644 index 00000000000..0ef3b353248 --- /dev/null +++ b/ACE/examples/QOS/Change_Sender_TSpec/QoS_Util.cpp @@ -0,0 +1,122 @@ +// QoS_Session_Impl.cpp +// $Id$ + +#define SENDER_PORT 10001 + +#include "ace/Log_Msg.h" +#include "ace/Get_Opt.h" +#include "QoS_Util.h" +#include "ace/OS_NS_strings.h" + +ACE_RCSID(QOS, QoS_Util,"$Id$") + +// constructor. +QoS_Util::QoS_Util (int argc, + ACE_TCHAR *argv[]) + : argc_ (argc), + argv_ (argv), + source_port_ (SENDER_PORT), + protocol_ (IPPROTO_UDP), + multicast_flag_ (0) +{ + ACE_NEW (this->mult_session_addr_, + ACE_INET_Addr (ACE_DEFAULT_MULTICAST_PORT)); + + ACE_NEW (this->dest_addr_, + ACE_INET_Addr (ACE_DEFAULT_SERVER_PORT)); +} + +// destructor. +QoS_Util::~QoS_Util (void) +{ + delete this->mult_session_addr_; + delete this->dest_addr_; +} + +int +QoS_Util::parse_args (void) +{ + ACE_Get_Opt get_opts (this->argc_, this->argv_, ACE_TEXT("m:n:p:P:c")); + int c = 0; + + while ((c = get_opts ()) != -1) + switch (c) + { + case 'm': // multicast session address. + this->multicast_flag_ = 1; + this->mult_session_addr_->set (get_opts.opt_arg ()); + break; + case 'n': // to be used by Senders only to specify the destination. + this->dest_addr_->set (get_opts.opt_arg ()); + break; + case 'p': // protocol. + if (ACE_OS::strcasecmp (get_opts.opt_arg (), ACE_TEXT("tcp")) == 0) + this->protocol_ = IPPROTO_TCP; + else + if (ACE_OS::strcasecmp (get_opts.opt_arg (), ACE_TEXT("udp")) == 0) + this->protocol_ = IPPROTO_UDP; + else + ACE_DEBUG ((LM_DEBUG, + "Unknown protocol specified\n" + "UDP assumed\n")); + break; + case 'P': // sender source port. + this->source_port_ = ACE_OS::atoi (get_opts.opt_arg ()); + break; + case 'h': // display help for different options. + default: + ACE_ERROR_RETURN ((LM_ERROR, + "usage: %s" + " [-m host:port] QoS multicast session address" + " Overides the receiver address specified in the -n option" + " [-n host:port] Use for a unicast sender. " + " Follow by receiver addr" + " [-p tcp|udp] specify protocol to be used" + " [-P port] source sender port" + " [-h] <help>" + "\n", + argv_ [0]), + -1); + } + + // If multicast address is specified then ignore the unicast sender + // destination address and force the protocol to be UDP. + if (this->multicast_flag_ == 1) + { + this->dest_addr_ = this->mult_session_addr_; + this->protocol_ = IPPROTO_UDP; + } + + // Indicates successful parsing of command line. + return 0; +} + +ACE_INET_Addr * +QoS_Util::mult_session_addr (void) const +{ + return this->mult_session_addr_; +} + +ACE_INET_Addr * +QoS_Util::dest_addr (void) const +{ + return this->dest_addr_; +} + +u_short +QoS_Util::source_port (void) const +{ + return this->source_port_; +} + +ACE_Protocol_ID +QoS_Util::protocol (void) const +{ + return this->protocol_; +} + +int +QoS_Util::multicast_flag (void) const +{ + return this->multicast_flag_; +} diff --git a/ACE/examples/QOS/Change_Sender_TSpec/QoS_Util.h b/ACE/examples/QOS/Change_Sender_TSpec/QoS_Util.h new file mode 100644 index 00000000000..ae347de68f6 --- /dev/null +++ b/ACE/examples/QOS/Change_Sender_TSpec/QoS_Util.h @@ -0,0 +1,75 @@ +/* -*- C++ -*- */ +// $Id$ + +// ===================================================================== +// +// = LIBRARY +// ACE_wrappers/examples/QOS +// +// = FILENAME +// QoS_Util.h +// +// = AUTHOR +// Vishal Kachroo <vishal@cs.wustl.edu> +// +// ===================================================================== + +#ifndef QOS_UTIL_H +#define QOS_UTIL_H + +#include "ace/INET_Addr.h" +#include "ace/QoS/QoS_Session.h" + +class QoS_Util +{ + // = TITLE + // This class provides the utility functions like parse_args () + // required by a QoS enabled application. + +public: + + // constructor. + QoS_Util (int argc, ACE_TCHAR *argv[]); + + // destructor. + ~QoS_Util (void); + + // Parse command-line arguments. + int parse_args (void); + + // GET methods. + ACE_INET_Addr *mult_session_addr (void) const; + + ACE_INET_Addr *dest_addr (void) const; + + u_short source_port (void) const; + + ACE_Protocol_ID protocol (void) const; + + int multicast_flag (void) const; + +private: + + // Command line arguments. + int argc_; + ACE_TCHAR **argv_; + + // Multicast session address. + ACE_INET_Addr *mult_session_addr_; + + // Unicast destination address of the receiver. + ACE_INET_Addr *dest_addr_; + + // Source port for the sender. + u_short source_port_; + + // Protocol. + ACE_Protocol_ID protocol_; + + // Multicast Flag. + int multicast_flag_; + +}; + +#endif /* QOS_UTIL_H */ + diff --git a/ACE/examples/QOS/Change_Sender_TSpec/README b/ACE/examples/QOS/Change_Sender_TSpec/README new file mode 100644 index 00000000000..a8423774320 --- /dev/null +++ b/ACE/examples/QOS/Change_Sender_TSpec/README @@ -0,0 +1,126 @@ +$Id$ + +A Regression test for ACE QoS features. +--------------------------------------- + +This test implements a simple Receiver-Sender program that ensures +Quality of Service (QoS) guarantees on the underlying network before +transmitting data. The program tests the ACE QoS APIs/features. The +test works for Winsock2 APIs on Win2K as well as RAPI on Solaris. + +In addition it dynamically changes the sender TSpec which in turn +changes the PATH messages. + +------------------------------------------------------------------------ +WIN2K : + +Build Requirements : +-------------------- +1. Two Win2K machines. +2. June98 Platform SDK or later. +3. Link with ws2_32.lib + +The test consists of a server (which is the receiver) and a client + (which is the sender). + + The receiver is started first (though it is not mandatory) as : + + server -m merengue.cs.wustl.edu:9091 + + -m: specifies the multicast session address that both client and + server subscribe to for QoS events. + + -p: Protocol to be used. Could be udp or tcp. Default is udp. + + -P: Sender source port. If not specified, DEFAULT_SOURCE_SENDER_PORT + (10001) will be used. + + -h: Displays the help on various options. + +The sample Sender is started next as : + + client -m merengue.cs.wustl.edu:9091 -P 10004 + + -m: specifies the multicast session address that both client and + server subscribe to for QoS events. + + -n: Option to be used by senders only to specify the destination + address. This option is overriden if a multicast address is also + specified through the -m option. + + -p: Protocol to be used. Could be udp or tcp. Default is udp. + + -P: Sender source port. If not specified, DEFAULT_SOURCE_SENDER_PORT + (10001) will be used. + + -h: Displays the help on various options. + +On Win2K the user must have administrative access to the machine to +run this program. It seems to be a pre-requisite to opening QoS +sockets. + +The sender and receiver should be run on different Win2K machines. + +The test demonstrates how to GQOS enable an application using the ACE QoS APIs. +It concentrates on the use of various ACE QoS APIs and their correctness. + +------------------------------------------------------------------------------- + +RAPI : + +0. The $ACE_ROOT/include/makeinclude/platform_macros.GNU should be the +following : + +include /project/doc/vishal/ACE_wrappers/include/makeinclude/platform_sunos5_sunc++.GNU +PLATFORM_RAPI_CPPFLAGS += -I/project/doc/vishal/rapi/rel4.2a4/rsvpd/ +PLATFORM_RAPI_LIBS += -lrsvp +PLATFORM_RAPI_LDFLAGS += -L/project/doc/vishal/rapi/rel4.2a4/rsvpd/ + +assuming that RAPI library is installed in /project/doc/vishal/rapi/rel4.2a4/ + +1. Compile ACE with + + make rapi=1 static_libs_only=1 + + Static library option is used because the RAPI library that we have + does not compile as a shared object. + +2. Run the RSVP Daemon on two machines: (merengue.cs and macarena.cs) + + /project/doc/vishal/rapi/rel4.2a4/rsvpd/rsvpd -D + + The current version of the daemon comes with an inbuilt rtap + application to test the various reservation commands and RAPI APIs. + + Typical values for rtap would be : + + sender merengue/5000 [ t 2000000 100000 2000000 512 1024 ] + reserve wf [ cl 4000000 200000 4000000 256 2024 ] + + + + From ACE: + dest udp macarena/5000 + sender ace/5000 [ t 2000000 100000 2000000 512 1024 ] + sender macarena/5022 [ t 2000000 100000 2000000 512 1024 ] + sender beguine/6000 [ t 2000000 100000 2000000 512 1024 ] + + From Macarena: + wait until done with ACE + dest udp macarena/5000 <session name> + reserve wf [ cl 2000000 100000 2000000 512 1024 ] + + + +3. If RTAP runs fine and the daemons show the debug messages about + RESV, PATH and other RSVP messages, run the QoS example, making sure + that rtap session is released on both machines. + +------------------------------------------------------------------------------- + +If you run into any problems with this test please contact Vishal +Kachroo <vishal@cs.wustl.edu>. + +This README last updated on 20th July, 2000. + +------------------------------------------------------------------------------- diff --git a/ACE/examples/QOS/Change_Sender_TSpec/Receiver_QoS_Event_Handler.cpp b/ACE/examples/QOS/Change_Sender_TSpec/Receiver_QoS_Event_Handler.cpp new file mode 100644 index 00000000000..d6ece4d563c --- /dev/null +++ b/ACE/examples/QOS/Change_Sender_TSpec/Receiver_QoS_Event_Handler.cpp @@ -0,0 +1,145 @@ +/* -*- C++ -*- */ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// ACE_wrappers/examples/QOS +// +// = FILENAME +// Receiver_QoS_Event_Handler.cpp +// +// = AUTHOR +// Vishal Kachroo <vishal@cs.wustl.edu> +// +// ============================================================================ + +#include "Receiver_QoS_Event_Handler.h" +#include "ace/Log_Msg.h" +#include "ace/SString.h" +#include "Fill_ACE_QoS.h" + +// Constructor. +Receiver_QoS_Event_Handler::Receiver_QoS_Event_Handler (void) +{ +} + +Receiver_QoS_Event_Handler::Receiver_QoS_Event_Handler (const ACE_SOCK_Dgram_Mcast_QoS + &dgram_mcast_qos, + ACE_QoS_Session *qos_session) + : dgram_mcast_qos_ (dgram_mcast_qos), + qos_session_ (qos_session) +{ +} + +// Destructor. +Receiver_QoS_Event_Handler::~Receiver_QoS_Event_Handler (void) +{ +} + +// Return the handle of the Dgram_Mcast. This method is called +// internally by the reactor. +ACE_HANDLE +Receiver_QoS_Event_Handler::get_handle (void) const +{ + return this->dgram_mcast_qos_.get_handle (); +} + +// Called when there is a READ activity on the dgram_mcast_qos handle. +int +Receiver_QoS_Event_Handler::handle_input (ACE_HANDLE) +{ + char buf[BUFSIZ]; + + iovec iov; + iov.iov_base = buf; + iov.iov_len = BUFSIZ; + + ACE_OS::memset (iov.iov_base, + 0, + BUFSIZ); + + ACE_DEBUG ((LM_DEBUG, + "Inside handle_input () of Receiver_QoS_Event_Handler ()\n")); + + // Receive message from multicast group. + ssize_t result = + this->dgram_mcast_qos_.recv (&iov, + 1, + this->remote_addr_); + + if (result != -1) + { + ACE_DEBUG ((LM_DEBUG, + "Message Received : %s", + iov.iov_base)); + return 0; + } + else + return -1; +} + +// Called when there is a QoS Event. +int +Receiver_QoS_Event_Handler::handle_qos (ACE_HANDLE fd) +{ + ACE_UNUSED_ARG (fd); + + ACE_DEBUG ((LM_DEBUG, + "\nReceived a QOS event. Inside handle_qos ()\n")); + + // We have received an RSVP event. The following update_qos () call + // calls rapi_dispatch () in case of RAPI and WSAIoctl (GET_QOS) in + // case of W2K. It then does the QoS parameter translation and updates + // the QoS session object with the latest QoS. This call replaces the + // direct call that was being made to WSAIoctl (GET_QOS) here for the + // Win2K example. + + if (this->qos_session_->update_qos () == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "Error in updating QoS\n"), + -1); + else + ACE_DEBUG ((LM_DEBUG, + " Updating QOS succeeds.\n")); + + // Now proactively query the QoS object for QoS. + ACE_QoS ace_get_qos = this->qos_session_->qos (); + + ACE_DEBUG ((LM_DEBUG, + "\nReceiving Flowspec :\t\t\tSending Flowspec :\n\n" + "\tToken Rate = %d\t\t\tToken Rate = %d\n" + "\tToken Bucket Size = %d\t\t\tToken Bucket Size = %d\n" + "\tPeak Bandwidth = %d\t\t\tPeak Bandwidth = %d\n" + "\tLatency = %d\t\t\t\tLatency = %d\n" + "\tDelay Variation = %d\t\t\tDelay Variation = %d\n" + "\tService Type = %d\t\t\tService Type = %d\n" + "\tMax SDU Size = %d\t\t\tMax SDU Size = %d\n" + "\tMinimum Policed Size = %d\t\tMinimum Policed Size = %d\n\n", + ace_get_qos.receiving_flowspec ()->token_rate (), + ace_get_qos.sending_flowspec ()->token_rate (), + ace_get_qos.receiving_flowspec ()->token_bucket_size (), + ace_get_qos.sending_flowspec ()->token_bucket_size (), + ace_get_qos.receiving_flowspec ()->peak_bandwidth (), + ace_get_qos.sending_flowspec ()->peak_bandwidth (), + ace_get_qos.receiving_flowspec ()->latency (), + ace_get_qos.sending_flowspec ()->latency (), + ace_get_qos.receiving_flowspec ()->delay_variation (), + ace_get_qos.sending_flowspec ()->delay_variation (), + ace_get_qos.receiving_flowspec ()->service_type (), + ace_get_qos.sending_flowspec ()->service_type (), + ace_get_qos.receiving_flowspec ()->max_sdu_size (), + ace_get_qos.sending_flowspec ()->max_sdu_size (), + ace_get_qos.receiving_flowspec ()->minimum_policed_size (), + ace_get_qos.sending_flowspec ()->minimum_policed_size ())); + + +return 0; + +} + + + + + + diff --git a/ACE/examples/QOS/Change_Sender_TSpec/Receiver_QoS_Event_Handler.h b/ACE/examples/QOS/Change_Sender_TSpec/Receiver_QoS_Event_Handler.h new file mode 100644 index 00000000000..874d628e3c1 --- /dev/null +++ b/ACE/examples/QOS/Change_Sender_TSpec/Receiver_QoS_Event_Handler.h @@ -0,0 +1,61 @@ +/* -*- C++ -*- */ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// ACE_wrappers/examples/QOS +// +// = FILENAME +// Receiver_QoS_Event_Handler.h +// +// = AUTHOR +// Vishal Kachroo <vishal@cs.wustl.edu> +// +// ============================================================================ + +#ifndef RECEIVER_QOS_EVENT_HANDLER_H +#define RECEIVER_QOS_EVENT_HANDLER_H + +#include "ace/Reactor.h" +#include "ace/INET_Addr.h" +#include "ace/Event_Handler.h" +#include "ace/QoS/QoS_Session.h" +#include "ace/QoS/SOCK_Dgram_Mcast_QoS.h" + +ACE_RCSID(Receiver_QoS_Event_Handler, Receiver_QoS_Event_Handler, "$Id$") + + class Receiver_QoS_Event_Handler : public ACE_Event_Handler + { + public: + // = Initialization and Termination methods. + Receiver_QoS_Event_Handler (void); + // Constructor. + + Receiver_QoS_Event_Handler::Receiver_QoS_Event_Handler (const ACE_SOCK_Dgram_Mcast_QoS &dgram_mcast_qos, + ACE_QoS_Session *qos_session); + // Constructor. + + ~Receiver_QoS_Event_Handler (void); + // Destructor. + + virtual ACE_HANDLE get_handle (void) const; + // Override this to return the handle of the Dgram_Mcast + // that we are using. + + virtual int handle_input (ACE_HANDLE fd); + // Handles a READ event. + + virtual int handle_qos (ACE_HANDLE fd); + // Handles a QoS event. + + private: + ACE_SOCK_Dgram_Mcast_QoS dgram_mcast_qos_; + ACE_QoS_Session *qos_session_; + ACE_INET_Addr remote_addr_; + }; + +#endif /* RECEIVER_QOS_EVENT_HANDLER_H */ + + + diff --git a/ACE/examples/QOS/Change_Sender_TSpec/Sender_QoS_Event_Handler.cpp b/ACE/examples/QOS/Change_Sender_TSpec/Sender_QoS_Event_Handler.cpp new file mode 100644 index 00000000000..7688bc34373 --- /dev/null +++ b/ACE/examples/QOS/Change_Sender_TSpec/Sender_QoS_Event_Handler.cpp @@ -0,0 +1,221 @@ +/* -*- C++ -*- */ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// ACE_wrappers/examples/QOS +// +// = FILENAME +// Sender_QoS_Event_Handler.cpp +// +// = AUTHOR +// Vishal Kachroo <vishal@cs.wustl.edu> +// +// ============================================================================ + +#include "Sender_QoS_Event_Handler.h" +#include "ace/Log_Msg.h" + +#include "Fill_ACE_QoS.h" + +// Constructor. +Sender_QoS_Event_Handler::Sender_QoS_Event_Handler (void) +{ +} + +// Constructor. +Sender_QoS_Event_Handler::Sender_QoS_Event_Handler (const ACE_SOCK_Dgram_Mcast_QoS + &dgram_mcast_qos, + ACE_QoS_Session *qos_session) + : dgram_mcast_qos_ (dgram_mcast_qos), + qos_session_ (qos_session) +{ +} + +// Destructor. +Sender_QoS_Event_Handler::~Sender_QoS_Event_Handler (void) +{ +} + +// Return the handle of the Dgram_Mcast. This method is called +// internally by the reactor. + +ACE_HANDLE +Sender_QoS_Event_Handler::get_handle (void) const +{ + return this->dgram_mcast_qos_.get_handle (); +} + +// Handle the QoS Event. In this case send data to the receiver +// using WSASendTo() that uses overlapped I/O. + +int +Sender_QoS_Event_Handler::handle_qos (ACE_HANDLE) +{ + ACE_DEBUG ((LM_DEBUG, + "\nReceived a QOS event. Inside handle_qos ()\n")); + + // We have received an RSVP event. The following update_qos () call + // calls rapi_dispatch () in case of RAPI and WSAIoctl (GET_QOS) in + // case of W2K. It then does the QoS parameter translation and updates + // the QoS session object with the latest QoS. This call replaces the + // direct call that was being made to WSAIoctl (GET_QOS) here for the + // Win2K example. + + if (this->qos_session_->update_qos () == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "Error in updating QoS\n"), + -1); + else + ACE_DEBUG ((LM_DEBUG, + " Updating QOS succeeds.\n")); + + // Now proactively query the QoS object for QoS. + ACE_QoS ace_get_qos = this->qos_session_->qos (); + + ACE_DEBUG ((LM_DEBUG, + "\nReceiving Flowspec :\t\t\tSending Flowspec :\n\n" + "\tToken Rate = %d\t\t\tToken Rate = %d\n" + "\tToken Bucket Size = %d\t\t\tToken Bucket Size = %d\n" + "\tPeak Bandwidth = %d\t\t\tPeak Bandwidth = %d\n" + "\tLatency = %d\t\t\t\tLatency = %d\n" + "\tDelay Variation = %d\t\t\tDelay Variation = %d\n" + "\tService Type = %d\t\t\tService Type = %d\n" + "\tMax SDU Size = %d\t\t\tMax SDU Size = %d\n" + "\tMinimum Policed Size = %d\t\tMinimum Policed Size = %d\n\n", + ace_get_qos.receiving_flowspec ()->token_rate (), + ace_get_qos.sending_flowspec ()->token_rate (), + ace_get_qos.receiving_flowspec ()->token_bucket_size (), + ace_get_qos.sending_flowspec ()->token_bucket_size (), + ace_get_qos.receiving_flowspec ()->peak_bandwidth (), + ace_get_qos.sending_flowspec ()->peak_bandwidth (), + ace_get_qos.receiving_flowspec ()->latency (), + ace_get_qos.sending_flowspec ()->latency (), + ace_get_qos.receiving_flowspec ()->delay_variation (), + ace_get_qos.sending_flowspec ()->delay_variation (), + ace_get_qos.receiving_flowspec ()->service_type (), + ace_get_qos.sending_flowspec ()->service_type (), + ace_get_qos.receiving_flowspec ()->max_sdu_size (), + ace_get_qos.sending_flowspec ()->max_sdu_size (), + ace_get_qos.receiving_flowspec ()->minimum_policed_size (), + ace_get_qos.sending_flowspec ()->minimum_policed_size ())); + + // This is SPECIFIC TO WIN2K and should be done in the qos_update function. + +// ACE_QoS ace_get_qos; +// u_long dwBytes; + +// if (ACE_OS::ioctl (this->dgram_mcast_qos_.get_handle (), +// ACE_SIO_GET_QOS, +// ace_get_qos, +// &dwBytes) == -1) +// ACE_ERROR ((LM_ERROR, +// "Error in Qos get ACE_OS::ioctl ()\n" +// "Bytes Returned = %d\n", +// dwBytes)); +// else +// ACE_DEBUG ((LM_DEBUG, +// "Getting QOS using ACE_OS::ioctl () succeeds.\n")); + + char* msg = "Hello sent on a QoS enabled session !!\n"; + iovec iov[1]; + iov[0].iov_base = msg; + iov[0].iov_len = ACE_OS::strlen(msg); + + size_t bytes_sent = 0; + + // Send "Hello" to the QoS session address to which the receiver has + // subscribed. + if (this->dgram_mcast_qos_.send (iov, + 1, + bytes_sent, + 0, + this->qos_session_->dest_addr (), + 0, + 0) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "Error in dgram_mcast.send ()\n"), + -1); + else + ACE_DEBUG ((LM_DEBUG, + "Using ACE_OS::sendto () : Bytes sent : %d", + bytes_sent)); + + // + // create a dynamic flow spec on each callback to test QoS retransmits + // + ACE_CString flow_id ("flow_id"); + + Fill_ACE_QoS flow_spec_list; + ACE_DEBUG ((LM_DEBUG, + "\nA new flow spec! in QoS handler.")); + + static int token_rate = 9400; + ++token_rate; + static int peak_bw = 18500; + ++peak_bw; + switch (flow_spec_list.map ().bind (flow_id, + new ACE_Flow_Spec (token_rate, + 708, + peak_bw, + 0, + 0, + ACE_SERVICETYPE_CONTROLLEDLOAD, + 368, + 368, + 25, + 1))) + { + case 1 : + ACE_ERROR_RETURN ((LM_ERROR, + "Unable to bind the new flow spec\n" + "The Flow Spec name already exists\n"), + -1); + break; + case -1 : + ACE_ERROR_RETURN ((LM_ERROR, + "Unable to bind the new flow spec\n"), + -1); + break; + } + + // + // set up the new qos + // + ACE_QoS another_qos_sender; + if (flow_spec_list.fill_simplex_sender_qos (another_qos_sender, + flow_id) !=0) + ACE_ERROR_RETURN ((LM_ERROR, + "Unable to fill handler-simplex sender qos\n"), + -1); + else + ACE_DEBUG ((LM_DEBUG, + "Successfully built a new flowspec in handle_qos!\n")); + + // + // change the qos for the current session + // + ACE_QoS_Manager qos_manager = this->dgram_mcast_qos_.qos_manager (); + + ACE_DEBUG ((LM_DEBUG, + "QoS Manager was built in handle_qos!\n")); + + // Set the QoS for the session. Replaces the ioctl () call that + // was being made previously. + if (this->qos_session_->qos (&this->dgram_mcast_qos_, + &qos_manager, + another_qos_sender) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "Unable to set QoS\n"), + -1); + else + ACE_DEBUG ((LM_DEBUG, + "Setting QOS succeeds.\n")); + + + // ACE_SOCK_Dgram_Mcast_QoS dgram_mcast_qos_; + // ACE_QoS_Session *qos_session_; + + return 0; +} diff --git a/ACE/examples/QOS/Change_Sender_TSpec/Sender_QoS_Event_Handler.h b/ACE/examples/QOS/Change_Sender_TSpec/Sender_QoS_Event_Handler.h new file mode 100644 index 00000000000..b691bbd0615 --- /dev/null +++ b/ACE/examples/QOS/Change_Sender_TSpec/Sender_QoS_Event_Handler.h @@ -0,0 +1,61 @@ +/* -*- C++ -*- */ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// ACE_wrappers/examples/QOS +// +// = FILENAME +// Sender_QoS_Event_Handler.h +// +// = AUTHOR +// Vishal Kachroo <vishal@cs.wustl.edu> +// +// ============================================================================ + +#ifndef SENDER_QOS_EVENT_HANDLER_H +#define SENDER_QOS_EVENT_HANDLER_H + +#include "ace/Event_Handler.h" +#include "ace/Reactor.h" +#include "ace/INET_Addr.h" +#include "ace/QoS/SOCK_Dgram_Mcast_QoS.h" +#include "ace/QoS/QoS_Session.h" + +//#define MY_DEFPORT 5001 +//#define DEFAULT_MULTICASTGROUP "234.5.6.7" + +ACE_RCSID(Sender_QoS_Event_Handler, Sender_QoS_Event_Handler, "$Id$") + +class Sender_QoS_Event_Handler : public ACE_Event_Handler +{ +public: + // = Initialization and Termination methods. + Sender_QoS_Event_Handler (void); + // Constructor. + + Sender_QoS_Event_Handler::Sender_QoS_Event_Handler (const ACE_SOCK_Dgram_Mcast_QoS + &dgram_mcast_qos, + ACE_QoS_Session *qos_session + ); + // Constructor. + + ~Sender_QoS_Event_Handler (void); + // Destructor. + + virtual ACE_HANDLE get_handle (void) const; + // Override this to return the handle of the Dgram_Mcast + // that we are using. + + virtual int handle_qos (ACE_HANDLE fd); + // Handles a QoS event. Right now, just + // prints a message. + +private: + + ACE_SOCK_Dgram_Mcast_QoS dgram_mcast_qos_; + ACE_QoS_Session *qos_session_; +}; + +#endif /* SENDER_QOS_EVENT_HANDLER_H */ diff --git a/ACE/examples/QOS/Change_Sender_TSpec/receiver.cpp b/ACE/examples/QOS/Change_Sender_TSpec/receiver.cpp new file mode 100644 index 00000000000..e5702b90c1c --- /dev/null +++ b/ACE/examples/QOS/Change_Sender_TSpec/receiver.cpp @@ -0,0 +1,319 @@ +/* -*- C++ -*- */ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// ACE_wrappers/examples/QOS +// +// = FILENAME +// server.cpp +// +// = AUTHOR +// Vishal Kachroo <vishal@cs.wustl.edu> +// +// ============================================================================ + +#define QOSEVENT_MAIN + +#include "ace/QoS/QoS_Session.h" +#include "ace/QoS/QoS_Session_Factory.h" +#include "ace/QoS/QoS_Decorator.h" +#include "ace/QoS/SOCK_Dgram_Mcast_QoS.h" + +#include "QoS_Util.h" +#include "Fill_ACE_QoS.h" +#include "QoS_Signal_Handler.h" +#include "Receiver_QoS_Event_Handler.h" + +// To open QOS sockets administrative access is required on the +// machine. Fill in default values for QoS structure. The default +// values were simply choosen from existing QOS templates available +// via WSAGetQosByName. Notice that ProviderSpecific settings are +// being allowed when picking the "default" template but not for +// "well-known" QOS templates. Also notice that since data is only +// flowing from sender to receiver, different flowspecs are filled in +// depending upon whether this application is acting as a sender or +// receiver. + + +// This function fills up the ACE_QoS_Params with the supplied iovec +// and ACE_QoS. + +int +FillQoSParams (ACE_QoS_Params &qos_params, + iovec* iov, + ACE_QoS* qos) +{ + qos_params.callee_data (iov); + qos_params.caller_data (0); + qos_params.socket_qos (qos); + qos_params.group_socket_qos (0); + qos_params.flags (ACE_JL_BOTH); + + return 0; +} + +int +ACE_TMAIN (int argc, ACE_TCHAR * argv[]) +{ + + QoS_Util qos_util(argc, argv); + + if (qos_util.parse_args () == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "Error in parsing args\n"), + -1); + + // This is a multicast application. + if (qos_util.multicast_flag ()) + { + Fill_ACE_QoS fill_ace_qos; + + // The application adds the flow specs that it wants into the + // Fill_ACE_QoS. The Fill_ACE_QoS indexes the flow specs by the + // flow spec names. Here the new flowspec being added is g_711. + ACE_CString g_711 ("g_711"); + + switch (fill_ace_qos.map ().bind (g_711, + new ACE_Flow_Spec (9200, + 708, + 18400, + 0, + 0, + ACE_SERVICETYPE_CONTROLLEDLOAD, + 368, + 368, + 25, + 1))) + { + case 1 : + ACE_ERROR_RETURN ((LM_ERROR, + "Unable to bind the new flow spec\n" + "The Flow Spec name already exists\n"), + -1); + break; + case -1 : + ACE_ERROR_RETURN ((LM_ERROR, + "Unable to bind the new flow spec\n"), + -1); + break; + } + + ACE_DEBUG ((LM_DEBUG, + "g_711 Flow Spec bound successfully\n")); + + // This is a receiver. So we fill in the receiving QoS parameters. + ACE_QoS ace_qos_receiver; + if (fill_ace_qos.fill_simplex_receiver_qos (ace_qos_receiver, + g_711) !=0) + ACE_ERROR_RETURN ((LM_ERROR, + "Unable to fill simplex receiver qos\n"), + -1); + else + ACE_DEBUG ((LM_DEBUG, + "Filled up the Receiver QoS parameters\n")); + + // Opening a new Multicast Datagram. + ACE_SOCK_Dgram_Mcast_QoS dgram_mcast_qos; + + // Multicast Session Address specified by user at command line. + // If this address is not specified, + // <localhost:ACE_DEFAULT_MULTICAST_PORT> is assumed. + ACE_INET_Addr mult_addr (*(qos_util.mult_session_addr ())); + + // Fill the ACE_QoS_Params to be passed to the <ACE_OS::join_leaf> + // through subscribe. + + ACE_QoS_Params qos_params; + FillQoSParams (qos_params, 0, &ace_qos_receiver); + + // Create a QoS Session Factory. + ACE_QoS_Session_Factory session_factory; + + // Ask the factory to create a QoS session. + ACE_QoS_Session *qos_session = + session_factory.create_session (); + + // Create a destination address for the QoS session. The same + // address should be used for the subscribe call later. A copy + // is made below only to distinguish the two usages of the dest + // address. + + ACE_INET_Addr dest_addr (mult_addr); + + // A QoS session is defined by the 3-tuple [DestAddr, DestPort, + // Protocol]. Initialize the QoS session. + if (qos_session->open (mult_addr, + IPPROTO_UDP) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "Error in opening the QoS session\n"), + -1); + else + ACE_DEBUG ((LM_DEBUG, + "QoS session opened successfully\n")); + + // The following call opens the Dgram_Mcast and calls the + // <ACE_OS::join_leaf> with the qos_params supplied here. Note + // the QoS session object is passed into this call. This + // subscribes the underlying socket to the passed in QoS + // session. For joining multiple multicast sessions, the + // following subscribe call should be made with different + // multicast addresses and a new QoS session object should be + // passed in for each such call. The QoS session objects can be + // created only through the session factory. Care should be + // taken that the mult_addr for the subscribe() call matches the + // dest_addr of the QoS session object. If this is not done, the + // subscribe call will fail. A more abstract version of + // subscribe will be added that constrains the various features + // of GQoS like different flags etc. + + if (dgram_mcast_qos.subscribe (mult_addr, + qos_params, + 1, + 0, + AF_INET, + // ACE_FROM_PROTOCOL_INFO, + 0, + 0, // ACE_Protocol_Info, + 0, + ACE_OVERLAPPED_SOCKET_FLAG + | ACE_FLAG_MULTIPOINT_C_LEAF + | ACE_FLAG_MULTIPOINT_D_LEAF, + qos_session) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "Error in subscribe\n"), + -1); + else + ACE_DEBUG ((LM_DEBUG, + "Dgram_Mcast subscribe succeeds \n")); + + int nIP_TTL = 25; + char achInBuf [BUFSIZ]; + u_long dwBytes; + + // Should this be abstracted into QoS objects ?? Doesnt seem to have + // to do anything directly with QoS. + if (ACE_OS::ioctl (dgram_mcast_qos.get_handle (), // Socket. + ACE_SIO_MULTICAST_SCOPE, // IO control code. + &nIP_TTL, // In buffer. + sizeof (nIP_TTL), // Length of in buffer. + achInBuf, // Out buffer. + BUFSIZ, // Length of Out buffer. + &dwBytes, // bytes returned. + 0, // Overlapped. + 0) == -1) // Func. + ACE_ERROR ((LM_ERROR, + "Error in Multicast scope ACE_OS::ioctl() \n")); + else + ACE_DEBUG ((LM_DEBUG, + "Setting TTL with Multicast scope ACE_OS::ioctl call succeeds \n")); + + int bFlag = 0; + + // Should this be abstracted into QoS objects ?? Doesnt seem to have + // to do anything directly with QoS. + if (ACE_OS::ioctl (dgram_mcast_qos.get_handle (), // Socket. + ACE_SIO_MULTIPOINT_LOOPBACK, // IO control code. + &bFlag, // In buffer. + sizeof (bFlag), // Length of in buffer. + achInBuf, // Out buffer. + BUFSIZ, // Length of Out buffer. + &dwBytes, // bytes returned. + 0, // Overlapped. + 0) == -1) // Func. + ACE_ERROR ((LM_ERROR, + "Error in Loopback ACE_OS::ioctl() \n")); + else + ACE_DEBUG ((LM_DEBUG, + "Disable Loopback with ACE_OS::ioctl call succeeds \n")); + + // This is a receiver. + qos_session->flags (ACE_QoS_Session::ACE_QOS_RECEIVER); + + ACE_QoS_Manager qos_manager = dgram_mcast_qos.qos_manager (); + + // Set the QoS for the session. Replaces the ioctl () call that + // was being made previously. + if (qos_session->qos (&dgram_mcast_qos, + &qos_manager, + ace_qos_receiver) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "Unable to set QoS\n"), + -1); + else + ACE_DEBUG ((LM_DEBUG, + "Setting QOS succeeds.\n")); + + // Register a signal handler that helps to gracefully close the + // open QoS sessions. + QoS_Signal_Handler qos_signal_handler (qos_session); + + // Register the usual SIGINT signal handler with the Reactor for + // the application to gracefully release the QoS session and + // shutdown. + if (ACE_Reactor::instance ()->register_handler + (SIGINT, &qos_signal_handler) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "Error in registering the Signal Handler.\n"), + -1); + + // Handler to process QoS and Data events for the reciever. + Receiver_QoS_Event_Handler qos_event_handler (dgram_mcast_qos, + qos_session); + + // Decorate the above handler with QoS functionality. + ACE_QoS_Decorator qos_decorator (&qos_event_handler, + qos_session); + + // Initialize the Decorator. + if (qos_decorator.init () != 0) + ACE_ERROR_RETURN ((LM_ERROR, + "QoS Decorator init () failed.\n"), + -1); + + // Register the decorated Event Handler with the Reactor. + if (ACE_Reactor::instance ()->register_handler (&qos_decorator, + ACE_Event_Handler::QOS_MASK | + ACE_Event_Handler::READ_MASK) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "Error in registering the Decorator with the Reactor\n"), + -1); + +// // Register the RAPI Event Handler with the Reactor. This +// // handles the QoS events. +// if (ACE_Reactor::instance ()->register_handler +// (&rapi_event_handler, +// ACE_Event_Handler::QOS_MASK | ACE_Event_Handler::READ_MASK) == -1) +// ACE_ERROR_RETURN ((LM_ERROR, +// "Error in registering the RAPI Event Handler\n"), +// -1); + +// // The following event handler handles the data. +// ACE_QoS_Event_Handler data_event_handler (dgram_mcast_qos, +// qos_session); + +// // Register the Data Event Handler with the Reactor. +// if (ACE_Reactor::instance ()->register_handler +// (&data_event_handler,ACE_Event_Handler::READ_MASK) == -1) +// ACE_ERROR_RETURN ((LM_ERROR, +// "Error in registering Data Event Handler\n"), +// -1); + + // Start the event loop. + ACE_DEBUG ((LM_DEBUG, + "Running the Event Loop ... \n")); + + ACE_Reactor::instance ()->run_event_loop (); + + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) shutting down server logging daemon\n")); + } + else + ACE_DEBUG ((LM_DEBUG, + "Specify a -m option for multicast application\n")); + return 0; +} + + + diff --git a/ACE/examples/QOS/Change_Sender_TSpec/sender.cpp b/ACE/examples/QOS/Change_Sender_TSpec/sender.cpp new file mode 100644 index 00000000000..68d8d1a5586 --- /dev/null +++ b/ACE/examples/QOS/Change_Sender_TSpec/sender.cpp @@ -0,0 +1,313 @@ +/* -*- C++ -*- */ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// ACE_wrappers/examples/QOS +// +// = FILENAME +// client.cpp +// +// = AUTHOR +// Vishal Kachroo <vishal@cs.wustl.edu> +// +// ============================================================================ + + +#include "ace/QoS/QoS_Session.h" +#include "ace/QoS/QoS_Session_Factory.h" +#include "ace/QoS/QoS_Session_Impl.h" +#include "ace/QoS/QoS_Decorator.h" +#include "ace/QoS/SOCK_Dgram_Mcast_QoS.h" + +#include "QoS_Util.h" +#include "Fill_ACE_QoS.h" +#include "QoS_Signal_Handler.h" +#include "Sender_QoS_Event_Handler.h" + +// To open QOS sockets administrative access is required on the +// machine. Fill in default values for QoS structure. The default +// values were simply choosen from existing QOS templates available +// via WSAGetQosByName. Notice that ProviderSpecific settings are +// being allowed when picking the "default" template but not for +// "well-known" QOS templates. Also notice that since data is only +// flowing from sender to receiver, different flowspecs are filled in +// depending upon whether this application is acting as a sender or +// receiver. + +// This function fills up the ACE_QoS_Params with the supplied iovec and ACE_QoS. + +int +FillQoSParams (ACE_QoS_Params &qos_params, + iovec* iov, + ACE_QoS* qos) +{ + qos_params.callee_data (iov); + qos_params.caller_data (0); + qos_params.socket_qos (qos); + qos_params.group_socket_qos (0); + qos_params.flags (ACE_JL_BOTH); + + return 0; +} + +int +ACE_TMAIN (int argc, ACE_TCHAR * argv[]) +{ + + ACE_DEBUG ((LM_DEBUG, + "Sender\n")); + + QoS_Util qos_util(argc, argv); + + if (qos_util.parse_args () == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "Error in parsing args\n"), + -1); + + // This is a multicast application. + if (qos_util.multicast_flag ()) + { + Fill_ACE_QoS fill_ace_qos; + + // The application adds the flow specs that it wants into the + // Fill_ACE_QoS. The Fill_ACE_QoS indexes the flow specs by the flow + // spec names. Here the new flowspec being added is g_711. + ACE_CString g_711 ("g_711"); + + switch (fill_ace_qos.map ().bind (g_711, + new ACE_Flow_Spec (9200, + 708, + 18400, + 0, + 0, + ACE_SERVICETYPE_CONTROLLEDLOAD, + 368, + 368, + 25, + 1))) + { + case 1 : + ACE_ERROR_RETURN ((LM_ERROR, + "Unable to bind the new flow spec\n" + "The Flow Spec name already exists\n"), + -1); + break; + case -1 : + ACE_ERROR_RETURN ((LM_ERROR, + "Unable to bind the new flow spec\n"), + -1); + break; + } + + ACE_DEBUG ((LM_DEBUG, + "g_711 Flow Spec bound successfully\n")); + + // This is a sender. So we fill in the sending QoS parameters. + ACE_QoS ace_qos_sender; + + if (fill_ace_qos.fill_simplex_sender_qos (ace_qos_sender, + g_711) !=0) + ACE_ERROR_RETURN ((LM_ERROR, + "Unable to fill simplex sender qos\n"), + -1); + else + ACE_DEBUG ((LM_DEBUG, + "Filled up the Sender QoS parameters\n")); + + // Opening a new Multicast Datagram. It is absolutely necessary that + // the sender and the receiver subscribe to the same multicast + // addresses to make sure the "multicast sessions" for the two are + // the same. This is used to match the RESV<->PATH states. + ACE_SOCK_Dgram_Mcast_QoS dgram_mcast_qos; + + // Multicast Session Address specified by user at command line. + // If this address is not specified, + // <localhost:ACE_DEFAULT_MULTICAST_PORT> is assumed. + ACE_INET_Addr mult_addr (*(qos_util.mult_session_addr ())); + + // Fill the ACE_QoS_Params to be passed to the <ACE_OS::join_leaf> + // through subscribe. + + ACE_QoS_Params qos_params; + FillQoSParams (qos_params, 0, &ace_qos_sender); + + // Create a QoS Session Factory. + ACE_QoS_Session_Factory session_factory; + + // Ask the factory to create a QoS session. + ACE_QoS_Session *qos_session = + session_factory.create_session (); + + // Create a destination address for the QoS session. The same + // address should be used for the subscribe call later. A copy is + // made below only to distinguish the two usages of the dest + // address. + + ACE_INET_Addr dest_addr (mult_addr); + + // A QoS session is defined by the 3-tuple [DestAddr, DestPort, + // Protocol]. Initialize the QoS session. + if (qos_session->open (mult_addr, + IPPROTO_UDP) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "Error in opening the QoS session\n"), + -1); + else + ACE_DEBUG ((LM_DEBUG, + "QoS session opened successfully\n")); + + // The following call opens the Dgram_Mcast and calls the + // <ACE_OS::join_leaf> with the qos_params supplied here. Note the + // QoS session object is passed into this call. This subscribes the + // underlying socket to the passed in QoS session. For joining + // multiple multicast sessions, the following subscribe call should + // be made with different multicast addresses and a new QoS session + // object should be passed in for each such call. The QoS session + // objects can be created only through the session factory. Care + // should be taken that the mult_addr for the subscribe() call + // matches the dest_addr of the QoS session object. If this is not + // done, the subscribe call will fail. A more abstract version of + // subscribe will be added that constrains the various features of + // GQoS like different flags etc. + + if (dgram_mcast_qos.subscribe (mult_addr, + qos_params, + 1, + 0, + AF_INET, + // ACE_FROM_PROTOCOL_INFO, + 0, + 0, // ACE_Protocol_Info, + 0, + ACE_OVERLAPPED_SOCKET_FLAG + | ACE_FLAG_MULTIPOINT_C_LEAF + | ACE_FLAG_MULTIPOINT_D_LEAF, + qos_session) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "Error in subscribe\n"), + -1); + else + ACE_DEBUG ((LM_DEBUG, + "Dgram_Mcast subscribe succeeds \n")); + + int nIP_TTL = 25; + char achInBuf [BUFSIZ]; + u_long dwBytes; + + // Should this be abstracted into QoS objects ?? Doesnt seem to have + // to do anything directly with QoS. + if (ACE_OS::ioctl (dgram_mcast_qos.get_handle (), // Socket. + ACE_SIO_MULTICAST_SCOPE, // IO control code. + &nIP_TTL, // In buffer. + sizeof (nIP_TTL), // Length of in buffer. + achInBuf, // Out buffer. + BUFSIZ, // Length of Out buffer. + &dwBytes, // bytes returned. + 0, // Overlapped. + 0) == -1) // Func. + ACE_ERROR ((LM_ERROR, + "Error in Multicast scope ACE_OS::ioctl() \n")); + else + ACE_DEBUG ((LM_DEBUG, + "Setting TTL with Multicast scope ACE_OS::ioctl call succeeds \n")); + + int bFlag = 0; + + // Should this be abstracted into QoS objects ?? Doesnt seem to have + // to do anything directly with QoS. + if (ACE_OS::ioctl (dgram_mcast_qos.get_handle (), // Socket. + ACE_SIO_MULTIPOINT_LOOPBACK, // IO control code. + &bFlag, // In buffer. + sizeof (bFlag), // Length of in buffer. + achInBuf, // Out buffer. + BUFSIZ, // Length of Out buffer. + &dwBytes, // bytes returned. + 0, // Overlapped. + 0) == -1) // Func. + ACE_ERROR ((LM_ERROR, + "Error in Loopback ACE_OS::ioctl() \n")); + else + ACE_DEBUG ((LM_DEBUG, + "Disable Loopback with ACE_OS::ioctl call succeeds \n")); + + // This is a sender. + qos_session->flags (ACE_QoS_Session::ACE_QOS_SENDER); + + ACE_QoS_Manager qos_manager = dgram_mcast_qos.qos_manager (); + + // Since we are using RSVP, it is imperative that the client + // application have the option of supplying the source sender + // port for the RSVP messages. A default will be chosen by the + // ACE API if this is not done. + qos_session->source_port (qos_util.source_port ()); + + // Set the QoS for the session. Replaces the ioctl () call that + // was being made previously. + if (qos_session->qos (&dgram_mcast_qos, + &qos_manager, + ace_qos_sender) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "Unable to set QoS\n"), + -1); + else + ACE_DEBUG ((LM_DEBUG, + "Setting QOS succeeds.\n")); + + // Register a signal handler that helps to gracefully close the open + // QoS sessions. + QoS_Signal_Handler qos_signal_handler (qos_session); + + // Register the usual SIGINT signal handler with the Reactor for + // the application to gracefully release the QoS session and + // shutdown. + if (ACE_Reactor::instance ()->register_handler + (SIGINT, &qos_signal_handler) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "Error in registering the Signal Handler.\n"), + -1); + + // Handler to process QoS and Data events for the reciever. + Sender_QoS_Event_Handler qos_event_handler (dgram_mcast_qos, + qos_session); + + // Decorate the above handler with QoS functionality. + ACE_QoS_Decorator qos_decorator (&qos_event_handler, + qos_session); + + // Initialize the Decorator. + if (qos_decorator.init () != 0) + ACE_ERROR_RETURN ((LM_ERROR, + "QoS Decorator init () failed.\n"), + -1); + + // Register the decorated Event Handler with the Reactor. + if (ACE_Reactor::instance ()->register_handler (&qos_decorator, + ACE_Event_Handler::QOS_MASK | + ACE_Event_Handler::READ_MASK) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "Error in registering the Decorator with the Reactor\n"), + -1); + + // Start the event loop. + ACE_DEBUG ((LM_DEBUG, + "Running the Event Loop ... \n")); + + ACE_Reactor::instance ()->run_event_loop (); + + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) shutting down server logging daemon\n")); + } + else + ACE_DEBUG ((LM_DEBUG, + "Specify a -m option for multicast application\n")); + return 0; +} + + + + + + + diff --git a/ACE/examples/QOS/Diffserv/Makefile.am b/ACE/examples/QOS/Diffserv/Makefile.am new file mode 100644 index 00000000000..e94221278a2 --- /dev/null +++ b/ACE/examples/QOS/Diffserv/Makefile.am @@ -0,0 +1,62 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +ACE_BUILDDIR = $(top_builddir) +ACE_ROOT = $(top_srcdir) + +noinst_PROGRAMS = + +## Makefile.QOS_Diffserv_Client.am + +if BUILD_QOS +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS += client + +client_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) \ + -DACE_HAS_QOS + +client_SOURCES = \ + diffserv_test.cpp + +client_LDADD = \ + $(ACE_BUILDDIR)/ace/QoS/libACE_QoS.la \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO +endif BUILD_QOS + +## Makefile.QOS_Diffserv_Server.am + +if BUILD_QOS +noinst_PROGRAMS += server + +server_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) \ + -DACE_HAS_QOS + +server_SOURCES = \ + server.cpp + +server_LDADD = \ + $(ACE_BUILDDIR)/ace/QoS/libACE_QoS.la \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif BUILD_QOS + +## Clean up template repositories, etc. +clean-local: + -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.* + -rm -f gcctemp.c gcctemp so_locations *.ics + -rm -rf cxx_repository ptrepository ti_files + -rm -rf templateregistry ir.out + -rm -rf ptrepository SunWS_cache Templates.DB diff --git a/ACE/examples/QOS/Diffserv/NOTES.txt b/ACE/examples/QOS/Diffserv/NOTES.txt new file mode 100644 index 00000000000..4e73c66af0f --- /dev/null +++ b/ACE/examples/QOS/Diffserv/NOTES.txt @@ -0,0 +1,58 @@ +# $Id$ + +Linux notes +=========== + +Under Linux kernel 2.4, the following DSCP values +could not be set with the setsockopt call +unless you run as root: + +EF, CS5, CS6, CS7 + +Also, under Linux 2.4.2 kernel, if I could successfully +set the 2 bits reserved for ECN in the Diffserv Field to +0x00 or 0x02. However, the setsockopt call would +fail if it was set to 0x01 or 0x03. + +According to the Linux Diffserv mailing list: +http://diffserv.sourceforge.net +http://www.geocrawler.com/archives/3/11111/2001/10/0/6761099/ + +=========================================================================== +On Fri, Oct 05, 2001 at 08:18:06AM +0300, Pekka Savola wrote: +> On Tue, 2 Oct 2001, Craig Rodrigues wrote: +> > Can someone shed some light as to why I got this +> > error under Linux? Is it configuration problem, +> > or is there some sort of policy decision in the kernel that +> > requires the process to be run as root when setting +> > those DSCP values? +> +> A part of DSCP field was previously Precedence. +> +> Linux has required that in order to use 'Critical' or higher Precedence, +> one must have CAP_NET_ADMIN capability, in most cases, root. +> +> I'm not one to say whether this restriction should be removed. Perhaps. +> +> -- +> Pekka Savola "Tell me of difficulties surmounted, +> Netcore Oy not those you stumble over and fall" +> Systems. Networks. Security. -- Robert Jordan: A Crown of Swords +> +=========================================================================== + +FreeBSD notes +============= +Under FreeBSD 4.3, I encountered no problems +setting DSCP or ECN values, and I could set all +these values without being root. +However, FreeBSD seems to be more fussy about the size of the parameter +you pass into the setsockopt call. Make sure you get the +size right, and cast it properly, ie. don't cast a short, or some +other size. + + +Solaris notes +============= +No problems setting DSCP or ECN values. + diff --git a/ACE/examples/QOS/Diffserv/QOS_Diffserv.mpc b/ACE/examples/QOS/Diffserv/QOS_Diffserv.mpc new file mode 100644 index 00000000000..3e66fbee34a --- /dev/null +++ b/ACE/examples/QOS/Diffserv/QOS_Diffserv.mpc @@ -0,0 +1,18 @@ +// -*- MPC -*- +// $Id$ + +project(*client) : aceexe, qos { + avoids += ace_for_tao + exename = client + requires += qos + Source_Files { + diffserv_test.cpp + } +} +project(*server) : aceexe, qos { + exename = server + requires += qos + Source_Files { + server.cpp + } +} diff --git a/ACE/examples/QOS/Diffserv/README b/ACE/examples/QOS/Diffserv/README new file mode 100644 index 00000000000..285d514ad12 --- /dev/null +++ b/ACE/examples/QOS/Diffserv/README @@ -0,0 +1,107 @@ +This directory contains an example which +tests the setting of the Diffserv Codepoint (DSCP) +values in the +IP TOS field of a stream of UDP packets. + +Running the example +=================== + +(1) On one host, run: + server [UDP port number] + + If port number is omitted, a default port number of 20002 + is used. + +(2) On a second host, run: + diffserv_test [destination host] [destination port] + + The host and port of where the server is running should + be specified. + + A stream of UDP packets will be sent from to the server, + with various codepoints set. + +(3) Look at the Diffserv Field (formerly known as the TOS field) + of your packets, using a protocol analyzer, such as Ethereal. + + + + +Introduction +============ +In RFC 2474, the Type of Service (TOS) field in +the IP header was renamed the Diffserv (DS) field. +The DS field is one octet (8 bits). + + 0 1 2 3 4 5 6 7 + +---+---+---+---+---+---+---+---+ + | DSCP | ECN | + +---+---+---+---+---+---+---+---+ + +The first 6 bits of the field are +reserved for the Diffserv Codepoint (DSCP). +There are 64 possible values (0-63) for the DSCP. + +Bits 6 and 7 of the DS field are reserved +for Explicit Congestion Notification (ECN). +ECN is defined in RFC 3168. + + +Per-Hop Behaviors (PHB) +======================= + +A Per-Hop Behavior (PHB) is a description of the externally +observable forwarding treatment applied at a differentiated +services compliant node. + +Certain PHB's are defined in RFC's and associated with +different DSCP values. Other values are undefined and left +for experimentation. Please refer to the RFC's for a full +explanation of the attributes of the various PHB's. + + +DSCP value PHB RFC +(binary) +----------------------------------------------------------- +000000 Default (Best Effort) 2474 +001000 Class Selector (CS1) 2474 +010000 Class Selector (CS2) 2474 +011000 Class Selector (CS3) 2474 +100000 Class Selector (CS4) 2474 +101000 Class Selector (CS5) 2474 +110000 Class Selector (CS6) 2474 +111000 Class Selector (CS7) 2474 +001010 Assured Forwarding (AF11) 2597 +001100 Assured Forwarding (AF12) 2597 +001110 Assured Forwarding (AF13) 2597 +010010 Assured Forwarding (AF21) 2597 +010100 Assured Forwarding (AF22) 2597 +010110 Assured Forwarding (AF23) 2597 +011010 Assured Forwarding (AF31) 2597 +011100 Assured Forwarding (AF32) 2597 +011110 Assured Forwarding (AF33) 2597 +100010 Assured Forwarding (AF41) 2597 +100100 Assured Forwarding (AF42) 2597 +100110 Assured Forwarding (AF43) 2597 +101110 Expedited Forwarding (EF) 2598 + + +References +========== +RFC 2474, "Definition of the Differentiated Services (DS Field) + in the IPv4 and IPv6 Headers", http://www.ietf.org/rfc/rfc2474.txt + +RFC 2475, "An Architecture for Differentiated Services", + http://www.ietf.org/rfc/rfc2475.txt + +RFC 2597, "Assured Forwarding PHB Group", http://www.ietf.org/rfc/rfc2597.txt + +RFC 3246, "An Expedited Forwarding PHB", http://www.ietf.org/rfc/rfc3246.txt + +RFC 3247, "Supplemental Information for the New Definition of the EF PHB", + http://www.ietf.org/rfc/rfc3247.txt + +RFC 3168, "The Addition of Explicit Congestion Notification (ECN) + to IP", http://www.ietf.org/rfc/rfc3168.txt + +Ethereal, http://www.ethereal.com diff --git a/ACE/examples/QOS/Diffserv/diffserv_test.cpp b/ACE/examples/QOS/Diffserv/diffserv_test.cpp new file mode 100644 index 00000000000..1969616ea32 --- /dev/null +++ b/ACE/examples/QOS/Diffserv/diffserv_test.cpp @@ -0,0 +1,136 @@ +//============================================================================= +/** + * @file diffserv_test.cpp + * + * $Id$ + * + * @author Craig Rodrigues <crodrigu@bbn.com> + * @brief Send UDP packets to a destination host and port. + * Change the Diffserv field to various values. + */ +//============================================================================= + +#include "ace/Log_Msg.h" +#include "ace/SOCK_CODgram.h" +#include "ace/INET_Addr.h" +#include "ace/OS_NS_string.h" +#include "ace/OS_NS_stdlib.h" +#include "ace/OS_NS_unistd.h" + +#define IPDSFIELD_DSCP_DEFAULT 0x00 +#define IPDSFIELD_DSCP_CS1 0x08 +#define IPDSFIELD_DSCP_CS2 0x10 +#define IPDSFIELD_DSCP_CS3 0x18 +#define IPDSFIELD_DSCP_CS4 0x20 +#define IPDSFIELD_DSCP_CS5 0x28 +#define IPDSFIELD_DSCP_CS6 0x30 +#define IPDSFIELD_DSCP_CS7 0x38 +#define IPDSFIELD_DSCP_AF11 0x0A +#define IPDSFIELD_DSCP_AF12 0x0C +#define IPDSFIELD_DSCP_AF13 0x0E +#define IPDSFIELD_DSCP_AF21 0x12 +#define IPDSFIELD_DSCP_AF22 0x14 +#define IPDSFIELD_DSCP_AF23 0x16 +#define IPDSFIELD_DSCP_AF31 0x1A +#define IPDSFIELD_DSCP_AF32 0x1C +#define IPDSFIELD_DSCP_AF33 0x1E +#define IPDSFIELD_DSCP_AF41 0x22 +#define IPDSFIELD_DSCP_AF42 0x24 +#define IPDSFIELD_DSCP_AF43 0x26 +#define IPDSFIELD_DSCP_EF 0x2E +#define IPDSFIELD_ECT_MASK 0x02 +#define IPDSFIELD_CE_MASK 0x01 + +int dscp [] = + { + IPDSFIELD_DSCP_DEFAULT , + IPDSFIELD_DSCP_CS1 , + IPDSFIELD_DSCP_CS2 , + IPDSFIELD_DSCP_CS3 , + IPDSFIELD_DSCP_CS4 , + IPDSFIELD_DSCP_CS5 , + IPDSFIELD_DSCP_CS6 , + IPDSFIELD_DSCP_CS7 , + IPDSFIELD_DSCP_AF11 , + IPDSFIELD_DSCP_AF12 , + IPDSFIELD_DSCP_AF13 , + IPDSFIELD_DSCP_AF21 , + IPDSFIELD_DSCP_AF22 , + IPDSFIELD_DSCP_AF23 , + IPDSFIELD_DSCP_AF31 , + IPDSFIELD_DSCP_AF32 , + IPDSFIELD_DSCP_AF33 , + IPDSFIELD_DSCP_AF41 , + IPDSFIELD_DSCP_AF42 , + IPDSFIELD_DSCP_AF43 , + IPDSFIELD_DSCP_EF + }; + +const char *dscp_char[]= + { + "Normal", + "CS1", + "CS2", + "CS3", + "CS4", + "CS5", + "CS6", + "CS7", + "Assured Forwarding 11", + "Assured Forwarding 12", + "Assured Forwarding 13", + "Assured Forwarding 21", + "Assured Forwarding 22", + "Assured Forwarding 23", + "Assured Forwarding 31", + "Assured Forwarding 32", + "Assured Forwarding 33", + "Assured Forwarding 41", + "Assured Forwarding 42", + "Assured Forwarding 43", + "Expedited Forwarding" + }; + +int +ACE_TMAIN (int argc , ACE_TCHAR *argv[]) +{ + + if(argc != 3) + { + ACE_DEBUG((LM_DEBUG, "Usage:\n %s [destination host] [destination port]\n\n", argv[0])); + ACE_OS::exit(1); + } + + + char *buf = (char *)ACE_OS::malloc(20 * sizeof(char)); + ACE_OS::strcpy(buf, "Hello"); + + ACE_SOCK_CODgram sock; + ACE_INET_Addr raddr(ACE_OS::atoi(argv[2]), argv[1]); + + sock.open( raddr, ACE_Addr::sap_any, PF_INET, 0, 1); + int opt=0; + int ret =0, ret2=0; + unsigned int i; + for(i=0; i < 21; i++) + { + opt = dscp[i] << 2; + ret = sock.set_option(IPPROTO_IP, IP_TOS, (int *)&opt, (int)sizeof(opt) ); + if(ret == -1){ + ACE_DEBUG((LM_DEBUG, "setsockopt error: %m\n")); + } + + for (int j=0; j<3; j++) + { + ret2 = sock.send(buf, ACE_OS::strlen(buf)); + if(ret2 == -1){ + ACE_DEBUG((LM_DEBUG, "send error: %m\n")); + } + printf("opt: %u dscp: %u, %s, setsockopt returned: %d, send returned: %d\n", opt, opt >> 2, dscp_char[i], ret, ret2); + ACE_OS::sleep(1); + } + } + + ACE_OS::free(buf); + return 0; +} diff --git a/ACE/examples/QOS/Diffserv/run_test.pl b/ACE/examples/QOS/Diffserv/run_test.pl new file mode 100755 index 00000000000..aef0765bac8 --- /dev/null +++ b/ACE/examples/QOS/Diffserv/run_test.pl @@ -0,0 +1,40 @@ +eval '(exit $?0)' && eval 'exec perl -S $0 ${1+"$@"}' + & eval 'exec perl -S $0 $argv:q' + if 0; + +# $Id$ +# -*- perl -*- + +use lib "$ENV{ACE_ROOT}/bin"; +use PerlACE::Run_Test; + +$iorfile = PerlACE::LocalFile ("ior"); + +unlink $iorfile; +$status = 0; + +$CL = new PerlACE::Process ("diffserv_test", "localhost 20002"); +$SV = new PerlACE::Process ("server"); + +$server = $SV->Spawn (); +$SV->TimedWait(2); + +$client = $CL->SpawnWaitKill (200); + +if ($client != 0) { + $time = localtime; + print STDERR "ERROR: client returned $client at $time\n"; + $status = 1; +} + +$server = $SV->WaitKill (400); + +if ($server != 0) { + $time = localtime; + print STDERR "ERROR: server returned $server at $time\n"; + $status = 1; +} + +unlink $iorfile; + +exit $status; diff --git a/ACE/examples/QOS/Diffserv/server.cpp b/ACE/examples/QOS/Diffserv/server.cpp new file mode 100644 index 00000000000..a1030d775e9 --- /dev/null +++ b/ACE/examples/QOS/Diffserv/server.cpp @@ -0,0 +1,163 @@ +//============================================================================= +/** + * @file server.cpp + * + * $Id$ + * + * @author Craig Rodrigues <crodrigu@bbn.com> + * @brief Start a server which listens for UDP packets on a specified port. + */ +//============================================================================= + +#include "ace/Reactor.h" +#include "ace/Process.h" +#include "ace/SOCK_Dgram.h" +#include "ace/INET_Addr.h" +#include "ace/Log_Msg.h" + +// Port used to receive for dgrams. +static u_short port1; + +class Dgram_Endpoint : public ACE_Event_Handler +{ +public: + Dgram_Endpoint (const ACE_INET_Addr &local_addr); + + // = Hook methods inherited from the <ACE_Event_Handler>. + virtual ACE_HANDLE get_handle (void) const; + virtual int handle_input (ACE_HANDLE handle); + virtual int handle_timeout (const ACE_Time_Value & tv, + const void *arg = 0); + virtual int handle_close (ACE_HANDLE handle, + ACE_Reactor_Mask close_mask); + + int send (const char *buf, size_t len, const ACE_INET_Addr &); + // Send the <buf> to the peer. + +private: + ACE_SOCK_Dgram endpoint_; + // Wrapper for sending/receiving dgrams. +}; + +int +Dgram_Endpoint::send (const char *buf, + size_t len, + const ACE_INET_Addr &addr) +{ + return this->endpoint_.send (buf, len, addr); +} + +Dgram_Endpoint::Dgram_Endpoint (const ACE_INET_Addr &local_addr) + : endpoint_ (local_addr) +{ +} + +ACE_HANDLE +Dgram_Endpoint::get_handle (void) const +{ + return this->endpoint_.get_handle (); +} + +int +Dgram_Endpoint::handle_close (ACE_HANDLE handle, + ACE_Reactor_Mask) +{ + ACE_UNUSED_ARG (handle); + + this->endpoint_.close (); + delete this; + return 0; +} + +int +Dgram_Endpoint::handle_input (ACE_HANDLE) +{ + char buf[BUFSIZ]; + ACE_INET_Addr from_addr; + + ssize_t n = this->endpoint_.recv (buf, + sizeof buf, + from_addr); + + if (n == -1) + ACE_ERROR ((LM_ERROR, + "%p\n", + "handle_input")); + else + { + buf[n] = 0; + ACE_DEBUG ((LM_DEBUG, + "Received buf of size %d = %s\n", + n, + buf)); + } + return 0; +} + +int +Dgram_Endpoint::handle_timeout (const ACE_Time_Value &, + const void *) +{ + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) timed out for endpoint\n")); + return 0; +} + +static int +run_test (u_short localport) +{ + ACE_INET_Addr local_addr (localport); + + Dgram_Endpoint *endpoint; + + ACE_NEW_RETURN (endpoint, + Dgram_Endpoint (local_addr), + -1); + + ACE_DEBUG((LM_DEBUG, "Starting server on port %d\n",port1)); + + // Read data from other side. + if (ACE_Reactor::instance ()->register_handler + (endpoint, + ACE_Event_Handler::READ_MASK) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "ACE_Reactor::register_handler"), + -1); + + int ret; + while(1){ + ACE_Time_Value tv(10, 0); + ret = ACE_Reactor::instance ()->handle_events (&tv); + /* Error occurred while handling event */ + if (ret < 0) + { + ACE_ERROR_RETURN ((LM_DEBUG, + "(%P|%t) %p\n", + "handle_events"), + -1); + } + /* We have timed out without handling an event, break out of loop */ + if(ret == 0) break; + } + + return 0; +} + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + // Estabish call backs and socket names. + + port1 = argc > 1 ? ACE_OS::atoi (argv[1]) : ACE_DEFAULT_SERVER_PORT; + + if(argc < 3) + { + run_test (port1); + } + else{ + ACE_DEBUG((LM_DEBUG, "\nUsage:\n %s [port number]\n", argv[0])); + return -1; + } + + return 0; +} diff --git a/ACE/examples/QOS/Makefile.am b/ACE/examples/QOS/Makefile.am new file mode 100644 index 00000000000..7b2d8a15844 --- /dev/null +++ b/ACE/examples/QOS/Makefile.am @@ -0,0 +1,16 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +SUBDIRS = \ + Change_Receiver_FlowSpec \ + Change_Sender_TSpec \ + Diffserv \ + Simple + diff --git a/ACE/examples/QOS/Simple/Fill_ACE_QoS.cpp b/ACE/examples/QOS/Simple/Fill_ACE_QoS.cpp new file mode 100644 index 00000000000..20c03f40fa6 --- /dev/null +++ b/ACE/examples/QOS/Simple/Fill_ACE_QoS.cpp @@ -0,0 +1,99 @@ +// Fill_ACE_QoS.cpp +// $Id$ + +#include "Fill_ACE_QoS.h" + +ACE_RCSID(QOS, Fill_ACE_QoS,"$Id$") + +const iovec Fill_ACE_QoS::iov_ = {0,0}; + +Fill_ACE_QoS::Fill_ACE_QoS (void) +{ + ACE_NEW (this->default_traffic_, + ACE_Flow_Spec (ACE_QOS_NOT_SPECIFIED, + ACE_QOS_NOT_SPECIFIED, + ACE_QOS_NOT_SPECIFIED, + ACE_QOS_NOT_SPECIFIED, + ACE_QOS_NOT_SPECIFIED, + ACE_SERVICETYPE_NOTRAFFIC, + ACE_QOS_NOT_SPECIFIED, + ACE_QOS_NOT_SPECIFIED, + 25, + 1)); +} + +// destructor. +Fill_ACE_QoS::~Fill_ACE_QoS (void) +{} + +int +Fill_ACE_QoS::fill_simplex_receiver_qos (ACE_QoS &ace_qos, + const ACE_CString &recv_flow_name) +{ + ACE_Flow_Spec *recv_flow_spec = 0; + + if (this->map ().find (recv_flow_name, recv_flow_spec) != 0) + ACE_ERROR_RETURN ((LM_DEBUG, + "Unable to find a FlowSpec with name %s", + recv_flow_name.c_str ()), + -1); + ace_qos.receiving_flowspec (recv_flow_spec); + ace_qos.sending_flowspec ((this->default_traffic_)); + ace_qos.provider_specific (Fill_ACE_QoS::iov_); + + return 0; +} + + +int +Fill_ACE_QoS::fill_simplex_sender_qos (ACE_QoS &ace_qos, + const ACE_CString &send_flow_name) +{ + ACE_Flow_Spec *send_flow_spec = 0; + + if (this->map ().find (send_flow_name, send_flow_spec) != 0) + ACE_ERROR_RETURN ((LM_DEBUG, + "Unable to find a FlowSpec with name %s", + send_flow_name.c_str ()), + -1); + + ace_qos.receiving_flowspec ((this->default_traffic_)); + ace_qos.sending_flowspec (send_flow_spec); + ace_qos.provider_specific (Fill_ACE_QoS::iov_); + + return 0; +} + +int +Fill_ACE_QoS::fill_duplex_qos (ACE_QoS &ace_qos, + const ACE_CString &recv_flow_name, + const ACE_CString &send_flow_name) +{ + ACE_Flow_Spec *send_flow_spec = 0; + ACE_Flow_Spec *recv_flow_spec = 0; + + if (this->map ().find (recv_flow_name, recv_flow_spec) != 0) + ACE_ERROR_RETURN ((LM_DEBUG, + "Unable to find a FlowSpec with name %s", + recv_flow_name.c_str ()), + -1); + + if (this->map ().find (send_flow_name, send_flow_spec) != 0) + ACE_ERROR_RETURN ((LM_DEBUG, + "Unable to find a FlowSpec with name %s", + send_flow_name.c_str ()), + -1); + + ace_qos.receiving_flowspec (recv_flow_spec); + ace_qos.sending_flowspec (send_flow_spec); + ace_qos.provider_specific (Fill_ACE_QoS::iov_); + + return 0; +} + +Fill_ACE_QoS::FLOW_SPEC_HASH_MAP& +Fill_ACE_QoS::map (void) +{ + return this->flow_spec_map_; +} + diff --git a/ACE/examples/QOS/Simple/Fill_ACE_QoS.h b/ACE/examples/QOS/Simple/Fill_ACE_QoS.h new file mode 100644 index 00000000000..281b9beb876 --- /dev/null +++ b/ACE/examples/QOS/Simple/Fill_ACE_QoS.h @@ -0,0 +1,75 @@ +/* -*- C++ -*- */ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// ACE_wrappers/examples/QOS +// +// = FILENAME +// Fill_ACE_QoS.h +// +// = AUTHOR +// Vishal Kachroo <vishal@cs.wustl.edu> +// +// ============================================================================ + +#ifndef FILL_ACE_QOS_H +#define FILL_ACE_QOS_H + +#include "ace/SString.h" +#include "ace/Hash_Map_Manager.h" +#include "ace/ACE.h" +#include "ace/Null_Mutex.h" +#include "ace/OS_QoS.h" + +class Fill_ACE_QoS +{ + // TITLE + // This class helps users to add new flow specs and provides + // utility functions for filling up the flow specs for simplex/duplex + // sessions. + +public: + typedef ACE_Hash_Map_Manager <ACE_CString, ACE_Flow_Spec *, ACE_Null_Mutex> FLOW_SPEC_HASH_MAP; + + //Initialization and termination methods. + Fill_ACE_QoS (void); + // constructor. + + ~Fill_ACE_QoS (void); + // destructor. + + int fill_simplex_receiver_qos (ACE_QoS &ace_qos, + const ACE_CString &recv_flow_name); + // To be used by receivers. Fills the receiver qos and sets the + // sender qos to NO_TRAFFIC. + + int fill_simplex_sender_qos (ACE_QoS &ace_qos, + const ACE_CString &send_flow_name); + // To be used by senders. Fills the sender qos and sets the receiver + // qos to NO_TRAFFIC. + + int fill_duplex_qos (ACE_QoS &ace_qos, + const ACE_CString &recv_flow_name, + const ACE_CString &send_flow_name); + // To be used by applications that wish to be both receivers and + // senders. + + FLOW_SPEC_HASH_MAP& map (void); + // Returns the hash map of flowspecs indexed by flowspec name. + +private: + + // The Service Provider is currently set to NULL for all ACE_QoS. + static const iovec iov_; + + // A NO_TRAFFIC flow spec. Senders set the receiving qos to this + // while the receivers set the sending qos to this. + ACE_Flow_Spec *default_traffic_; + + // A list of flowspecs indexed by the flowspec name. + FLOW_SPEC_HASH_MAP flow_spec_map_; +}; + +#endif /* FILL_ACE_QOS_H */ diff --git a/ACE/examples/QOS/Simple/FlowSpec_Dbase.h b/ACE/examples/QOS/Simple/FlowSpec_Dbase.h new file mode 100644 index 00000000000..fc382048c13 --- /dev/null +++ b/ACE/examples/QOS/Simple/FlowSpec_Dbase.h @@ -0,0 +1,52 @@ +/* -*- C++ -*- */ +//$Id$ + +// ============================================================================ +// +// = LIBRARY +// ACE_wrappers/examples/QOS +// +// = FILENAME +// FlowSpec_Dbase.h +// +// = AUTHOR +// Vishal Kachroo <vishal@cs.wustl.edu> +// +// ============================================================================ + +#ifndef FLOWSPEC_DBASE_H +#define FLOWSPEC_DBASE_H + +// This file contains the different FlowSpecs that the QoS enabled +// application uses. Its a good idea to list them all here so the +// application code is clean. + +ACE_Flow_Spec notraffic (ACE_QOS_NOT_SPECIFIED, + ACE_QOS_NOT_SPECIFIED, + ACE_QOS_NOT_SPECIFIED, + ACE_QOS_NOT_SPECIFIED, + ACE_QOS_NOT_SPECIFIED, + ACE_SERVICETYPE_NOTRAFFIC, + ACE_QOS_NOT_SPECIFIED, + ACE_QOS_NOT_SPECIFIED, + 25, + 1); + +ACE_Flow_Spec g711 (9200, + 708, + 18400, + 0, + 0, + ACE_SERVICETYPE_CONTROLLEDLOAD, + 368, + 368, + 25, + 1); + +// The default session address is macarena.cs.wustl.edu. I am using macarena +// as my receiver for testing. +#define DEFAULT_QOS_SESSION_MACHINE "128.252.165.127" +#define DEFAULT_QOS_SESSION_PORT 8001 + +#endif /* FLOWSPEC_DBASE_H */ + diff --git a/ACE/examples/QOS/Simple/Makefile.am b/ACE/examples/QOS/Simple/Makefile.am new file mode 100644 index 00000000000..d86d7cd43eb --- /dev/null +++ b/ACE/examples/QOS/Simple/Makefile.am @@ -0,0 +1,76 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +ACE_BUILDDIR = $(top_builddir) +ACE_ROOT = $(top_srcdir) + +noinst_PROGRAMS = + +## Makefile.QOS_Simple_Receiver.am + +if BUILD_QOS +noinst_PROGRAMS += receiver + +receiver_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) \ + -DACE_HAS_QOS + +receiver_SOURCES = \ + Fill_ACE_QoS.cpp \ + QoS_Signal_Handler.cpp \ + QoS_Util.cpp \ + Receiver_QoS_Event_Handler.cpp \ + receiver.cpp \ + Fill_ACE_QoS.h \ + QoS_Signal_Handler.h \ + QoS_Util.h \ + Receiver_QoS_Event_Handler.h + +receiver_LDADD = \ + $(ACE_BUILDDIR)/ace/QoS/libACE_QoS.la \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif BUILD_QOS + +## Makefile.QOS_Simple_Sender.am + +if BUILD_QOS +noinst_PROGRAMS += sender + +sender_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) \ + -DACE_HAS_QOS + +sender_SOURCES = \ + Fill_ACE_QoS.cpp \ + QoS_Signal_Handler.cpp \ + QoS_Util.cpp \ + Sender_QoS_Event_Handler.cpp \ + sender.cpp \ + Fill_ACE_QoS.h \ + QoS_Signal_Handler.h \ + QoS_Util.h \ + Sender_QoS_Event_Handler.h + +sender_LDADD = \ + $(ACE_BUILDDIR)/ace/QoS/libACE_QoS.la \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif BUILD_QOS + +## Clean up template repositories, etc. +clean-local: + -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.* + -rm -f gcctemp.c gcctemp so_locations *.ics + -rm -rf cxx_repository ptrepository ti_files + -rm -rf templateregistry ir.out + -rm -rf ptrepository SunWS_cache Templates.DB diff --git a/ACE/examples/QOS/Simple/QOS_Simple.mpc b/ACE/examples/QOS/Simple/QOS_Simple.mpc new file mode 100644 index 00000000000..9767bd6fdb9 --- /dev/null +++ b/ACE/examples/QOS/Simple/QOS_Simple.mpc @@ -0,0 +1,25 @@ +// -*- MPC -*- +// $Id$ + +project(*receiver) : aceexe, qos { + exename = receiver + requires += qos + Source_Files { + Fill_ACE_QoS.cpp + QoS_Signal_Handler.cpp + QoS_Util.cpp + receiver.cpp + Receiver_QoS_Event_Handler.cpp + } +} +project(*sender) : aceexe, qos { + exename = sender + requires += qos + Source_Files { + Fill_ACE_QoS.cpp + QoS_Signal_Handler.cpp + QoS_Util.cpp + sender.cpp + Sender_QoS_Event_Handler.cpp + } +} diff --git a/ACE/examples/QOS/Simple/QoS_Signal_Handler.cpp b/ACE/examples/QOS/Simple/QoS_Signal_Handler.cpp new file mode 100644 index 00000000000..a0533bacdbc --- /dev/null +++ b/ACE/examples/QOS/Simple/QoS_Signal_Handler.cpp @@ -0,0 +1,40 @@ +// QoS_Signal_Handler.cpp +// $Id$ + +#include "ace/Log_Msg.h" +#include "QoS_Signal_Handler.h" + +ACE_RCSID(QOS, QoS_Signal_Handler,"$Id$") + +// constructor. +QoS_Signal_Handler::QoS_Signal_Handler (ACE_QoS_Session *qos_session) + : qos_session_ (qos_session) +{ +} + +// Releases the QoS sessions gracefully. +int +QoS_Signal_Handler::handle_signal (int signum, siginfo_t *, ucontext_t*) +{ + + ACE_DEBUG ((LM_DEBUG, + "QoS_Signal_Handler::handle_signal\n")); + + if (signum == SIGINT) + { + ACE_DEBUG ((LM_DEBUG, + "QoS_Signal_Handler::handle_signal SIGINT called\n")); + if (this->qos_session_->close () == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "Unable to close the QoS session.\n"), + -1); + else + ACE_DEBUG ((LM_DEBUG, + "QoS Session with id %d closed successfully.\n", + this->qos_session_->session_id ())); + } + else + ACE_DEBUG ((LM_DEBUG, + "A signal other than SIGINT received.\nIgnoring.\n")); + return 0; +} diff --git a/ACE/examples/QOS/Simple/QoS_Signal_Handler.h b/ACE/examples/QOS/Simple/QoS_Signal_Handler.h new file mode 100644 index 00000000000..35b9f3a19e7 --- /dev/null +++ b/ACE/examples/QOS/Simple/QoS_Signal_Handler.h @@ -0,0 +1,45 @@ +/* -*- C++ -*- */ +// $Id$ + +// ===================================================================== +// +// = LIBRARY +// ACE_wrappers/examples/QOS +// +// = FILENAME +// QoS_Signal_Handler.h +// +// = AUTHOR +// Vishal Kachroo <vishal@cs.wustl.edu> +// +// ===================================================================== + +#ifndef QOS_SIGNAL_HANDLER_H +#define QOS_SIGNAL_HANDLER_H + +#include "ace/Event_Handler.h" +#include "ace/QoS/QoS_Session.h" + +class QoS_Signal_Handler : public ACE_Event_Handler +{ + // TITLE + // This class Handles the SIGINT signal through the Reactor. + // Useful to gracefully release QoS sessions. + +public: + + QoS_Signal_Handler (ACE_QoS_Session *qos_session); + // constructor. + + int handle_signal(int signum, siginfo_t*,ucontext_t*); + // Override this method to implement graceful shutdown. + +private: + + ACE_QoS_Session *qos_session_; + // Session to be gracefully shutdown. + +}; + +#endif /* QOS_SIGNAL_HANDLER_H */ + diff --git a/ACE/examples/QOS/Simple/QoS_Util.cpp b/ACE/examples/QOS/Simple/QoS_Util.cpp new file mode 100644 index 00000000000..0ef3b353248 --- /dev/null +++ b/ACE/examples/QOS/Simple/QoS_Util.cpp @@ -0,0 +1,122 @@ +// QoS_Session_Impl.cpp +// $Id$ + +#define SENDER_PORT 10001 + +#include "ace/Log_Msg.h" +#include "ace/Get_Opt.h" +#include "QoS_Util.h" +#include "ace/OS_NS_strings.h" + +ACE_RCSID(QOS, QoS_Util,"$Id$") + +// constructor. +QoS_Util::QoS_Util (int argc, + ACE_TCHAR *argv[]) + : argc_ (argc), + argv_ (argv), + source_port_ (SENDER_PORT), + protocol_ (IPPROTO_UDP), + multicast_flag_ (0) +{ + ACE_NEW (this->mult_session_addr_, + ACE_INET_Addr (ACE_DEFAULT_MULTICAST_PORT)); + + ACE_NEW (this->dest_addr_, + ACE_INET_Addr (ACE_DEFAULT_SERVER_PORT)); +} + +// destructor. +QoS_Util::~QoS_Util (void) +{ + delete this->mult_session_addr_; + delete this->dest_addr_; +} + +int +QoS_Util::parse_args (void) +{ + ACE_Get_Opt get_opts (this->argc_, this->argv_, ACE_TEXT("m:n:p:P:c")); + int c = 0; + + while ((c = get_opts ()) != -1) + switch (c) + { + case 'm': // multicast session address. + this->multicast_flag_ = 1; + this->mult_session_addr_->set (get_opts.opt_arg ()); + break; + case 'n': // to be used by Senders only to specify the destination. + this->dest_addr_->set (get_opts.opt_arg ()); + break; + case 'p': // protocol. + if (ACE_OS::strcasecmp (get_opts.opt_arg (), ACE_TEXT("tcp")) == 0) + this->protocol_ = IPPROTO_TCP; + else + if (ACE_OS::strcasecmp (get_opts.opt_arg (), ACE_TEXT("udp")) == 0) + this->protocol_ = IPPROTO_UDP; + else + ACE_DEBUG ((LM_DEBUG, + "Unknown protocol specified\n" + "UDP assumed\n")); + break; + case 'P': // sender source port. + this->source_port_ = ACE_OS::atoi (get_opts.opt_arg ()); + break; + case 'h': // display help for different options. + default: + ACE_ERROR_RETURN ((LM_ERROR, + "usage: %s" + " [-m host:port] QoS multicast session address" + " Overides the receiver address specified in the -n option" + " [-n host:port] Use for a unicast sender. " + " Follow by receiver addr" + " [-p tcp|udp] specify protocol to be used" + " [-P port] source sender port" + " [-h] <help>" + "\n", + argv_ [0]), + -1); + } + + // If multicast address is specified then ignore the unicast sender + // destination address and force the protocol to be UDP. + if (this->multicast_flag_ == 1) + { + this->dest_addr_ = this->mult_session_addr_; + this->protocol_ = IPPROTO_UDP; + } + + // Indicates successful parsing of command line. + return 0; +} + +ACE_INET_Addr * +QoS_Util::mult_session_addr (void) const +{ + return this->mult_session_addr_; +} + +ACE_INET_Addr * +QoS_Util::dest_addr (void) const +{ + return this->dest_addr_; +} + +u_short +QoS_Util::source_port (void) const +{ + return this->source_port_; +} + +ACE_Protocol_ID +QoS_Util::protocol (void) const +{ + return this->protocol_; +} + +int +QoS_Util::multicast_flag (void) const +{ + return this->multicast_flag_; +} diff --git a/ACE/examples/QOS/Simple/QoS_Util.h b/ACE/examples/QOS/Simple/QoS_Util.h new file mode 100644 index 00000000000..ae347de68f6 --- /dev/null +++ b/ACE/examples/QOS/Simple/QoS_Util.h @@ -0,0 +1,75 @@ +/* -*- C++ -*- */ +// $Id$ + +// ===================================================================== +// +// = LIBRARY +// ACE_wrappers/examples/QOS +// +// = FILENAME +// QoS_Util.h +// +// = AUTHOR +// Vishal Kachroo <vishal@cs.wustl.edu> +// +// ===================================================================== + +#ifndef QOS_UTIL_H +#define QOS_UTIL_H + +#include "ace/INET_Addr.h" +#include "ace/QoS/QoS_Session.h" + +class QoS_Util +{ + // = TITLE + // This class provides the utility functions like parse_args () + // required by a QoS enabled application. + +public: + + // constructor. + QoS_Util (int argc, ACE_TCHAR *argv[]); + + // destructor. + ~QoS_Util (void); + + // Parse command-line arguments. + int parse_args (void); + + // GET methods. + ACE_INET_Addr *mult_session_addr (void) const; + + ACE_INET_Addr *dest_addr (void) const; + + u_short source_port (void) const; + + ACE_Protocol_ID protocol (void) const; + + int multicast_flag (void) const; + +private: + + // Command line arguments. + int argc_; + ACE_TCHAR **argv_; + + // Multicast session address. + ACE_INET_Addr *mult_session_addr_; + + // Unicast destination address of the receiver. + ACE_INET_Addr *dest_addr_; + + // Source port for the sender. + u_short source_port_; + + // Protocol. + ACE_Protocol_ID protocol_; + + // Multicast Flag. + int multicast_flag_; + +}; + +#endif /* QOS_UTIL_H */ + diff --git a/ACE/examples/QOS/Simple/README b/ACE/examples/QOS/Simple/README new file mode 100644 index 00000000000..13255842932 --- /dev/null +++ b/ACE/examples/QOS/Simple/README @@ -0,0 +1,142 @@ +//$Id$ + +A Regression test for ACE QoS features. +--------------------------------------- + +This test implements a simple Receiver-Sender program that ensures +Quality of Service (QoS) guarantees on the underlying network before +transmitting data. The program tests the ACE QoS APIs/features. The +test works for Winsock2 APIs on Win2K as well as RAPI on Solaris. + + +------------------------------------------------------------------------ +WIN2K : + +Build Requirements : +-------------------- +1. Two Win2K machines. +2. June98 Platform SDK or later. +3. Link with ws2_32.lib + +The test consists of a receiver and a sender. + + The sender is started first (though it is not mandatory) as : + + sender -m merengue.cs.wustl.edu:9091 -P 10004 + + -m: specifies the multicast session address that both client and + server subscribe to for QoS events. + + -p: Protocol to be used. Could be udp or tcp. Default is udp. + + -P: Sender source port. If not specified, DEFAULT_SOURCE_SENDER_PORT + (10001) will be used. + + -h: Displays the help on various options. + +The sample Sender is started next as : + + receiver -m merengue.cs.wustl.edu:9091 + + -m: specifies the multicast session address that both client and + server subscribe to for QoS events. + + -n: Option to be used by senders only to specify the destination + address. This option is overriden if a multicast address is also + specified through the -m option. + + -p: Protocol to be used. Could be udp or tcp. Default is udp. + + -P: Sender source port. If not specified, DEFAULT_SOURCE_SENDER_PORT + (10001) will be used. + + -h: Displays the help on various options. + +On Win2K the user must have administrative access to the machine to +run this program. It seems to be a pre-requisite to opening QoS +sockets. + +The sender and receiver should be run on different Win2K machines. + +The test demonstrates how to GQOS enable an application using the ACE QoS APIs. +It concentrates on the use of various ACE QoS APIs and their correctness. + +------------------------------------------------------------------------------- + +RAPI : + +0. The $ACE_ROOT/include/makeinclude/platform_macros.GNU should include the +following : + +include /project/doc/vishal/ACE_wrappers/include/makeinclude/<appropriate platform macros file eg.platform_sunos5_sunc++.GNU> +PLATFORM_RAPI_CPPFLAGS += -I/project/doc/vishal/rapi/rel4.2a4/rsvpd/ +PLATFORM_RAPI_LIBS += -lrsvp +PLATFORM_RAPI_LDFLAGS += -L/project/doc/vishal/rapi/rel4.2a4/rsvpd/ + +assuming that RAPI library is installed in /project/doc/vishal/rapi/rel4.2a4/ + +1. Compile ACE with + + make rapi=1 + +2. Run the RSVP Daemon on two machines: (merengue.cs and macarena.cs) + + /project/doc/vishal/rapi/rel4.2a4/rsvpd/rsvpd -D + + The current version of the daemon comes with an inbuilt rtap + application to test the various reservation commands and RAPI APIs. + + Typical values for rtap would be : + + dest udp macarena/5000 + sender merengue/5000 [ t 2000000 100000 2000000 512 1024 ] + + dest udp macarena/5000 + reserve wf [ cl 2000000 100000 2000000 512 1024 ] + +3. If RTAP runs fine and the daemons show the debug messages about + RESV, PATH and other RSVP messages, run the QoS example, making sure + that rtap session is released on both machines. + +The test consists of a receiver and a sender. + + The sender is started first (though it is not mandatory) as : + + sender -m macarena.cs.wustl.edu:9091 -P 10004 + + -m: specifies the multicast session address that both client and + server subscribe to for QoS events. + + -p: Protocol to be used. Could be udp or tcp. Default is udp. + + -P: Sender source port. If not specified, DEFAULT_SOURCE_SENDER_PORT + (10001) will be used. + + -h: Displays the help on various options. + +The sample Sender is started next as : + + receiver -m macarena.cs.wustl.edu:9091 + + -m: specifies the multicast session address that both client and + server subscribe to for QoS events. + + -n: Option to be used by senders only to specify the destination + address. This option is overriden if a multicast address is also + specified through the -m option. + + -p: Protocol to be used. Could be udp or tcp. Default is udp. + + -P: Sender source port. If not specified, DEFAULT_SOURCE_SENDER_PORT + (10001) will be used. + + -h: Displays the help on various options. + +------------------------------------------------------------------------------- + +If you run into any problems with this test please contact Vishal +Kachroo <vishal@cs.wustl.edu>. + +This README last updated on 20th July, 2000. + +------------------------------------------------------------------------------- diff --git a/ACE/examples/QOS/Simple/Receiver_QoS_Event_Handler.cpp b/ACE/examples/QOS/Simple/Receiver_QoS_Event_Handler.cpp new file mode 100644 index 00000000000..69258313420 --- /dev/null +++ b/ACE/examples/QOS/Simple/Receiver_QoS_Event_Handler.cpp @@ -0,0 +1,137 @@ +/* -*- C++ -*- */ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// ACE_wrappers/examples/QOS +// +// = FILENAME +// Receiver_QoS_Event_Handler.cpp +// +// = AUTHOR +// Vishal Kachroo <vishal@cs.wustl.edu> +// +// ============================================================================ + +#include "Receiver_QoS_Event_Handler.h" +#include "ace/Log_Msg.h" +#include "ace/OS_NS_string.h" + +// Constructor. +Receiver_QoS_Event_Handler::Receiver_QoS_Event_Handler (void) +{ +} + +Receiver_QoS_Event_Handler::Receiver_QoS_Event_Handler (const ACE_SOCK_Dgram_Mcast_QoS + &dgram_mcast_qos, + ACE_QoS_Session *qos_session) + : dgram_mcast_qos_ (dgram_mcast_qos), + qos_session_ (qos_session) +{ +} + +// Destructor. +Receiver_QoS_Event_Handler::~Receiver_QoS_Event_Handler (void) +{ +} + +// Return the handle of the Dgram_Mcast. This method is called +// internally by the reactor. +ACE_HANDLE +Receiver_QoS_Event_Handler::get_handle (void) const +{ + return this->dgram_mcast_qos_.get_handle (); +} + +// Called when there is a READ activity on the dgram_mcast_qos handle. +int +Receiver_QoS_Event_Handler::handle_input (ACE_HANDLE) +{ + char buf[BUFSIZ]; + + iovec iov; + iov.iov_base = buf; + iov.iov_len = BUFSIZ; + + ACE_OS::memset (iov.iov_base, + 0, + BUFSIZ); + + ACE_DEBUG ((LM_DEBUG, + "Inside handle_input () of Receiver_QoS_Event_Handler ()\n")); + + // Receive message from multicast group. + ssize_t result = + this->dgram_mcast_qos_.recv (&iov, + 1, + this->remote_addr_); + + if (result != -1) + { + ACE_DEBUG ((LM_DEBUG, + "Message Received : %s", + iov.iov_base)); + return 0; + } + else + return -1; +} + +// Called when there is a QoS Event. +int +Receiver_QoS_Event_Handler::handle_qos (ACE_HANDLE fd) +{ + ACE_UNUSED_ARG (fd); + + ACE_DEBUG ((LM_DEBUG, + "\nReceived a QOS event. Inside handle_qos ()\n")); + + // We have received an RSVP event. The following update_qos () call + // calls rapi_dispatch () in case of RAPI and WSAIoctl (GET_QOS) in + // case of W2K. It then does the QoS parameter translation and updates + // the QoS session object with the latest QoS. This call replaces the + // direct call that was being made to WSAIoctl (GET_QOS) here for the + // Win2K example. + + if (this->qos_session_->update_qos () == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "Error in updating QoS\n"), + -1); + else + ACE_DEBUG ((LM_DEBUG, + " Updating QOS succeeds.\n")); + + // Now proactively query the QoS object for QoS. + ACE_QoS ace_get_qos = this->qos_session_->qos (); + + ACE_DEBUG ((LM_DEBUG, + "\nReceiving Flowspec :\t\t\tSending Flowspec :\n\n" + "\tToken Rate = %d\t\t\tToken Rate = %d\n" + "\tToken Bucket Size = %d\t\t\tToken Bucket Size = %d\n" + "\tPeak Bandwidth = %d\t\t\tPeak Bandwidth = %d\n" + "\tLatency = %d\t\t\t\tLatency = %d\n" + "\tDelay Variation = %d\t\t\tDelay Variation = %d\n" + "\tService Type = %d\t\t\tService Type = %d\n" + "\tMax SDU Size = %d\t\t\tMax SDU Size = %d\n" + "\tMinimum Policed Size = %d\t\tMinimum Policed Size = %d\n\n", + ace_get_qos.receiving_flowspec ()->token_rate (), + ace_get_qos.sending_flowspec ()->token_rate (), + ace_get_qos.receiving_flowspec ()->token_bucket_size (), + ace_get_qos.sending_flowspec ()->token_bucket_size (), + ace_get_qos.receiving_flowspec ()->peak_bandwidth (), + ace_get_qos.sending_flowspec ()->peak_bandwidth (), + ace_get_qos.receiving_flowspec ()->latency (), + ace_get_qos.sending_flowspec ()->latency (), + ace_get_qos.receiving_flowspec ()->delay_variation (), + ace_get_qos.sending_flowspec ()->delay_variation (), + ace_get_qos.receiving_flowspec ()->service_type (), + ace_get_qos.sending_flowspec ()->service_type (), + ace_get_qos.receiving_flowspec ()->max_sdu_size (), + ace_get_qos.sending_flowspec ()->max_sdu_size (), + ace_get_qos.receiving_flowspec ()->minimum_policed_size (), + ace_get_qos.sending_flowspec ()->minimum_policed_size ())); + + return 0; + +} diff --git a/ACE/examples/QOS/Simple/Receiver_QoS_Event_Handler.h b/ACE/examples/QOS/Simple/Receiver_QoS_Event_Handler.h new file mode 100644 index 00000000000..874d628e3c1 --- /dev/null +++ b/ACE/examples/QOS/Simple/Receiver_QoS_Event_Handler.h @@ -0,0 +1,61 @@ +/* -*- C++ -*- */ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// ACE_wrappers/examples/QOS +// +// = FILENAME +// Receiver_QoS_Event_Handler.h +// +// = AUTHOR +// Vishal Kachroo <vishal@cs.wustl.edu> +// +// ============================================================================ + +#ifndef RECEIVER_QOS_EVENT_HANDLER_H +#define RECEIVER_QOS_EVENT_HANDLER_H + +#include "ace/Reactor.h" +#include "ace/INET_Addr.h" +#include "ace/Event_Handler.h" +#include "ace/QoS/QoS_Session.h" +#include "ace/QoS/SOCK_Dgram_Mcast_QoS.h" + +ACE_RCSID(Receiver_QoS_Event_Handler, Receiver_QoS_Event_Handler, "$Id$") + + class Receiver_QoS_Event_Handler : public ACE_Event_Handler + { + public: + // = Initialization and Termination methods. + Receiver_QoS_Event_Handler (void); + // Constructor. + + Receiver_QoS_Event_Handler::Receiver_QoS_Event_Handler (const ACE_SOCK_Dgram_Mcast_QoS &dgram_mcast_qos, + ACE_QoS_Session *qos_session); + // Constructor. + + ~Receiver_QoS_Event_Handler (void); + // Destructor. + + virtual ACE_HANDLE get_handle (void) const; + // Override this to return the handle of the Dgram_Mcast + // that we are using. + + virtual int handle_input (ACE_HANDLE fd); + // Handles a READ event. + + virtual int handle_qos (ACE_HANDLE fd); + // Handles a QoS event. + + private: + ACE_SOCK_Dgram_Mcast_QoS dgram_mcast_qos_; + ACE_QoS_Session *qos_session_; + ACE_INET_Addr remote_addr_; + }; + +#endif /* RECEIVER_QOS_EVENT_HANDLER_H */ + + + diff --git a/ACE/examples/QOS/Simple/Sender_QoS_Event_Handler.cpp b/ACE/examples/QOS/Simple/Sender_QoS_Event_Handler.cpp new file mode 100644 index 00000000000..5ee4ccf0f8e --- /dev/null +++ b/ACE/examples/QOS/Simple/Sender_QoS_Event_Handler.cpp @@ -0,0 +1,144 @@ +/* -*- C++ -*- */ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// ACE_wrappers/examples/QOS +// +// = FILENAME +// Sender_QoS_Event_Handler.cpp +// +// = AUTHOR +// Vishal Kachroo <vishal@cs.wustl.edu> +// +// ============================================================================ + +#include "Sender_QoS_Event_Handler.h" +#include "ace/Log_Msg.h" +#include "ace/OS_NS_string.h" + +// Constructor. +Sender_QoS_Event_Handler::Sender_QoS_Event_Handler (void) +{ +} + +// Constructor. +Sender_QoS_Event_Handler::Sender_QoS_Event_Handler (const ACE_SOCK_Dgram_Mcast_QoS + &dgram_mcast_qos, + ACE_QoS_Session *qos_session) + : dgram_mcast_qos_ (dgram_mcast_qos), + qos_session_ (qos_session) +{ +} + +// Destructor. +Sender_QoS_Event_Handler::~Sender_QoS_Event_Handler (void) +{ +} + +// Return the handle of the Dgram_Mcast. This method is called +// internally by the reactor. + +ACE_HANDLE +Sender_QoS_Event_Handler::get_handle (void) const +{ + return this->dgram_mcast_qos_.get_handle (); +} + +// Handle the QoS Event. In this case send data to the receiver +// using WSASendTo() that uses overlapped I/O. + +int +Sender_QoS_Event_Handler::handle_qos (ACE_HANDLE) +{ + ACE_DEBUG ((LM_DEBUG, + "\nReceived a QOS event. Inside handle_qos ()\n")); + + // We have received an RSVP event. The following update_qos () call + // calls rapi_dispatch () in case of RAPI and WSAIoctl (GET_QOS) in + // case of W2K. It then does the QoS parameter translation and updates + // the QoS session object with the latest QoS. This call replaces the + // direct call that was being made to WSAIoctl (GET_QOS) here for the + // Win2K example. + + if (this->qos_session_->update_qos () == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "Error in updating QoS\n"), + -1); + else + ACE_DEBUG ((LM_DEBUG, + " Updating QOS succeeds.\n")); + + // Now proactively query the QoS object for QoS. + ACE_QoS ace_get_qos = this->qos_session_->qos (); + + ACE_DEBUG ((LM_DEBUG, + "\nReceiving Flowspec :\t\t\tSending Flowspec :\n\n" + "\tToken Rate = %d\t\t\tToken Rate = %d\n" + "\tToken Bucket Size = %d\t\t\tToken Bucket Size = %d\n" + "\tPeak Bandwidth = %d\t\t\tPeak Bandwidth = %d\n" + "\tLatency = %d\t\t\t\tLatency = %d\n" + "\tDelay Variation = %d\t\t\tDelay Variation = %d\n" + "\tService Type = %d\t\t\tService Type = %d\n" + "\tMax SDU Size = %d\t\t\tMax SDU Size = %d\n" + "\tMinimum Policed Size = %d\t\tMinimum Policed Size = %d\n\n", + ace_get_qos.receiving_flowspec ()->token_rate (), + ace_get_qos.sending_flowspec ()->token_rate (), + ace_get_qos.receiving_flowspec ()->token_bucket_size (), + ace_get_qos.sending_flowspec ()->token_bucket_size (), + ace_get_qos.receiving_flowspec ()->peak_bandwidth (), + ace_get_qos.sending_flowspec ()->peak_bandwidth (), + ace_get_qos.receiving_flowspec ()->latency (), + ace_get_qos.sending_flowspec ()->latency (), + ace_get_qos.receiving_flowspec ()->delay_variation (), + ace_get_qos.sending_flowspec ()->delay_variation (), + ace_get_qos.receiving_flowspec ()->service_type (), + ace_get_qos.sending_flowspec ()->service_type (), + ace_get_qos.receiving_flowspec ()->max_sdu_size (), + ace_get_qos.sending_flowspec ()->max_sdu_size (), + ace_get_qos.receiving_flowspec ()->minimum_policed_size (), + ace_get_qos.sending_flowspec ()->minimum_policed_size ())); + + // This is SPECIFIC TO WIN2K and should be done in the qos_update function. + +// ACE_QoS ace_get_qos; +// u_long dwBytes; + +// if (ACE_OS::ioctl (this->dgram_mcast_qos_.get_handle (), +// ACE_SIO_GET_QOS, +// ace_get_qos, +// &dwBytes) == -1) +// ACE_ERROR ((LM_ERROR, +// "Error in Qos get ACE_OS::ioctl ()\n" +// "Bytes Returned = %d\n", +// dwBytes)); +// else +// ACE_DEBUG ((LM_DEBUG, +// "Getting QOS using ACE_OS::ioctl () succeeds.\n")); + + char* msg = "Hello sent on a QoS enabled session !!\n"; + iovec iov[1]; + iov[0].iov_base = msg; + iov[0].iov_len = ACE_OS::strlen(msg); + + size_t bytes_sent = 0; + + // Send "Hello" to the QoS session address to which the receiver has + // subscribed. + if (this->dgram_mcast_qos_.send (iov, + 1, + bytes_sent, + 0, + this->qos_session_->dest_addr (), + 0, + 0) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "Error in dgram_mcast.send ()\n"), + -1); + else + ACE_DEBUG ((LM_DEBUG, + "Using ACE_OS::sendto () : Bytes sent : %d", + bytes_sent)); + return 0; +} diff --git a/ACE/examples/QOS/Simple/Sender_QoS_Event_Handler.h b/ACE/examples/QOS/Simple/Sender_QoS_Event_Handler.h new file mode 100644 index 00000000000..b691bbd0615 --- /dev/null +++ b/ACE/examples/QOS/Simple/Sender_QoS_Event_Handler.h @@ -0,0 +1,61 @@ +/* -*- C++ -*- */ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// ACE_wrappers/examples/QOS +// +// = FILENAME +// Sender_QoS_Event_Handler.h +// +// = AUTHOR +// Vishal Kachroo <vishal@cs.wustl.edu> +// +// ============================================================================ + +#ifndef SENDER_QOS_EVENT_HANDLER_H +#define SENDER_QOS_EVENT_HANDLER_H + +#include "ace/Event_Handler.h" +#include "ace/Reactor.h" +#include "ace/INET_Addr.h" +#include "ace/QoS/SOCK_Dgram_Mcast_QoS.h" +#include "ace/QoS/QoS_Session.h" + +//#define MY_DEFPORT 5001 +//#define DEFAULT_MULTICASTGROUP "234.5.6.7" + +ACE_RCSID(Sender_QoS_Event_Handler, Sender_QoS_Event_Handler, "$Id$") + +class Sender_QoS_Event_Handler : public ACE_Event_Handler +{ +public: + // = Initialization and Termination methods. + Sender_QoS_Event_Handler (void); + // Constructor. + + Sender_QoS_Event_Handler::Sender_QoS_Event_Handler (const ACE_SOCK_Dgram_Mcast_QoS + &dgram_mcast_qos, + ACE_QoS_Session *qos_session + ); + // Constructor. + + ~Sender_QoS_Event_Handler (void); + // Destructor. + + virtual ACE_HANDLE get_handle (void) const; + // Override this to return the handle of the Dgram_Mcast + // that we are using. + + virtual int handle_qos (ACE_HANDLE fd); + // Handles a QoS event. Right now, just + // prints a message. + +private: + + ACE_SOCK_Dgram_Mcast_QoS dgram_mcast_qos_; + ACE_QoS_Session *qos_session_; +}; + +#endif /* SENDER_QOS_EVENT_HANDLER_H */ diff --git a/ACE/examples/QOS/Simple/receiver.cpp b/ACE/examples/QOS/Simple/receiver.cpp new file mode 100644 index 00000000000..72381d64f69 --- /dev/null +++ b/ACE/examples/QOS/Simple/receiver.cpp @@ -0,0 +1,301 @@ +/* -*- C++ -*- */ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// ACE_wrappers/examples/QOS +// +// = FILENAME +// server.cpp +// +// = AUTHOR +// Vishal Kachroo <vishal@cs.wustl.edu> +// +// ============================================================================ + +#define QOSEVENT_MAIN + +#include "ace/QoS/QoS_Session.h" +#include "ace/QoS/QoS_Session_Factory.h" +#include "ace/QoS/QoS_Decorator.h" +#include "ace/QoS/SOCK_Dgram_Mcast_QoS.h" + +#include "QoS_Util.h" +#include "Fill_ACE_QoS.h" +#include "QoS_Signal_Handler.h" +#include "Receiver_QoS_Event_Handler.h" + +// To open QOS sockets administrative access is required on the +// machine. Fill in default values for QoS structure. The default +// values were simply choosen from existing QOS templates available +// via WSAGetQosByName. Notice that ProviderSpecific settings are +// being allowed when picking the "default" template but not for +// "well-known" QOS templates. Also notice that since data is only +// flowing from sender to receiver, different flowspecs are filled in +// depending upon whether this application is acting as a sender or +// receiver. + + +// This function fills up the ACE_QoS_Params with the supplied iovec +// and ACE_QoS. + +int +FillQoSParams (ACE_QoS_Params &qos_params, + iovec* iov, + ACE_QoS* qos) +{ + qos_params.callee_data (iov); + qos_params.caller_data (0); + qos_params.socket_qos (qos); + qos_params.group_socket_qos (0); + qos_params.flags (ACE_JL_BOTH); + + return 0; +} + +int +ACE_TMAIN (int argc, ACE_TCHAR * argv[]) +{ + + QoS_Util qos_util(argc, argv); + + if (qos_util.parse_args () == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "Error in parsing args\n"), + -1); + + // This is a multicast application. + if (qos_util.multicast_flag ()) + { + Fill_ACE_QoS fill_ace_qos; + + // The application adds the flow specs that it wants into the + // Fill_ACE_QoS. The Fill_ACE_QoS indexes the flow specs by the + // flow spec names. Here the new flowspec being added is g_711. + ACE_CString g_711 ("g_711"); + + switch (fill_ace_qos.map ().bind (g_711, + new ACE_Flow_Spec (9200, + 708, + 18400, + 0, + 0, + ACE_SERVICETYPE_CONTROLLEDLOAD, + 368, + 368, + 25, + 1))) + { + case 1 : + ACE_ERROR_RETURN ((LM_ERROR, + "Unable to bind the new flow spec\n" + "The Flow Spec name already exists\n"), + -1); + break; + case -1 : + ACE_ERROR_RETURN ((LM_ERROR, + "Unable to bind the new flow spec\n"), + -1); + break; + } + + ACE_DEBUG ((LM_DEBUG, + "g_711 Flow Spec bound successfully\n")); + + // This is a receiver. So we fill in the receiving QoS parameters. + ACE_QoS ace_qos_receiver; + if (fill_ace_qos.fill_simplex_receiver_qos (ace_qos_receiver, + g_711) !=0) + ACE_ERROR_RETURN ((LM_ERROR, + "Unable to fill simplex receiver qos\n"), + -1); + else + ACE_DEBUG ((LM_DEBUG, + "Filled up the Receiver QoS parameters\n")); + + // Opening a new Multicast Datagram. + ACE_SOCK_Dgram_Mcast_QoS dgram_mcast_qos; + + // Multicast Session Address specified by user at command line. + // If this address is not specified, + // <localhost:ACE_DEFAULT_MULTICAST_PORT> is assumed. + ACE_INET_Addr mult_addr (*(qos_util.mult_session_addr ())); + + // Fill the ACE_QoS_Params to be passed to the <ACE_OS::join_leaf> + // through subscribe. + + ACE_QoS_Params qos_params; + FillQoSParams (qos_params, 0, &ace_qos_receiver); + + // Create a QoS Session Factory. + ACE_QoS_Session_Factory session_factory; + + // Ask the factory to create a QoS session. This could be RAPI or + // GQoS based on the parameter passed. + ACE_QoS_Session *qos_session = + session_factory.create_session (); + + // Create a destination address for the QoS session. The same + // address should be used for the subscribe call later. A copy + // is made below only to distinguish the two usages of the dest + // address. + + ACE_INET_Addr dest_addr (mult_addr); + + // A QoS session is defined by the 3-tuple [DestAddr, DestPort, + // Protocol]. Initialize the QoS session. + if (qos_session->open (mult_addr, + IPPROTO_UDP) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "Error in opening the QoS session\n"), + -1); + else + ACE_DEBUG ((LM_DEBUG, + "QoS session opened successfully\n")); + + // The following call opens the Dgram_Mcast and calls the + // <ACE_OS::join_leaf> with the qos_params supplied here. Note + // the QoS session object is passed into this call. This + // subscribes the underlying socket to the passed in QoS + // session. For joining multiple multicast sessions, the + // following subscribe call should be made with different + // multicast addresses and a new QoS session object should be + // passed in for each such call. The QoS session objects can be + // created only through the session factory. Care should be + // taken that the mult_addr for the subscribe() call matches the + // dest_addr of the QoS session object. If this is not done, the + // subscribe call will fail. A more abstract version of + // subscribe will be added that constrains the various features + // of GQoS like different flags etc. + + if (dgram_mcast_qos.subscribe (mult_addr, + qos_params, + 1, + 0, + AF_INET, + // ACE_FROM_PROTOCOL_INFO, + 0, + 0, // ACE_Protocol_Info, + 0, + ACE_OVERLAPPED_SOCKET_FLAG + | ACE_FLAG_MULTIPOINT_C_LEAF + | ACE_FLAG_MULTIPOINT_D_LEAF, + qos_session) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "Error in subscribe\n"), + -1); + else + ACE_DEBUG ((LM_DEBUG, + "Dgram_Mcast subscribe succeeds \n")); + + int nIP_TTL = 25; + char achInBuf [BUFSIZ]; + u_long dwBytes; + + // Should this be abstracted into QoS objects ?? Doesnt seem to have + // to do anything directly with QoS. + if (ACE_OS::ioctl (dgram_mcast_qos.get_handle (), // Socket. + ACE_SIO_MULTICAST_SCOPE, // IO control code. + &nIP_TTL, // In buffer. + sizeof (nIP_TTL), // Length of in buffer. + achInBuf, // Out buffer. + BUFSIZ, // Length of Out buffer. + &dwBytes, // bytes returned. + 0, // Overlapped. + 0) == -1) // Func. + ACE_ERROR ((LM_ERROR, + "Error in Multicast scope ACE_OS::ioctl() \n")); + else + ACE_DEBUG ((LM_DEBUG, + "Setting TTL with Multicast scope ACE_OS::ioctl call succeeds \n")); + + int bFlag = 0; + + // Should this be abstracted into QoS objects ?? Doesnt seem to have + // to do anything directly with QoS. + if (ACE_OS::ioctl (dgram_mcast_qos.get_handle (), // Socket. + ACE_SIO_MULTIPOINT_LOOPBACK, // IO control code. + &bFlag, // In buffer. + sizeof (bFlag), // Length of in buffer. + achInBuf, // Out buffer. + BUFSIZ, // Length of Out buffer. + &dwBytes, // bytes returned. + 0, // Overlapped. + 0) == -1) // Func. + ACE_ERROR ((LM_ERROR, + "Error in Loopback ACE_OS::ioctl() \n")); + else + ACE_DEBUG ((LM_DEBUG, + "Disable Loopback with ACE_OS::ioctl call succeeds \n")); + + // This is a receiver. + qos_session->flags (ACE_QoS_Session::ACE_QOS_RECEIVER); + + ACE_QoS_Manager qos_manager = dgram_mcast_qos.qos_manager (); + + // Set the QoS for the session. Replaces the ioctl () call that + // was being made previously. + if (qos_session->qos (&dgram_mcast_qos, + &qos_manager, + ace_qos_receiver) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "Unable to set QoS\n"), + -1); + else + ACE_DEBUG ((LM_DEBUG, + "Setting QOS succeeds.\n")); + + // Register a signal handler that helps to gracefully close the + // open QoS sessions. + QoS_Signal_Handler qos_signal_handler (qos_session); + + // Register the usual SIGINT signal handler with the Reactor for + // the application to gracefully release the QoS session and + // shutdown. + if (ACE_Reactor::instance ()->register_handler + (SIGINT, &qos_signal_handler) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "Error in registering the Signal Handler.\n"), + -1); + + // Handler to process QoS and Data events for the reciever. + Receiver_QoS_Event_Handler qos_event_handler (dgram_mcast_qos, + qos_session); + + // Decorate the above handler with QoS functionality. + ACE_QoS_Decorator qos_decorator (&qos_event_handler, + qos_session); + + // Initialize the Decorator. + if (qos_decorator.init () != 0) + ACE_ERROR_RETURN ((LM_ERROR, + "QoS Decorator init () failed.\n"), + -1); + + // Register the decorated Event Handler with the Reactor. + if (ACE_Reactor::instance ()->register_handler (&qos_decorator, + ACE_Event_Handler::QOS_MASK | + ACE_Event_Handler::READ_MASK) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "Error in registering the Decorator with the Reactor\n"), + -1); + + + // Start the event loop. + ACE_DEBUG ((LM_DEBUG, + "Running the Event Loop ... \n")); + + ACE_Reactor::instance ()->run_event_loop (); + + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) shutting down server logging daemon\n")); + } + else + ACE_DEBUG ((LM_DEBUG, + "Specify a -m option for multicast application\n")); + return 0; +} + + + diff --git a/ACE/examples/QOS/Simple/sender.cpp b/ACE/examples/QOS/Simple/sender.cpp new file mode 100644 index 00000000000..97e6aafa407 --- /dev/null +++ b/ACE/examples/QOS/Simple/sender.cpp @@ -0,0 +1,315 @@ +/* -*- C++ -*- */ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// ACE_wrappers/examples/QOS +// +// = FILENAME +// client.cpp +// +// = AUTHOR +// Vishal Kachroo <vishal@cs.wustl.edu> +// +// ============================================================================ + + +#include "ace/QoS/QoS_Session.h" +#include "ace/QoS/QoS_Session_Factory.h" +#include "ace/QoS/QoS_Session_Impl.h" +#include "ace/QoS/QoS_Decorator.h" +#include "ace/QoS/SOCK_Dgram_Mcast_QoS.h" + +#include "QoS_Util.h" +#include "Fill_ACE_QoS.h" +#include "QoS_Signal_Handler.h" +#include "Sender_QoS_Event_Handler.h" + +// To open QOS sockets administrative access is required on the +// machine. Fill in default values for QoS structure. The default +// values were simply choosen from existing QOS templates available +// via WSAGetQosByName. Notice that ProviderSpecific settings are +// being allowed when picking the "default" template but not for +// "well-known" QOS templates. Also notice that since data is only +// flowing from sender to receiver, different flowspecs are filled in +// depending upon whether this application is acting as a sender or +// receiver. + +// This function fills up the ACE_QoS_Params with the supplied iovec and ACE_QoS. + +int +FillQoSParams (ACE_QoS_Params &qos_params, + iovec* iov, + ACE_QoS* qos) +{ + qos_params.callee_data (iov); + qos_params.caller_data (0); + qos_params.socket_qos (qos); + qos_params.group_socket_qos (0); + qos_params.flags (ACE_JL_BOTH); + + return 0; +} + +int +ACE_TMAIN (int argc, ACE_TCHAR * argv[]) +{ + + ACE_DEBUG ((LM_DEBUG, + "Sender\n")); + + QoS_Util qos_util(argc, argv); + + if (qos_util.parse_args () == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "Error in parsing args\n"), + -1); + + // This is a multicast application. + if (qos_util.multicast_flag ()) + { + Fill_ACE_QoS fill_ace_qos; + + // The application adds the flow specs that it wants into the + // Fill_ACE_QoS. The Fill_ACE_QoS indexes the flow specs by the flow + // spec names. Here the new flowspec being added is g_711. + ACE_CString g_711 ("g_711"); + + switch (fill_ace_qos.map ().bind (g_711, + new ACE_Flow_Spec (9200, + 708, + 18400, + 0, + 0, + ACE_SERVICETYPE_CONTROLLEDLOAD, + 368, + 368, + 25, + 1))) + { + case 1 : + ACE_ERROR_RETURN ((LM_ERROR, + "Unable to bind the new flow spec\n" + "The Flow Spec name already exists\n"), + -1); + break; + case -1 : + ACE_ERROR_RETURN ((LM_ERROR, + "Unable to bind the new flow spec\n"), + -1); + break; + } + + ACE_DEBUG ((LM_DEBUG, + "g_711 Flow Spec bound successfully\n")); + + // This is a sender. So we fill in the sending QoS parameters. + ACE_QoS ace_qos_sender; + + if (fill_ace_qos.fill_simplex_sender_qos (ace_qos_sender, + g_711) !=0) + ACE_ERROR_RETURN ((LM_ERROR, + "Unable to fill simplex sender qos\n"), + -1); + else + ACE_DEBUG ((LM_DEBUG, + "Filled up the Sender QoS parameters\n")); + + // Opening a new Multicast Datagram. It is absolutely necessary that + // the sender and the receiver subscribe to the same multicast + // addresses to make sure the "multicast sessions" for the two are + // the same. This is used to match the RESV<->PATH states. + ACE_SOCK_Dgram_Mcast_QoS dgram_mcast_qos; + + // Multicast Session Address specified by user at command line. + // If this address is not specified, + // <localhost:ACE_DEFAULT_MULTICAST_PORT> is assumed. + ACE_INET_Addr mult_addr (*(qos_util.mult_session_addr ())); + + // Fill the ACE_QoS_Params to be passed to the <ACE_OS::join_leaf> + // through subscribe. + + ACE_QoS_Params qos_params; + FillQoSParams (qos_params, 0, &ace_qos_sender); + + // Create a QoS Session Factory. + ACE_QoS_Session_Factory session_factory; + + // Ask the factory to create a QoS session. + ACE_QoS_Session *qos_session = + session_factory.create_session (); + + // Create a destination address for the QoS session. The same + // address should be used for the subscribe call later. A copy is + // made below only to distinguish the two usages of the dest + // address. + + ACE_INET_Addr dest_addr (mult_addr); + + // A QoS session is defined by the 3-tuple [DestAddr, DestPort, + // Protocol]. Initialize the QoS session. + if (qos_session->open (mult_addr, + IPPROTO_UDP) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "Error in opening the QoS session\n"), + -1); + else + ACE_DEBUG ((LM_DEBUG, + "QoS session opened successfully\n")); + + // The following call opens the Dgram_Mcast and calls the + // <ACE_OS::join_leaf> with the qos_params supplied here. Note the + // QoS session object is passed into this call. This subscribes the + // underlying socket to the passed in QoS session. For joining + // multiple multicast sessions, the following subscribe call should + // be made with different multicast addresses and a new QoS session + // object should be passed in for each such call. The QoS session + // objects can be created only through the session factory. Care + // should be taken that the mult_addr for the subscribe() call + // matches the dest_addr of the QoS session object. If this is not + // done, the subscribe call will fail. A more abstract version of + // subscribe will be added that constrains the various features of + // GQoS like different flags etc. + + if (dgram_mcast_qos.subscribe (mult_addr, + qos_params, + 1, + 0, + AF_INET, + // ACE_FROM_PROTOCOL_INFO, + 0, + 0, // ACE_Protocol_Info, + 0, + ACE_OVERLAPPED_SOCKET_FLAG + | ACE_FLAG_MULTIPOINT_C_LEAF + | ACE_FLAG_MULTIPOINT_D_LEAF, + qos_session) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "Error in subscribe\n"), + -1); + else + ACE_DEBUG ((LM_DEBUG, + "Dgram_Mcast subscribe succeeds \n")); + + int nIP_TTL = 25; + char achInBuf [BUFSIZ]; + u_long dwBytes; + + // Should this be abstracted into QoS objects ?? Doesnt seem to have + // to do anything directly with QoS. + if (ACE_OS::ioctl (dgram_mcast_qos.get_handle (), // Socket. + ACE_SIO_MULTICAST_SCOPE, // IO control code. + &nIP_TTL, // In buffer. + sizeof (nIP_TTL), // Length of in buffer. + achInBuf, // Out buffer. + BUFSIZ, // Length of Out buffer. + &dwBytes, // bytes returned. + 0, // Overlapped. + 0) == -1) // Func. + ACE_ERROR ((LM_ERROR, + "Error in Multicast scope ACE_OS::ioctl() \n")); + else + ACE_DEBUG ((LM_DEBUG, + "Setting TTL with Multicast scope ACE_OS::ioctl call succeeds \n")); + + int bFlag = 0; + + // Should this be abstracted into QoS objects ?? Doesnt seem to have + // to do anything directly with QoS. + if (ACE_OS::ioctl (dgram_mcast_qos.get_handle (), // Socket. + ACE_SIO_MULTIPOINT_LOOPBACK, // IO control code. + &bFlag, // In buffer. + sizeof (bFlag), // Length of in buffer. + achInBuf, // Out buffer. + BUFSIZ, // Length of Out buffer. + &dwBytes, // bytes returned. + 0, // Overlapped. + 0) == -1) // Func. + ACE_ERROR ((LM_ERROR, + "Error in Loopback ACE_OS::ioctl() \n")); + else + ACE_DEBUG ((LM_DEBUG, + "Disable Loopback with ACE_OS::ioctl call succeeds \n")); + + // This is a sender. + qos_session->flags (ACE_QoS_Session::ACE_QOS_SENDER); + + ACE_QoS_Manager qos_manager = dgram_mcast_qos.qos_manager (); + + // Since we are using RSVP, it is imperative that the client + // application have the option of supplying the source sender + // port for the RSVP messages. A default will be chosen by the + // ACE API if this is not done. + qos_session->source_port (qos_util.source_port ()); + + // Set the QoS for the session. Replaces the ioctl () call that + // was being made previously. + if (qos_session->qos (&dgram_mcast_qos, + &qos_manager, + ace_qos_sender) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "Unable to set QoS\n"), + -1); + else + ACE_DEBUG ((LM_DEBUG, + "Setting QOS succeeds.\n")); + + // Register a signal handler that helps to gracefully close the open + // QoS sessions. + QoS_Signal_Handler qos_signal_handler (qos_session); + + // Register the usual SIGINT signal handler with the Reactor for + // the application to gracefully release the QoS session and + // shutdown. + if (ACE_Reactor::instance ()->register_handler + (SIGINT, &qos_signal_handler) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "Error in registering the Signal Handler.\n"), + -1); + + // Handler to process QoS and Data events for the reciever. + Sender_QoS_Event_Handler qos_event_handler (dgram_mcast_qos, + qos_session); + + // Decorate the above handler with QoS functionality. + ACE_QoS_Decorator qos_decorator (&qos_event_handler, + qos_session); + + // Initialize the Decorator. + if (qos_decorator.init () != 0) + ACE_ERROR_RETURN ((LM_ERROR, + "QoS Decorator init () failed.\n"), + -1); + + // Register the decorated Event Handler with the Reactor. + if (ACE_Reactor::instance ()->register_handler (&qos_decorator, + ACE_Event_Handler::QOS_MASK | + ACE_Event_Handler::READ_MASK) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "Error in registering the Decorator with the Reactor\n"), + -1); + + + + // Start the event loop. + ACE_DEBUG ((LM_DEBUG, + "Running the Event Loop ... \n")); + + ACE_Reactor::instance ()->run_event_loop (); + + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) shutting down server logging daemon\n")); + } + else + ACE_DEBUG ((LM_DEBUG, + "Specify a -m option for multicast application\n")); + return 0; +} + + + + + + + diff --git a/ACE/examples/README b/ACE/examples/README new file mode 100644 index 00000000000..4f2629dfba9 --- /dev/null +++ b/ACE/examples/README @@ -0,0 +1,77 @@ +This directory contains a number of examples that illustrate how to +use the following ACE library components. If you want to see how +to program using ACE, this is the best place to start reading code and +learning the ACE design. + +These examples are roughly divided up according to the class +categories in ACE. For more information on ACE class categories, +please take a look at $ACE_ROOT/ACE-categories. + + . ASX + Illustrate various components in the ADAPTIVE Service + eXecutive, which is a user-level implementation of + System V STREAMS written in C++. + + . Connection + Illustrate how the various Acceptor and Connector + components can be used. + + . IOStream + Illustrate how the ACE IOStreams wrapper works. + + . IPC_SAP + Illustrate the C++ wrappers for Sockets, TLI, UNIX and + Win32 Named Pipes, and UNIX Stream Pipes. + + . Log_Msg + Illustrate some of the features of the logging + facility used in ACE to consolidate debugging and + error report. + + . Logger + This is a simple version of a Server Logging Daemon + that illustrates the "bare-bones" usage of the + Reactor. A more sophisticated set of logging examples + are in the $ACE_ROOT/netsvcs/{client,lib,server} + directories. + + . Mem_Map + Illustrate how the ACE memory-mapped file components + work. + + . Misc + Various miscellaneous tests that illustrate how ACE + utility components work. + + . NT_Service + Illustrates how to write an NT Service using the + ACE_NT_Service class, and how to insert it and remove it + in the SCM, start it, and stop it, and how to run as a + service. + + . Reactor + Contains many examples of how to utilize the ACE + object-oriented event demultiplexer. + + . Service_Configurator + Illustrates the use of the ACE mechanism for + dynamically configuring communication services. + + . Shared_Malloc + Illustrates the use of ACE wrappers for + sophisticated use of the ACE_Malloc shared + memory components. + + . Shared_Memory + Illustrates the use of simple ACE wrappers for + shared memory and memory mapped file. + + . System_V_IPC + Illustrates how to use the ACE wrappers for System V + IPC (i.e., semphores, shared memory, and message + queues). + + . Threads + Illustrates the use of ACE wrappers for threading + and synchronization. + diff --git a/ACE/examples/Reactor/Dgram/.cvsignore b/ACE/examples/Reactor/Dgram/.cvsignore new file mode 100644 index 00000000000..94126b14c4e --- /dev/null +++ b/ACE/examples/Reactor/Dgram/.cvsignore @@ -0,0 +1,4 @@ +codgram +codgram +dgram +dgram diff --git a/ACE/examples/Reactor/Dgram/CODgram.cpp b/ACE/examples/Reactor/Dgram/CODgram.cpp new file mode 100644 index 00000000000..f423c43fb8c --- /dev/null +++ b/ACE/examples/Reactor/Dgram/CODgram.cpp @@ -0,0 +1,254 @@ +// $Id$ + +// Exercise the <ACE_SOCK_CODgram> wrapper along with the +// <ACE_Reactor>. This test simply ping-pongs datagrams back and +// forth between the peer1 and peer2 processes. This test can +// be run in two ways: +// +// 1. Stand-alone -- e.g., +// +// % ./CODgram +// +// which will spawn a child process and run peer1 and peer2 +// in different processes on the same machine. +// +// 2. Distributed -- e.g., +// +// # Peer1 +// % ./CODgram 10002 tango.cs.wustl.edu 10003 peer1 +// +// # Peer1 +// % ./CODgram 10003 tango.cs.wustl.edu 10002 peer2 +// +// which will run peer1 and peer2 in different processes +// on the same or different machines. Note that you MUST +// give the name "peer1" as the final argument to one and +// only one of the programs so that the test will work properly. + +#include "ace/OS_main.h" +#include "ace/OS_NS_string.h" +#include "ace/OS_NS_unistd.h" +#include "ace/Reactor.h" +#include "ace/SOCK_CODgram.h" +#include "ace/INET_Addr.h" +#include "ace/Process.h" +#include "ace/Log_Msg.h" + +ACE_RCSID(Dgram, CODgram, "$Id$") + +// Port used to receive for dgrams. +static u_short port1; + +class Dgram_Endpoint : public ACE_Event_Handler +{ +public: + Dgram_Endpoint (const ACE_INET_Addr &remote_addr, + const ACE_INET_Addr &local_addr); + + // = Hook methods inherited from the <ACE_Event_Handler>. + virtual ACE_HANDLE get_handle (void) const; + virtual int handle_input (ACE_HANDLE handle); + virtual int handle_timeout (const ACE_Time_Value & tv, + const void *arg = 0); + + virtual int handle_close (ACE_HANDLE handle, + ACE_Reactor_Mask close_mask); + + int send (const char *buf, size_t len); + // Send the <buf> to the peer. + +private: + ACE_SOCK_CODgram endpoint_; + // Wrapper for sending/receiving dgrams. +}; + +int +Dgram_Endpoint::send (const char *buf, size_t len) +{ + return this->endpoint_.send (buf, len); +} + +int +Dgram_Endpoint::handle_close (ACE_HANDLE handle, + ACE_Reactor_Mask) +{ + ACE_UNUSED_ARG (handle); + + this->endpoint_.close (); + return 0; +} + +Dgram_Endpoint::Dgram_Endpoint (const ACE_INET_Addr &remote_addr, + const ACE_INET_Addr &local_addr) + : endpoint_ (remote_addr, local_addr) +{ +} + +ACE_HANDLE +Dgram_Endpoint::get_handle (void) const +{ + return this->endpoint_.get_handle (); +} + +int +Dgram_Endpoint::handle_input (ACE_HANDLE) +{ + char buf[BUFSIZ]; + + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) activity occurred on handle %d!\n", + this->endpoint_.get_handle ())); + + ssize_t n = this->endpoint_.recv (buf, sizeof buf); + + if (n == -1) + ACE_ERROR ((LM_ERROR, + "%p\n", + "handle_input")); + else + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) buf of size %d = %*s\n", + n, n, buf)); + return 0; +} + +int +Dgram_Endpoint::handle_timeout (const ACE_Time_Value &, + const void *) +{ + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) timed out for endpoint\n")); + return 0; +} + +static int +run_test (u_short localport, + const ACE_TCHAR *remotehost, + u_short remoteport, + const ACE_TCHAR *peer) +{ + ACE_INET_Addr remote_addr (remoteport, + remotehost); + ACE_INET_Addr local_addr (localport); + + Dgram_Endpoint endpoint (remote_addr, local_addr); + + // Read data from other side. + if (ACE_Reactor::instance ()->register_handler + (&endpoint, + ACE_Event_Handler::READ_MASK) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "ACE_Reactor::register_handler"), + -1); + char buf[BUFSIZ]; + ACE_OS::strcpy (buf, + "Data to transmit"); + size_t len = ACE_OS::strlen (buf); + + // "peer1" is the "initiator." + if (ACE_OS::strncmp (peer, ACE_TEXT("peer1"), 5) == 0) + { + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) sending data\n")); + for (size_t i = 0; i < 20; i++) + { + endpoint.send (buf, len); + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) .\n")); + ACE_OS::sleep (1); + } + } + + for (int i = 0; i < 40; i++) + { + // Wait up to 10 seconds for data. + ACE_Time_Value tv (10, 0); + + if (ACE_Reactor::instance ()->handle_events (tv) <= 0) + ACE_ERROR_RETURN ((LM_DEBUG, + "(%P|%t) %p\n", + "handle_events"), + -1); + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) return from handle events\n")); + + endpoint.send (buf, len); + + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) .\n")); + } + + if (ACE_Reactor::instance ()->remove_handler + (&endpoint, + ACE_Event_Handler::READ_MASK) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "ACE_Reactor::remove_handler"), + -1); + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) exiting\n")); + return 0; +} + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + // Estabish call backs and socket names. + + port1 = argc > 1 ? ACE_OS::atoi (argv[1]) : ACE_DEFAULT_SERVER_PORT; + const ACE_TCHAR *remotehost = argc > 2 ? argv[2] : ACE_DEFAULT_SERVER_HOST; + const u_short port2 = argc > 3 ? ACE_OS::atoi (argv[3]) : port1 + 1; + + // Providing the fourth command line argument indicates we don't + // want to spawn a new process. On Win32, we use this to exec the + // new program. + if (argc > 4) + run_test (port1, + remotehost, + port2, + argv[4]); + else + { + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) local port = %d, remote host = %s, remote port = %d\n", + port1, + remotehost, + port2)); + + ACE_Process_Options options; + options.command_line ("%s %d %s %d %c", + argv[0], + port1, + remotehost, + port2, + 'c'); + + // This has no effect on NT and will spawn a process that exec + // the above run_test function. + options.creation_flags (ACE_Process_Options::NO_EXEC); + + ACE_Process new_process; + + switch (new_process.spawn (options)) + { + case -1: + return -1; + + case 0: + run_test (port1, + remotehost, + port2, + ACE_TEXT("peer1")); + break; + + default: + run_test (port2, + remotehost, + port1, + ACE_TEXT("peer2")); + new_process.wait (); + break; + } + } + + return 0; +} diff --git a/ACE/examples/Reactor/Dgram/Dgram.cpp b/ACE/examples/Reactor/Dgram/Dgram.cpp new file mode 100644 index 00000000000..c4c21e84186 --- /dev/null +++ b/ACE/examples/Reactor/Dgram/Dgram.cpp @@ -0,0 +1,258 @@ +// $Id$ + +// Exercise the <ACE_SOCK_Dgram> wrapper along with the <ACE_Reactor>. +// This test simply ping-pongs datagrams back and forth between the +// peer1 and peer2 processes. This test can be run in two ways: +// +// 1. Stand-alone -- e.g., +// +// % ./Dgram +// +// which will spawn a child process and run peer1 and peer2 +// in different processes on the same machine. +// +// 2. Distributed -- e.g., +// +// # Peer1 +// % ./Dgram 10002 tango.cs.wustl.edu 10003 peer1 +// +// # Peer1 +// % ./Dgram 10003 tango.cs.wustl.edu 10002 peer2 +// +// which will run peer1 and peer2 in different processes +// on the same or different machines. Note that you MUST +// give the name "peer1" as the final argument to one and +// only one of the programs so that the test will work properly. + +#include "ace/OS_main.h" +#include "ace/OS_NS_string.h" +#include "ace/OS_NS_unistd.h" +#include "ace/Reactor.h" +#include "ace/Process.h" +#include "ace/SOCK_Dgram.h" +#include "ace/INET_Addr.h" +#include "ace/Log_Msg.h" + +ACE_RCSID(Dgram, Dgram, "$Id$") + +// Port used to receive for dgrams. +static u_short port1; + +class Dgram_Endpoint : public ACE_Event_Handler +{ +public: + Dgram_Endpoint (const ACE_INET_Addr &local_addr); + + // = Hook methods inherited from the <ACE_Event_Handler>. + virtual ACE_HANDLE get_handle (void) const; + virtual int handle_input (ACE_HANDLE handle); + virtual int handle_timeout (const ACE_Time_Value & tv, + const void *arg = 0); + virtual int handle_close (ACE_HANDLE handle, + ACE_Reactor_Mask close_mask); + + int send (const char *buf, size_t len, const ACE_INET_Addr &); + // Send the <buf> to the peer. + +private: + ACE_SOCK_Dgram endpoint_; + // Wrapper for sending/receiving dgrams. +}; + +int +Dgram_Endpoint::send (const char *buf, + size_t len, + const ACE_INET_Addr &addr) +{ + return this->endpoint_.send (buf, len, addr); +} + +Dgram_Endpoint::Dgram_Endpoint (const ACE_INET_Addr &local_addr) + : endpoint_ (local_addr) +{ +} + +ACE_HANDLE +Dgram_Endpoint::get_handle (void) const +{ + return this->endpoint_.get_handle (); +} + +int +Dgram_Endpoint::handle_close (ACE_HANDLE handle, + ACE_Reactor_Mask) +{ + ACE_UNUSED_ARG (handle); + + this->endpoint_.close (); + delete this; + return 0; +} + +int +Dgram_Endpoint::handle_input (ACE_HANDLE) +{ + char buf[BUFSIZ]; + ACE_INET_Addr from_addr; + + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) activity occurred on handle %d!\n", + this->endpoint_.get_handle ())); + + ssize_t n = this->endpoint_.recv (buf, + sizeof buf, + from_addr); + + if (n == -1) + ACE_ERROR ((LM_ERROR, + "%p\n", + "handle_input")); + else + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) buf of size %d = %*s\n", + n, + n, + buf)); + return 0; +} + +int +Dgram_Endpoint::handle_timeout (const ACE_Time_Value &, + const void *) +{ + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) timed out for endpoint\n")); + return 0; +} + +static int +run_test (u_short localport, + const ACE_TCHAR *remotehost, + u_short remoteport, + const ACE_TCHAR *peer) +{ + ACE_INET_Addr remote_addr (remoteport, + remotehost); + ACE_INET_Addr local_addr (localport); + + Dgram_Endpoint *endpoint; + + ACE_NEW_RETURN (endpoint, + Dgram_Endpoint (local_addr), + -1); + + // Read data from other side. + if (ACE_Reactor::instance ()->register_handler + (endpoint, + ACE_Event_Handler::READ_MASK) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "ACE_Reactor::register_handler"), + -1); + + char buf[BUFSIZ]; + ACE_OS::strcpy (buf, "Data to transmit"); + size_t len = ACE_OS::strlen (buf); + + if (ACE_OS::strncmp (peer, ACE_TEXT("peer1"), 5) == 0) + { + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) sending data\n")); + + for (size_t i = 0; i < 20; i++) + { + endpoint->send (buf, len, remote_addr); + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) .\n")); + ACE_OS::sleep (1); + } + } + + for (int i = 0; i < 40; i++) + { + // Wait up to 10 seconds for data. + ACE_Time_Value tv (10, 0); + + if (ACE_Reactor::instance ()->handle_events (tv) <= 0) + ACE_ERROR_RETURN ((LM_DEBUG, + "(%P|%t) %p\n", + "handle_events"), + -1); + + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) return from handle events\n")); + + endpoint->send (buf, len, remote_addr); + + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) .\n")); + } + + if (ACE_Reactor::instance ()->remove_handler + (endpoint, + ACE_Event_Handler::READ_MASK) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "ACE_Reactor::remove_handler"), + -1); + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) exiting\n")); + return 0; +} + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + // Estabish call backs and socket names. + + port1 = argc > 1 ? ACE_OS::atoi (argv[1]) : ACE_DEFAULT_SERVER_PORT; + const ACE_TCHAR *remotehost = argc > 2 ? argv[2] : ACE_DEFAULT_SERVER_HOST; + const u_short port2 = argc > 3 ? ACE_OS::atoi (argv[3]) : port1 + 1; + + // Providing the fourth command line argument indicate we don't want + // to spawn a new process. On Win32, we use this to exec the new + // program. + if (argc > 4) + run_test (port1, remotehost, port2, argv[4]); + else + { + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) local port = %d, remote host = %s, remote port = %d\n", + port1, + remotehost, + port2)); + + ACE_Process_Options options; + options.command_line ("%s %d %s %d %c", + argv[0], + port1, + remotehost, + port2, + 'c'); + + // This has no effect on NT and will spawn a process that exec + // the above run_test function. + options.creation_flags (ACE_Process_Options::NO_EXEC); + + ACE_Process new_process; + switch (new_process.spawn (options)) + { + case -1: + return -1; + + case 0: + run_test (port1, + remotehost, + port2, + ACE_TEXT("peer1")); + break; + + default: + run_test (port2, + remotehost, + port1, + ACE_TEXT("peer2")); + new_process.wait (); + break; + } + } + return 0; +} diff --git a/ACE/examples/Reactor/Dgram/Makefile.am b/ACE/examples/Reactor/Dgram/Makefile.am new file mode 100644 index 00000000000..797f4b3d75e --- /dev/null +++ b/ACE/examples/Reactor/Dgram/Makefile.am @@ -0,0 +1,51 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +ACE_BUILDDIR = $(top_builddir) +ACE_ROOT = $(top_srcdir) + + +## Makefile.Reactor_Dgram.am +noinst_PROGRAMS = dgram + +dgram_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +dgram_SOURCES = \ + Dgram.cpp + +dgram_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Reactor_Dgram_CO.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS += codgram + +codgram_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +codgram_SOURCES = \ + CODgram.cpp + +codgram_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Clean up template repositories, etc. +clean-local: + -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.* + -rm -f gcctemp.c gcctemp so_locations *.ics + -rm -rf cxx_repository ptrepository ti_files + -rm -rf templateregistry ir.out + -rm -rf ptrepository SunWS_cache Templates.DB diff --git a/ACE/examples/Reactor/Dgram/Reactor_Dgram.mpc b/ACE/examples/Reactor/Dgram/Reactor_Dgram.mpc new file mode 100644 index 00000000000..1040aedc184 --- /dev/null +++ b/ACE/examples/Reactor/Dgram/Reactor_Dgram.mpc @@ -0,0 +1,18 @@ +// -*- MPC -*- +// $Id$ + +project(*CO) : aceexe { + avoids += ace_for_tao + exename = codgram + Source_Files { + CODgram.cpp + } +} + +project : aceexe { + exename = dgram + Source_Files { + Dgram.cpp + } +} + diff --git a/ACE/examples/Reactor/FIFO/.cvsignore b/ACE/examples/Reactor/FIFO/.cvsignore new file mode 100644 index 00000000000..955ffdc75d5 --- /dev/null +++ b/ACE/examples/Reactor/FIFO/.cvsignore @@ -0,0 +1,4 @@ +client +client +server +server diff --git a/ACE/examples/Reactor/FIFO/Makefile.am b/ACE/examples/Reactor/FIFO/Makefile.am new file mode 100644 index 00000000000..5540e860968 --- /dev/null +++ b/ACE/examples/Reactor/FIFO/Makefile.am @@ -0,0 +1,56 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +ACE_BUILDDIR = $(top_builddir) +ACE_ROOT = $(top_srcdir) + +noinst_PROGRAMS = + +## Makefile.Reactor_FIFO_Client.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS += client + +client_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +client_SOURCES = \ + client.cpp + +client_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Makefile.Reactor_FIFO_Server.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS += server + +server_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +server_SOURCES = \ + server.cpp + +server_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Clean up template repositories, etc. +clean-local: + -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.* + -rm -f gcctemp.c gcctemp so_locations *.ics + -rm -rf cxx_repository ptrepository ti_files + -rm -rf templateregistry ir.out + -rm -rf ptrepository SunWS_cache Templates.DB diff --git a/ACE/examples/Reactor/FIFO/Reactor_FIFO.mpc b/ACE/examples/Reactor/FIFO/Reactor_FIFO.mpc new file mode 100644 index 00000000000..072ec5412b8 --- /dev/null +++ b/ACE/examples/Reactor/FIFO/Reactor_FIFO.mpc @@ -0,0 +1,18 @@ +// -*- MPC -*- +// $Id$ + +project(*client) : aceexe { + avoids += ace_for_tao + exename = client + Source_Files { + client.cpp + } +} + +project(*server) : aceexe { + avoids += ace_for_tao + exename = server + Source_Files { + server.cpp + } +} diff --git a/ACE/examples/Reactor/FIFO/client.cpp b/ACE/examples/Reactor/FIFO/client.cpp new file mode 100644 index 00000000000..daa8d3304ad --- /dev/null +++ b/ACE/examples/Reactor/FIFO/client.cpp @@ -0,0 +1,23 @@ +// $Id$ + +#include "ace/FIFO_Send_Msg.h" +#include "ace/Log_Msg.h" +#include "ace/OS_NS_stropts.h" + +ACE_RCSID(FIFO, client, "$Id$") + +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + char buf[] = "hello world"; + ACE_Str_Buf msg (buf, sizeof buf); + + ACE_FIFO_Send_Msg fifo_sender (ACE_DEFAULT_RENDEZVOUS, + O_WRONLY | O_CREAT, + ACE_DEFAULT_FILE_PERMS); + + if (fifo_sender.send (msg) == -1) + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "send error for fifo"), -1); + else + return 0; +} diff --git a/ACE/examples/Reactor/FIFO/server.cpp b/ACE/examples/Reactor/FIFO/server.cpp new file mode 100644 index 00000000000..b6e91dd5046 --- /dev/null +++ b/ACE/examples/Reactor/FIFO/server.cpp @@ -0,0 +1,89 @@ +// $Id$ + +#include "ace/Service_Config.h" +#include "ace/Reactor.h" +#include "ace/Event_Handler.h" +#include "ace/FIFO_Recv_Msg.h" +#include "ace/Log_Msg.h" +#include "ace/OS_NS_unistd.h" +#include "ace/OS_NS_stropts.h" + +ACE_RCSID(FIFO, server, "$Id$") + +class FIFO_Recv_Handler : public ACE_Event_Handler +{ +public: + FIFO_Recv_Handler (void); + ~FIFO_Recv_Handler (void); + + virtual ACE_HANDLE get_handle (void) const; + virtual int handle_input (ACE_HANDLE fd); + +private: + ACE_FIFO_Recv_Msg fifo_reader_; +}; + +FIFO_Recv_Handler::FIFO_Recv_Handler (void) +{ + ACE_OS::unlink (ACE_DEFAULT_RENDEZVOUS); + + // Make sure to open the FIFO with the "persistent" flag enabled + // (which is the default). + if (this->fifo_reader_.open (ACE_DEFAULT_RENDEZVOUS) == -1) + ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("open"))); + + // Register with the Reactor. + if (ACE_Reactor::instance ()->register_handler + (this, ACE_Event_Handler::READ_MASK) == -1) + ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("register_handler"))); +} + +ACE_HANDLE +FIFO_Recv_Handler::get_handle (void) const +{ + return this->fifo_reader_.get_handle (); +} + +FIFO_Recv_Handler::~FIFO_Recv_Handler (void) +{ + this->fifo_reader_.close (); + this->fifo_reader_.remove (); +} + +int +FIFO_Recv_Handler::handle_input (ACE_HANDLE) +{ + char buf[BUFSIZ]; + + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("handle_input\n"))); + + ACE_Str_Buf msg (buf, 0, sizeof buf); + + ssize_t n = this->fifo_reader_.recv (msg); + + if (n < 0) + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("recv")), -1); + else + { + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("msg.len = %d, n = %d\n"), msg.len, n)); + + if (msg.len > 0) + { + // Do some work in here... + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("msg.buf = %C\n"), msg.buf)); + } + return 0; + } +} + +int +ACE_TMAIN (int, ACE_TCHAR *argv[]) +{ + ACE_Service_Config daemon (argv[0]); + + FIFO_Recv_Handler fr_handler; + + ACE_Reactor::instance ()->run_reactor_event_loop (); + + return 0; +} diff --git a/ACE/examples/Reactor/Makefile.am b/ACE/examples/Reactor/Makefile.am new file mode 100644 index 00000000000..24d9217302d --- /dev/null +++ b/ACE/examples/Reactor/Makefile.am @@ -0,0 +1,20 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +SUBDIRS = \ + Dgram \ + FIFO \ + Misc \ + Multicast \ + Ntalker \ + Proactor \ + TP_Reactor \ + WFMO_Reactor + diff --git a/ACE/examples/Reactor/Misc/.cvsignore b/ACE/examples/Reactor/Misc/.cvsignore new file mode 100644 index 00000000000..f7cc1865efa --- /dev/null +++ b/ACE/examples/Reactor/Misc/.cvsignore @@ -0,0 +1,16 @@ +demuxing +demuxing +early_timeouts +early_timeouts +notification +notification +pingpong +pingpong +reactors +reactors +signals_1 +signals_1 +signals_2 +signals_2 +timer_queue +timer_queue diff --git a/ACE/examples/Reactor/Misc/Makefile.am b/ACE/examples/Reactor/Misc/Makefile.am new file mode 100644 index 00000000000..47111585f87 --- /dev/null +++ b/ACE/examples/Reactor/Misc/Makefile.am @@ -0,0 +1,137 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +ACE_BUILDDIR = $(top_builddir) +ACE_ROOT = $(top_srcdir) + +## Makefile.Reactor_Misc_Demuxing.am +noinst_PROGRAMS = demuxing + +demuxing_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +demuxing_SOURCES = \ + test_demuxing.cpp + +demuxing_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Reactor_Misc_Early_Timeouts.am +noinst_PROGRAMS += early_timeouts + +early_timeouts_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +early_timeouts_SOURCES = \ + test_early_timeouts.cpp + +early_timeouts_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Reactor_Misc_Event_Handler_t.am +noinst_PROGRAMS += event_handler_t + +event_handler_t_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +event_handler_t_SOURCES = \ + test_event_handler_t.cpp + +event_handler_t_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Reactor_Misc_Notification.am +noinst_PROGRAMS += notification + +notification_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +notification_SOURCES = \ + notification.cpp + +notification_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Reactor_Misc_Pingpong.am +noinst_PROGRAMS += pingpong + +pingpong_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +pingpong_SOURCES = \ + pingpong.cpp + +pingpong_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Reactor_Misc_Reactors.am +noinst_PROGRAMS += reactors + +reactors_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +reactors_SOURCES = \ + test_reactors.cpp + +reactors_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Reactor_Misc_Signals_1.am +noinst_PROGRAMS += signals_1 + +signals_1_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +signals_1_SOURCES = \ + test_signals_1.cpp + +signals_1_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Reactor_Misc_Signals_2.am +noinst_PROGRAMS += signals_2 + +signals_2_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +signals_2_SOURCES = \ + test_signals_2.cpp + +signals_2_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Reactor_Misc_Timer_Queue.am +noinst_PROGRAMS += timer_queue + +timer_queue_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +timer_queue_SOURCES = \ + test_timer_queue.cpp + +timer_queue_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Clean up template repositories, etc. +clean-local: + -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.* + -rm -f gcctemp.c gcctemp so_locations *.ics + -rm -rf cxx_repository ptrepository ti_files + -rm -rf templateregistry ir.out + -rm -rf ptrepository SunWS_cache Templates.DB diff --git a/ACE/examples/Reactor/Misc/Reactor_Misc.mpc b/ACE/examples/Reactor/Misc/Reactor_Misc.mpc new file mode 100644 index 00000000000..c056a909bd8 --- /dev/null +++ b/ACE/examples/Reactor/Misc/Reactor_Misc.mpc @@ -0,0 +1,57 @@ +// -*- MPC -*- +// $Id$ + +project(*event_handler_t) : aceexe { + exename = event_handler_t + Source_Files { + test_event_handler_t.cpp + } +} +project(*demuxing) : aceexe { + exename = demuxing + Source_Files { + test_demuxing.cpp + } +} +project(*early_timeouts) : aceexe { + exename = early_timeouts + Source_Files { + test_early_timeouts.cpp + } +} +project(*notification) : aceexe { + exename = notification + Source_Files { + notification.cpp + } +} +project(*pingpong) : aceexe { + exename = pingpong + Source_Files { + pingpong.cpp + } +} +project(*reactors) : aceexe { + exename = reactors + Source_Files { + test_reactors.cpp + } +} +project(*signals_1) : aceexe { + exename = signals_1 + Source_Files { + test_signals_1.cpp + } +} +project(*signals_2) : aceexe { + exename = signals_2 + Source_Files { + test_signals_2.cpp + } +} +project(*timer_queue) : aceexe { + exename = timer_queue + Source_Files { + test_timer_queue.cpp + } +} diff --git a/ACE/examples/Reactor/Misc/notification.cpp b/ACE/examples/Reactor/Misc/notification.cpp new file mode 100644 index 00000000000..a04663b28ad --- /dev/null +++ b/ACE/examples/Reactor/Misc/notification.cpp @@ -0,0 +1,385 @@ +// $Id$ + +#include "ace/OS_NS_unistd.h" +#include "ace/Service_Config.h" +#include "ace/Reactor.h" +#include "ace/Thread_Manager.h" +#include "ace/Thread.h" +#include "ace/Signal.h" + +ACE_RCSID(Misc, notification, "$Id$") + +#if defined (ACE_HAS_THREADS) +#if defined (CHORUS) +// Chorus does not have signal, so we'll stop after a number of rounds. +#define MAX_ITERATIONS 3 +#else +#define MAX_ITERATIONS 10000 +#endif /* CHORUS */ + +class Thread_Handler : public ACE_Event_Handler +{ + // = TITLE + // Illustrate how the ACE_Reactor's thread-safe event notification + // mechanism works. + // + // = DESCRIPTION + // Handle timeouts in the main thread via the ACE_Reactor and I/O + // events in a separate thread. Just before the separate I/O + // thread exits it notifies the ACE_Reactor in the main thread + // using the ACE_Reactor's notification mechanism. +public: + Thread_Handler (long delay, + long interval, + size_t n_threads, + size_t max_iterations); + // Constructor. + + Thread_Handler (size_t id, + size_t max_iterations); + + ~Thread_Handler (void); + // Destructor. + + virtual int handle_signal (int signum, + siginfo_t * = 0, + ucontext_t * = 0); + // Handle signals. + + virtual int handle_exception (ACE_HANDLE); + // Print data from main thread. + + virtual int handle_output (ACE_HANDLE); + // Print data from main thread. + + virtual int handle_timeout (const ACE_Time_Value &, + const void *); + // Handle timeout events in the main thread. + + virtual int handle_input (ACE_HANDLE); + // General notification messages to the Reactor. + + virtual int notify (ACE_Time_Value *tv = 0); + // Perform notifications. + + virtual int svc (void); + // Handle I/O events in a separate threads. + +private: + static void *svc_run (void *); + // Glues C++ to C thread library functions. + + size_t id_; + // ID passed in by Thread_Handler constructor. + + size_t iterations_; + + static sig_atomic_t shutdown_; + // Shutting down. + + // = Timing variables. + // Delay factor for timer-driven I/O. + static ACE_Time_Value delay_; + + // Interval factor for Event_Handler timer. + static ACE_Time_Value interval_; +}; + +// Shutdown flag. +sig_atomic_t Thread_Handler::shutdown_ = 0; + +// Delay factor for timer-driven I/O. +ACE_Time_Value Thread_Handler::delay_; + +// Interval factor for Event_Handler timer. +ACE_Time_Value Thread_Handler::interval_; + +Thread_Handler::Thread_Handler (size_t id, + size_t max_iterations) + : id_ (id), + iterations_ (max_iterations) +{ +} + +Thread_Handler::~Thread_Handler (void) +{ + // Cleanup resources so that we don't crash and burn when shutdown. + ACE_Event_Handler::remove_stdin_handler (ACE_Reactor::instance (), + ACE_Thread_Manager::instance ()); + ACE_Reactor::instance ()->cancel_timer (this); +} + +Thread_Handler::Thread_Handler ( + long delay, + long interval, + size_t n_threads, + size_t max_iterations) + : iterations_ (max_iterations) +{ + ACE_Sig_Set sig_set; + + sig_set.sig_add (SIGQUIT); + sig_set.sig_add (SIGINT); + + delay_.set (delay); + interval_.set (interval); + this->id_ = 0; + + if (ACE_Event_Handler::register_stdin_handler (this, + ACE_Reactor::instance (), + ACE_Thread_Manager::instance ()) == -1) + ACE_ERROR ((LM_ERROR, + "%p\n", + "register_stdin_handler")); + else if (ACE_Reactor::instance ()->register_handler (sig_set, + this) == -1) + ACE_ERROR ((LM_ERROR, + "(%t) %p\n", + "register_handler")); + else if (ACE_Reactor::instance ()->schedule_timer + (this, + 0, + Thread_Handler::delay_, + Thread_Handler::interval_) == -1) + ACE_ERROR ((LM_ERROR, + "(%t) %p\n", + "schedule_timer")); + + // Set up this thread's signal mask to block all the signal in the + // <sig_set>, which is inherited by the threads it spawns. + ACE_Sig_Guard guard (&sig_set); + + // Create N new threads of control Thread_Handlers. + + for (size_t i = 0; i < n_threads; i++) + { + Thread_Handler *th; + + ACE_NEW (th, + Thread_Handler (i + 1, + this->iterations_)); + + if (ACE_Thread::spawn (reinterpret_cast<ACE_THR_FUNC> (&Thread_Handler::svc_run), + reinterpret_cast<void *> (th), + THR_NEW_LWP | THR_DETACHED) != 0) + ACE_ERROR ((LM_ERROR, + "%p\n", + "ACE_Thread::spawn")); + } + + // The destructor of <guard> unblocks the signal set so that only + // this thread receives them! +} + +int +Thread_Handler::notify (ACE_Time_Value *timeout) +{ + // Just do something to test the ACE_Reactor's multi-thread + // capabilities... + + if (ACE_Reactor::instance ()->notify + (this, + ACE_Event_Handler::EXCEPT_MASK, + timeout) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "(%t) %p\n", + "notification::notify:exception"), + -1); + else if (ACE_Reactor::instance ()->notify + (this, + ACE_Event_Handler::WRITE_MASK, + timeout) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "(%t) %p\n", + "notification::notify:write"), + -1); + return 0; +} + +// Test stdin handling that uses <select> to demultiplex HANDLEs. +// Input is only handled by the main thread. + +int +Thread_Handler::handle_input (ACE_HANDLE handle) +{ + char buf[BUFSIZ]; + ssize_t n = ACE_OS::read (handle, buf, sizeof buf); + + if (n > 0) + { + ACE_DEBUG ((LM_DEBUG, + "input to (%t) %*s", + n, + buf)); + + ACE_DEBUG ((LM_DEBUG, + "%d more input to kill\n", + this->iterations_)); + + // Only wait up to 10 milliseconds to notify the Reactor. + ACE_Time_Value timeout (0, + 10 * 1000); + + if (this->notify (&timeout) == -1) + ACE_ERROR ((LM_DEBUG, + "(%t), %p\n", + "notification::handle_input:notify")); + return 0; + } + else + return -1; +} + +// Perform a task that will test the ACE_Reactor's multi-threading +// capabilities in separate threads. + +int +Thread_Handler::svc (void) +{ + ACE_Time_Value sleep_timeout (0, + // Transform this into microseconds and divide by 2. + (Thread_Handler::interval_.sec () * ACE_ONE_SECOND_IN_USECS) / 2); + + for (int i = this->iterations_; + i > 0; + --i) + { + if (this->shutdown_ != 0) + break; + + // Block for delay_.secs () / 2, then notify the Reactor. + ACE_OS::sleep (sleep_timeout); + + // Wait up to 10 milliseconds to notify the Reactor. + ACE_Time_Value timeout (0, + 10 * 1000); + if (this->notify (&timeout) == -1) + ACE_ERROR ((LM_ERROR, + "(%t) %p\n", + "notify")); + } + + ACE_Reactor::instance ()->remove_handler (this, + ALL_EVENTS_MASK); + ACE_DEBUG ((LM_DEBUG, + "(%t) exiting svc\n")); + return 0; +} + +// Test signal handling. + +int +Thread_Handler::handle_signal (int signum, siginfo_t *, ucontext_t *) +{ + // @@ Note that this code is not portable to all OS platforms since + // it uses print statements within signal handler context. + ACE_DEBUG ((LM_DEBUG, + "(%t) received signal %S\n", + signum)); + + switch (signum) + { + case SIGINT: + case SIGQUIT: + ACE_ERROR ((LM_ERROR, + "(%t) ******************** shutting down %n on signal %S\n", + signum)); + this->shutdown_ = 1; + ACE_Reactor::end_event_loop(); + } + return 0; +} + +int +Thread_Handler::handle_timeout (const ACE_Time_Value &time, const void *) +{ + ACE_DEBUG ((LM_DEBUG, + "(%t) received timeout at (%u, %u), iterations = %d\n", + time.sec (), + time.usec (), + this->iterations_)); + + if (--this->iterations_ <= 0 + || Thread_Handler::interval_.sec () == 0) + ACE_Reactor::end_event_loop (); + + return 0; +} + +// Called by the ACE_Reactor when it receives a notification. + +int +Thread_Handler::handle_exception (ACE_HANDLE) +{ + ACE_DEBUG ((LM_DEBUG, + "(%t) exception to id %d, iteration = %d\n", + this->id_, + this->iterations_)); + return 0; +} + +// Called by the ACE_Reactor when it receives a notification. + +int +Thread_Handler::handle_output (ACE_HANDLE) +{ + ACE_DEBUG ((LM_DEBUG, + "(%t) output to id %d, iteration = %d\n", + this->id_, + // This decrement must come last since + // <handle_exception> is called before <handle_output>! + this->iterations_--)); + return 0; +} + +// "Shim" function that integrates C thread API with C++. + +void * +Thread_Handler::svc_run (void *eh) +{ + Thread_Handler *this_handler = + reinterpret_cast<Thread_Handler *> (eh); + + if (this_handler->svc () == 0) + return 0; + else + return reinterpret_cast<void *> (-1); +} + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + ACE_LOG_MSG->open (argv[0]); + + if (argc < 4) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("usage: %s delay interval n_threads [iterations]\n"), + argv[0])); + ACE_OS::exit (1); + } + + int delay = ACE_OS::atoi (argv[1]); + int interval = ACE_OS::atoi (argv[2]); + size_t n_threads = ACE_OS::atoi (argv[3]); + size_t max_iterations = argc > 4 ? ACE_OS::atoi (argv[4]) : MAX_ITERATIONS; + + Thread_Handler thr_handler (delay, + interval, + n_threads, + max_iterations); + + ACE_Reactor::instance ()->run_reactor_event_loop (); + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("exiting from main\n"))); + return 0; +} +#else +int +main (int, char *[]) +{ + ACE_ERROR_RETURN ((LM_ERROR, + "threads must be supported to run this application\n"), -1); +} +#endif /* ACE_HAS_THREADS */ diff --git a/ACE/examples/Reactor/Misc/pingpong.cpp b/ACE/examples/Reactor/Misc/pingpong.cpp new file mode 100644 index 00000000000..f4a3bc0630e --- /dev/null +++ b/ACE/examples/Reactor/Misc/pingpong.cpp @@ -0,0 +1,302 @@ +// $Id$ + +/* Simple program that illustrates many features of the ACE_Reactor: + + 1. I/O event demultiplexing + 2. Signal-based demultiplexing + 3. Timer-based demultiplexing + + To test this program, compile it and then execute it as follows: + + % ./pingpong hello + + You should see lots of the following output: + + writing <4> [7860] + writing <4> [7860] + writing <4> [7860] + writing <4> [7860] + reading <5> (7860) [1] = hello + writing <4> [7860] + writing <5> [7861] + reading <4> (7861) [2] = hello + reading <5> (7860) [2] = hello + writing <4> [7860] + writing <5> [7861] + reading <4> (7861) [3] = hello + reading <5> (7860) [3] = hello + + After 10 seconds you'll see the following: + + ./pingpong: shutting down tester (pid = 7861) + ./pingpong: shutting down tester (pid = 7860) + + and the program will stop. If you'd like to + stop it earlier, just hit the control-C sequence + and you'll see the same messages. */ + +#include "ace/Reactor.h" +#include "ace/Pipe.h" +#include "ace/Log_Msg.h" +#include "ace/ACE.h" +#include "ace/Test_and_Set.h" +#include "ace/OS_NS_string.h" +#include "ace/Null_Mutex.h" +#include "ace/OS_NS_unistd.h" +#if defined (ACE_WIN32) || defined (CHORUS) +# include "ace/Barrier.h" +# include "ace/Thread.h" +#endif + +ACE_RCSID(Misc, pingpong, "$Id$") + +class Ping_Pong : public ACE_Test_and_Set<ACE_Null_Mutex, sig_atomic_t> +{ +public: + Ping_Pong (char b[], ACE_HANDLE f); + virtual ACE_HANDLE get_handle (void) const; + virtual int handle_input (ACE_HANDLE); + virtual int handle_output (ACE_HANDLE); + virtual int handle_timeout (const ACE_Time_Value &, + const void *); + virtual int handle_close (ACE_HANDLE handle, + ACE_Reactor_Mask close_mask); +private: + char buf_[BUFSIZ]; + // Buffer to send. + + size_t buflen_; + // Length of the buffer to send. + + int pid_; + // Process ID. + + ACE_HANDLE handle_; + // Open handle. +}; + +Ping_Pong::Ping_Pong (char b[], ACE_HANDLE f) + : buflen_ (ACE_OS::strlen (b) + 1 + (2 * sizeof (int))), + pid_ (ACE_OS::getpid ()), + handle_ (f) +{ + *((int *) this->buf_) = (int) this->pid_; + *((int *) (this->buf_ + sizeof (int))) = 0; + ACE_OS::strcpy (this->buf_ + (2 * sizeof (int)), b); + this->buf_[this->buflen_ - 1] = '\n'; + this->buf_[this->buflen_] = '\0'; +} + +ACE_HANDLE +Ping_Pong::get_handle (void) const +{ + return this->handle_; +} + +int +Ping_Pong::handle_close (ACE_HANDLE, + ACE_Reactor_Mask) +{ + delete this; // Cleanup when we're removed from the reactor. + return 0; +} + +int +Ping_Pong::handle_input (ACE_HANDLE) +{ +#if defined (ACE_HAS_STREAM_PIPES) + // We can rely on record-oriented reads... + + ssize_t n = ACE::recv (this->handle_, this->buf_, this->buflen_); + + if (n != (ssize_t) this->buflen_) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("(%P|%t) reading [%d] %p\n"), + handle_, + ACE_TEXT ("read")), + -1); + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) reading <%d> (%d) [%d] = %C\n"), + this->handle_, + *(int *) this->buf_, + *(int *) (this->buf_ + sizeof (int)), + this->buf_ + (2 * sizeof (int)))); +#else + ssize_t n = ACE::recv (this->handle_, + this->buf_, + this->buflen_); + if (n == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("[%d] %p\n"), + handle_, + ACE_TEXT ("read")), + -1); + n -= (2 * sizeof (int)); + char *buf = this->buf_ + (2 * sizeof (int)); + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) reading <%d> = %*C\n"), + this->handle_, + n, + buf)); +#endif /* ACE_HAS_STREAM_PIPES */ + return 0; +} + +int +Ping_Pong::handle_output (ACE_HANDLE) +{ +#if defined (ACE_HAS_STREAM_PIPES) + // We can rely on record-oriented reads... + + (*(int *) (this->buf_)) = this->pid_; + (*(int *) (this->buf_ + sizeof (int)))++; + if (ACE::send (this->handle_, + this->buf_, + this->buflen_) == -1) + return -1; + else + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) writing <%d> [%d]\n"), + this->handle_, + this->pid_)); + return 0; + } +#else + if (ACE::send (this->handle_, + this->buf_, + this->buflen_) == -1) + return -1; + else + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) writing <%d>\n"), + this->handle_)); + return 0; + } +#endif /* ACE_HAS_STREAM_PIPES */ +} + +int +Ping_Pong::handle_timeout (const ACE_Time_Value &, + const void *) +{ + this->set (1); + return 0; +} + +// Contains the string to "pingpong" back and forth... +static ACE_TCHAR *string_name; + +// Wait for 10 seconds and then shut down. +static const ACE_Time_Value SHUTDOWN_TIME (10); + +static void +run_svc (ACE_HANDLE handle) +{ + Ping_Pong *callback = 0; + ACE_NEW (callback, + Ping_Pong (ACE_TEXT_ALWAYS_CHAR (string_name), + handle)); + + ACE_Reactor reactor; + + // Register the callback object for the various I/O, signal, and + // timer-based events. + + if (reactor.register_handler (callback, + ACE_Event_Handler::READ_MASK + | ACE_Event_Handler::WRITE_MASK) == -1 +#if !defined (CHORUS) + || reactor.register_handler (SIGINT, + callback) == -1 +#endif /* CHORUS */ + || reactor.schedule_timer (callback, + 0, + SHUTDOWN_TIME) == -1) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("reactor"))); + ACE_OS::exit (1); + } + + // Main event loop (one per process). + + while (callback->is_set () == 0) + if (reactor.handle_events () == -1) + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("handle_events"))); +} + +#if defined (ACE_WIN32) || defined (CHORUS) +static ACE_Barrier barrier (3); + +static void * +worker (void *arg) +{ + ACE_HANDLE handle = (ACE_HANDLE) arg; + + run_svc (handle); + + // Wait for the threads to exit. + barrier.wait (); + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) %n: shutting down tester\n"))); + return 0; +} +#endif /* ACE_WIN32 */ + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + if (argc != 2) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("usage: pingpong <string>\n")), + -1); + + ACE_LOG_MSG->open (argv[0]); + + string_name = argv[1]; + + ACE_HANDLE handles[2]; + + // Create a pipe and initialize the handles. + ACE_Pipe pipe (handles); + +#if defined (ACE_WIN32) || defined (CHORUS) + if (ACE_Thread::spawn (ACE_THR_FUNC (worker), + (void *) handles[0], + THR_DETACHED) == -1 + || ACE_Thread::spawn (ACE_THR_FUNC (worker), + (void *) handles[1], + THR_DETACHED) == -1) + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("%p\n%a"), + ACE_TEXT ("spawn"), + 1)); + barrier.wait (); +#else + pid_t pid = ACE_OS::fork (argv[0]); + + if (pid == -1) + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("%p\n%a"), + ACE_TEXT ("fork"), + 1)); + run_svc (handles[pid == 0]); + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) %n: shutting down tester\n"))); +#endif /* ACE_WIN32 */ + + if (pipe.close () == -1) + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("close"))); + return 0; +} diff --git a/ACE/examples/Reactor/Misc/test_demuxing.cpp b/ACE/examples/Reactor/Misc/test_demuxing.cpp new file mode 100644 index 00000000000..6badd849757 --- /dev/null +++ b/ACE/examples/Reactor/Misc/test_demuxing.cpp @@ -0,0 +1,384 @@ +// $Id$ + +// Perform an extensive test of all the ACE_Reactor's event handler +// dispatching mechanisms. These mechanisms illustrate how I/O, +// timeout, and signal events, as well as ACE_Message_Queues, can all +// be handled within the same demultiplexing and dispatching +// framework. In addition, this example illustrates how to use the +// ACE_Reactor for devices that perform I/O via signals (such as SVR4 +// message queues). + +#include "ace/ACE.h" +#include "ace/Service_Config.h" +#include "ace/Reactor.h" +#include "ace/Task.h" +#include "ace/Reactor_Notification_Strategy.h" +#include "ace/Signal.h" +#include "ace/OS_NS_fcntl.h" +#include "ace/OS_NS_unistd.h" + +ACE_RCSID(Misc, test_demuxing, "$Id$") + +// Default is to have a 2 second timeout. +static int timeout = 2; + +class Sig_Handler : public ACE_Event_Handler +{ + // = TITLE + // This class illustrates how to handle signal-driven I/O using + // the <ACE_Reactor> framework. Note that signals may be caught + // and processed without requiring the use of global signal + // handler functions or global signal handler data. +public: + Sig_Handler (void); + virtual ACE_HANDLE get_handle (void) const; + virtual int handle_input (ACE_HANDLE); + virtual int shutdown (ACE_HANDLE, ACE_Reactor_Mask); + virtual int handle_signal (int signum, siginfo_t * = 0, + ucontext_t * = 0); + +private: + ACE_HANDLE handle_; +}; + +// A dummy_handle is required to reserve a slot in the ACE_Reactor's +// descriptor table. + +Sig_Handler::Sig_Handler (void) +{ + // Assign the Sig_Handler a dummy I/O descriptor. Note that even + // though we open this file "Write Only" we still need to use the + // ACE_Event_Handler::NULL_MASK when registering this with the + // ACE_Reactor (see below). + this->handle_ = ACE_OS::open (ACE_DEV_NULL, O_WRONLY); + ACE_ASSERT (this->handle_ != ACE_INVALID_HANDLE); + + // Register signal handler object. Note that NULL_MASK is used to + // keep the ACE_Reactor from calling us back on the "/dev/null" + // descriptor. NULL_MASK just reserves a "slot" in the Reactor's + // internal demuxing table, but doesn't cause it to dispatch the + // event handler directly. Instead, we use the signal handler to do + // this. + ACE_Reactor_Mask mask = ACE_Event_Handler::NULL_MASK; + if (ACE_Reactor::instance ()->register_handler + (this, + mask) == -1) + ACE_ERROR ((LM_ERROR, + "%p\n%a", + "register_handler", + 1)); + + // Create a sigset_t corresponding to the signals we want to catch. + ACE_Sig_Set sig_set; + + sig_set.sig_add (SIGINT); + sig_set.sig_add (SIGQUIT); + sig_set.sig_add (SIGALRM); + + // Register the signal handler object to catch the signals. + if (ACE_Reactor::instance ()->register_handler + (sig_set, this) == -1) + ACE_ERROR ((LM_ERROR, + "%p\n%a", + "register_handler", + 1)); +} + +// Called by the ACE_Reactor to extract the handle. + +ACE_HANDLE +Sig_Handler::get_handle (void) const +{ + return this->handle_; +} + +// In a real application, this method would be where the read on the +// signal-driven I/O device would occur asynchronously. For now we'll +// just print a greeting to let you know that everything is working +// properly! + +int +Sig_Handler::handle_input (ACE_HANDLE) +{ + ACE_DEBUG ((LM_DEBUG, + "(%t) handling asynchonrous input...\n")); + return 0; +} + +// In a real application, this method would do any cleanup activities +// required when shutting down the I/O device. + +int +Sig_Handler::shutdown (ACE_HANDLE, ACE_Reactor_Mask) +{ + ACE_DEBUG ((LM_DEBUG, + "(%t) closing down Sig_Handler...\n")); + return 0; +} + +// This method handles all the signals that are being caught by this +// object. In our simple example, we are simply catching SIGALRM, +// SIGINT, and SIGQUIT. Anything else is logged and ignored. Note +// that the ACE_Reactor's signal handling mechanism eliminates the +// need to use global signal handler functions and data. + +int +Sig_Handler::handle_signal (int signum, siginfo_t *, ucontext_t *) +{ + switch (signum) + { +#if !defined (ACE_WIN32) + case SIGALRM: + // Rearm the alarm. + ACE_OS::alarm (4); + break; +#endif /* !ACE_WIN32 */ + case SIGINT: + // Tell the ACE_Reactor to enable the ready bit for + // this->handle_. The ACE_Reactor will subsequently call the + // <Sig_Handler::handle_input> method from within its event + // loop, i.e., the behavior triggered by the signal is handled + // in the main event loop, rather than in the signal handler. + return ACE_Reactor::instance ()->ready_ops + (this->handle_, + ACE_Event_Handler::READ_MASK, + ACE_Reactor::ADD_MASK); +#if defined (ACE_WIN32) + case SIGTERM: +#else + case SIGQUIT: +#endif /* ACE_WIN32 */ + ACE_Reactor::end_event_loop (); + break; + default: + ACE_ERROR_RETURN ((LM_ERROR, "invalid signal"), -1); + break; + /* NOTREACHED */ + } + return 0; +} + +class STDIN_Handler : public ACE_Event_Handler +{ + // = TITLE + // This class illustrates that the ACE_Reactor can handle signals, + // STDIO, and timeouts using the same mechanisms. +public: + STDIN_Handler (void); + ~STDIN_Handler (void); + virtual int handle_input (ACE_HANDLE); + virtual int handle_timeout (const ACE_Time_Value &, + const void *arg); +}; + +STDIN_Handler::STDIN_Handler (void) +{ + if (ACE_Event_Handler::register_stdin_handler (this, + ACE_Reactor::instance (), + ACE_Thread_Manager::instance ()) == -1) + ACE_ERROR ((LM_ERROR, + "%p\n", + "register_stdin_handler")); + + // Register the <STDIN_Handler> to be dispatched once every + // <timeout> seconds starting in <timeout> seconds. This example + // uses the "interval timer" feature of the <ACE_Reactor>'s timer + // queue. + else if (ACE_Reactor::instance ()->schedule_timer + (this, + 0, + ACE_Time_Value (timeout), + ACE_Time_Value (timeout)) == -1) + ACE_ERROR ((LM_ERROR, + "%p\n%a", + "schedule_timer", + 1)); +} + +STDIN_Handler::~STDIN_Handler (void) +{ + if (ACE_Event_Handler::remove_stdin_handler (ACE_Reactor::instance (), + ACE_Thread_Manager::instance ()) == -1) + ACE_ERROR ((LM_ERROR, + "%p\n", + "remove_stdin_handler")); + else if (ACE_Reactor::instance ()->cancel_timer + (this) == -1) + ACE_ERROR ((LM_ERROR, + "%p\n%a", + "cancel_timer", + 1)); +} + +int +STDIN_Handler::handle_timeout (const ACE_Time_Value &tv, + const void *) +{ + ACE_DEBUG ((LM_DEBUG, + "(%t) timeout occurred at %d sec, %d usec\n", + tv.sec (), + tv.usec ())); + return 0; +} + +// Read from input handle and write to stdout handle. + +int +STDIN_Handler::handle_input (ACE_HANDLE handle) +{ + char buf[BUFSIZ]; + ssize_t n = ACE_OS::read (handle, buf, sizeof buf); + + switch (n) + { + case -1: + if (errno == EINTR) + return 0; + /* NOTREACHED */ + else + ACE_ERROR ((LM_ERROR, + "%p\n", + "read")); + /* FALLTHROUGH */ + case 0: + ACE_Reactor::end_event_loop (); + break; + default: + { + ssize_t result = ACE::write_n (ACE_STDOUT, buf, n); + + if (result != n) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "write"), + result == -1 && errno == EINTR ? 0 : -1); + } + } + return 0; +} + +class Message_Handler : public ACE_Task <ACE_SYNCH> +{ +public: + Message_Handler (void); + + virtual int handle_input (ACE_HANDLE); + // Called back within the context of the <ACE_Reactor> Singleton to + // dequeue and process the message on the <ACE_Message_Queue>. + + virtual int svc (void); + // Run the "event-loop" periodically putting messages to our + // internal <Message_Queue> that we inherit from <ACE_Task>. + +private: + ACE_Reactor_Notification_Strategy notification_strategy_; + // This strategy will notify the <ACE_Reactor> Singleton when a new + // message is enqueued. +}; + +Message_Handler::Message_Handler (void) + : notification_strategy_ (ACE_Reactor::instance (), + this, + ACE_Event_Handler::READ_MASK) +{ + // Set this to the Reactor notification strategy. + this->msg_queue ()->notification_strategy (&this->notification_strategy_); + + if (this->activate ()) + ACE_ERROR ((LM_ERROR, + "%p\n", + "activate")); +} + +int +Message_Handler::svc (void) +{ + for (int i = 0;; i++) + { + ACE_Message_Block *mb; + + ACE_NEW_RETURN (mb, + ACE_Message_Block (1), + 0); + + mb->msg_priority (i); + ACE_OS::sleep (1); + + // Note that this putq() call with automagically invoke the + // notify() hook of our ACE_Reactor_Notification_Strategy, + // thereby informing the <ACE_Reactor> Singleton to call our + // <handle_input> method. + if (this->putq (mb) == -1) + { + if (errno == ESHUTDOWN) + ACE_ERROR_RETURN ((LM_ERROR, + "(%t) queue is deactivated"), 0); + else + ACE_ERROR_RETURN ((LM_ERROR, + "(%t) %p\n", + "putq"), + -1); + } + } + + ACE_NOTREACHED (return 0); +} + +int +Message_Handler::handle_input (ACE_HANDLE) +{ + ACE_DEBUG ((LM_DEBUG, + "(%t) Message_Handler::handle_input\n")); + + ACE_Message_Block *mb; + + if (this->getq (mb, (ACE_Time_Value *) &ACE_Time_Value::zero) == -1) + ACE_ERROR ((LM_ERROR, + "(%t) %p\n", + "dequeue_head")); + else + { + ACE_DEBUG ((LM_DEBUG, + "(%t) priority = %d\n", + mb->msg_priority ())); + mb->release (); + } + + return 0; +} + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + ACE_Service_Config daemon (argv [0]); + + // Optionally start the alarm. + if (argc > 1) + { + ACE_OS::alarm (4); + timeout = ACE_OS::atoi (argv[1]); + } + + // Signal handler. + Sig_Handler sh; + + // Define an I/O handler object. + STDIN_Handler ioh; + + // Define a message handler. + Message_Handler mh; + + // Loop handling signals and I/O events until SIGQUIT occurs. + + while (ACE_Reactor::instance ()->event_loop_done () == 0) + ACE_Reactor::instance ()->run_reactor_event_loop (); + + // Deactivate the message queue. + mh.msg_queue ()->deactivate (); + + // Wait for the thread to exit. + ACE_Thread_Manager::instance ()->wait (); + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%t) leaving main\n"))); + return 0; +} diff --git a/ACE/examples/Reactor/Misc/test_early_timeouts.cpp b/ACE/examples/Reactor/Misc/test_early_timeouts.cpp new file mode 100644 index 00000000000..4c7193d9a67 --- /dev/null +++ b/ACE/examples/Reactor/Misc/test_early_timeouts.cpp @@ -0,0 +1,114 @@ +// $Id$ + +// ================================================================ +// +// = LIBRARY +// examples/Reactor/Misc/ +// +// = FILENAME +// test_early_timeouts.cpp +// +// = DESCRIPTION +// On some platforms, select() returns before the time value +// specified. This tests counts the number of times this happens +// and the max early timeout. +// +// = AUTHOR +// Irfan Pyarali <irfan@cs.wustl.edu> +// +// ================================================================ + +#include "ace/Handle_Set.h" +#include "ace/Pipe.h" +#include "ace/Log_Msg.h" +#include "ace/Time_Value.h" +#include "ace/OS_NS_sys_time.h" +#include "ace/OS_NS_sys_select.h" + +ACE_RCSID(Misc, test_early_timeouts, "$Id$") + +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + // Mumber of seconds this test should run + int runtime_in_seconds = 10; + + // Iterations + int iterations = runtime_in_seconds * 10; + + // 100 millisecond timeout + ACE_Time_Value timeout (0, 100000); + + // Time before starting select + ACE_Time_Value starting_time_of_day; + + // Time before starting select + ACE_Time_Value ending_time_of_day; + + // Number of times the timer expired early + int no_of_early_timers = 0; + + // Maximum early timeout + ACE_Time_Value maximum_early_timeout; + + // + // Dummy handle and handle set + // Note that some OS do not like "empty selects" + // + + // Dummy handle set + ACE_Handle_Set dummy_handle_set; + + // Dummy pipe + ACE_Pipe dummy_pipe; + int result = dummy_pipe.open (); + ACE_ASSERT (result == 0); + ACE_UNUSED_ARG (result); // To avoid compile warning with ACE_NDEBUG. + + for (int i = 1; i <= iterations; i++) + { + // Add dummy handle to dummy set + dummy_handle_set.set_bit (dummy_pipe.read_handle ()); + + // Note the time before select + starting_time_of_day = ACE_OS::gettimeofday (); + + // Wait for timeout + result = ACE_OS::select ((int) dummy_pipe.read_handle (), dummy_handle_set, 0, 0, &timeout); + ACE_ASSERT (result == 0); + + // Note the time after select + ending_time_of_day = ACE_OS::gettimeofday (); + + // Expected ending time + ACE_Time_Value expected_ending_time_of_day = + starting_time_of_day + timeout; + + // If the timer expired early + if (ending_time_of_day < expected_ending_time_of_day) + { + // How early + ACE_Time_Value early_timeout = expected_ending_time_of_day - ending_time_of_day; + + // Increment number of early timers + no_of_early_timers++; + + // Check max early timeout + if (early_timeout > maximum_early_timeout) + { + maximum_early_timeout = early_timeout; + } + } + } + + ACE_DEBUG ((LM_DEBUG, + "There were %d early timers out of %d calls to select() (%f%%)\n" + "The max early timeout was: %dsec %dusec\n", + no_of_early_timers, + iterations, + float (no_of_early_timers) / iterations * 100, + maximum_early_timeout.sec (), + maximum_early_timeout.usec ())); + + return 0; +} diff --git a/ACE/examples/Reactor/Misc/test_event_handler_t.cpp b/ACE/examples/Reactor/Misc/test_event_handler_t.cpp new file mode 100644 index 00000000000..4261859784e --- /dev/null +++ b/ACE/examples/Reactor/Misc/test_event_handler_t.cpp @@ -0,0 +1,47 @@ +// $Id$ + +#include "ace/Event_Handler_T.h" +#include "ace/Log_Msg.h" + +ACE_RCSID(Misc, test_event_handler_t, "$Id$") + +#if defined (ACE_HAS_TEMPLATE_TYPEDEFS) + +class ACE_Test_Sig_Handler +{ +public: + ACE_Test_Sig_Handler (void) {} + virtual ~ACE_Test_Sig_Handler (void) {} + virtual ACE_HANDLE get_handle (void) const { return 0; } + virtual void set_handle (ACE_HANDLE) {} + virtual int handle_async_io (ACE_HANDLE) { return 0; } + virtual int shutdown (ACE_HANDLE, ACE_Reactor_Mask) { return 0; } + virtual int signal_handler (int /* signum */, + siginfo_t * = 0, + ucontext_t * = 0) + { + return 0; + } +}; + +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + typedef ACE_Event_Handler_T<ACE_Test_Sig_Handler> EH_SH; + + // Tie the ACE_Event_Handler_T together with the methods from ACE_Test_Sig_Handler. + EH_SH tied_sh (new ACE_Test_Sig_Handler, 1, + &ACE_Test_Sig_Handler::get_handle, + &ACE_Test_Sig_Handler::handle_async_io, + &ACE_Test_Sig_Handler::shutdown, + &ACE_Test_Sig_Handler::signal_handler); + return 0; +} + +#else +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_ERROR_RETURN ((LM_ERROR, "your platform does not support template typedefs\n"), 1); +} +#endif /* ACE_HAS_TEMPLATE_TYPEDEFS */ diff --git a/ACE/examples/Reactor/Misc/test_reactors.cpp b/ACE/examples/Reactor/Misc/test_reactors.cpp new file mode 100644 index 00000000000..a08580672e0 --- /dev/null +++ b/ACE/examples/Reactor/Misc/test_reactors.cpp @@ -0,0 +1,195 @@ +// $Id$ + +// Perform a torture test of multiple ACE_Reactors and ACE_Tasks in +// the same process... Thanks to Detlef Becker for contributing this. + +#include "ace/Reactor.h" +#include "ace/Service_Config.h" +#include "ace/Task.h" +#include "ace/Atomic_Op.h" + +ACE_RCSID(Misc, test_reactors, "$Id$") + +#if defined (ACE_HAS_THREADS) + +#include "ace/Recursive_Thread_Mutex.h" + +static const int NUM_INVOCATIONS = 10; +static const int MAX_TASKS = 20; + +class Test_Task : public ACE_Task<ACE_MT_SYNCH> +{ +public: + Test_Task (void); + ~Test_Task (void); + + virtual int open (void *args = 0); + virtual int close (u_long flags = 0); + virtual int svc (void); + + virtual int handle_input (ACE_HANDLE handle); + virtual int handle_close (ACE_HANDLE fd, + ACE_Reactor_Mask close_mask); + +private: + int handled_; + + static int task_count_; +}; + +int Test_Task::task_count_ = 0; + +static ACE_Atomic_Op<ACE_Thread_Mutex, int> done_count = MAX_TASKS * 2; + +static ACE_Recursive_Thread_Mutex reclock_; + +Test_Task::Test_Task (void) + : handled_ (0) +{ + ACE_GUARD (ACE_Recursive_Thread_Mutex, ace_mon, reclock_); + + Test_Task::task_count_++; + ACE_DEBUG ((LM_DEBUG, + "(%t) TT+ Test_Task::task_count_ = %d\n", + Test_Task::task_count_)); +} + +Test_Task::~Test_Task (void) +{ + ACE_GUARD (ACE_Recursive_Thread_Mutex, ace_mon, reclock_); + + ACE_DEBUG ((LM_DEBUG, + "(%t) TT- Test_Task::task_count_ = %d\n", + Test_Task::task_count_)); +} + +int +Test_Task::open (void *args) +{ + this->reactor ((ACE_Reactor *) args); + return this->activate (THR_NEW_LWP); +} + +int +Test_Task::close (u_long) +{ + ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, reclock_, -1); + + Test_Task::task_count_--; + ACE_DEBUG ((LM_DEBUG, + "(%t) close Test_Task::task_count_ = %d\n", + Test_Task::task_count_)); + return 0; +} + +int +Test_Task::svc (void) +{ + for (int i = 0; i < NUM_INVOCATIONS; i++) + { + ACE_OS::thr_yield (); + + // ACE_DEBUG ((LM_DEBUG, "(%t) calling notify %d\n", i)); + + if (this->reactor ()->notify (this, ACE_Event_Handler::READ_MASK) == -1) + ACE_ERROR_RETURN ((LM_ERROR, "(%t) %p\n", "notify"), -1); + + // ACE_DEBUG ((LM_DEBUG, "(%t) leaving notify %d\n", i)); + } + + return 0; +} + +int +Test_Task::handle_close (ACE_HANDLE, + ACE_Reactor_Mask) +{ + ACE_DEBUG ((LM_DEBUG, "(%t) handle_close\n")); + return 0; +} + +int +Test_Task::handle_input (ACE_HANDLE) +{ + ACE_DEBUG ((LM_DEBUG, "(%t) handle_input\n")); + + this->handled_++; + + if (this->handled_ == NUM_INVOCATIONS) + { + done_count--; + ACE_DEBUG ((LM_DEBUG, + "(%t) handle_input, handled_ = %d, done_count = %d\n", + this->handled_, done_count.value ())); + } + + ACE_OS::thr_yield (); + return -1; +} + +static void * +worker (void *args) +{ + ACE_Reactor *reactor = (ACE_Reactor *) args; + + reactor->owner (ACE_Thread::self ()); + + ACE_Time_Value timeout (4); + + for (;;) + { + //ACE_DEBUG ((LM_DEBUG, "(%t) calling handle_events\n")); + + switch (reactor->handle_events (timeout)) + { + case -1: + ACE_ERROR_RETURN ((LM_ERROR, "(%t) %p\n", "reactor"), 0); + /* NOTREACHED */ + case 0: + ACE_ERROR_RETURN ((LM_ERROR, "(%t) timeout\n"), 0); + /* NOTREACHED */ + } + + // ACE_DEBUG ((LM_DEBUG, "(%t) done with handle_events\n")); + + } + + ACE_NOTREACHED(return 0); +} + +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_Reactor *react1 = ACE_Reactor::instance (); + ACE_Reactor *react2 = new ACE_Reactor (); + Test_Task tt1[MAX_TASKS]; + Test_Task tt2[MAX_TASKS]; + + for (int i = 0; i < MAX_TASKS; i++) + { + tt1[i].open (react1); + tt2[i].open (react2); + } + + if (ACE_Thread_Manager::instance ()->spawn + (ACE_THR_FUNC (worker), (void *) react1, THR_NEW_LWP) == -1) + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "spawn"), -1); + + else if (ACE_Thread_Manager::instance ()->spawn + (ACE_THR_FUNC (worker), (void *) react2, THR_NEW_LWP) == -1) + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "spawn"), -1); + + ACE_Thread_Manager::instance ()->wait (); + ACE_DEBUG ((LM_DEBUG, "(%t) done\n")); + + return 0; +} + +#else +int +main (int, char *[]) +{ + ACE_ERROR ((LM_ERROR, "threads not supported on this platform\n")); + return 0; +} +#endif /* ACE_HAS_THREADS */ diff --git a/ACE/examples/Reactor/Misc/test_signals_1.cpp b/ACE/examples/Reactor/Misc/test_signals_1.cpp new file mode 100644 index 00000000000..b0410f572c1 --- /dev/null +++ b/ACE/examples/Reactor/Misc/test_signals_1.cpp @@ -0,0 +1,114 @@ +// $Id$ + +// This simple program illustrates the difference between handling +// signals via the Reactor (which doesn't cause the event loop to +// terminate) and signals that aren't handled via the Reactor (which +// do). + +#include "ace/Service_Config.h" +#include "ace/Reactor.h" +#include "ace/Log_Msg.h" +#include "ace/Signal.h" + +ACE_RCSID(Misc, test_signals_1, "$Id$") + +// Number of times to allow signal to execute until we quit. +static size_t count = 10; + +static void +my_signal_function (int sig) +{ + ACE_DEBUG ((LM_DEBUG, + "Executed non-ACE signal handler for signal %S\n", + sig)); +} + +class My_Handler : public ACE_Event_Handler +{ +public: + virtual int handle_signal (int sig, + siginfo_t *, + ucontext_t *) + { + // @@ Note that this code is not portable to all OS platforms + // since it uses print statements within signal handler context. + ACE_DEBUG ((LM_DEBUG, + "Executed ACE signal handler for signal %S, count = %d\n", + sig, + count)); + count--; + + if (count == 0) + ACE_Reactor::end_event_loop (); + + return 0; + } + + virtual int handle_timeout (const ACE_Time_Value &, + const void *arg) + { + ACE_DEBUG ((LM_DEBUG, + "%s\n", + (const char *) arg)); + return 0; + } +}; + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + // First you need a handler for the timeout. + My_Handler my_handler; + + // This is the timeout period in seconds. + ACE_Time_Value period (ACE_DEFAULT_TIMEOUT); + + if (argc > 1) + period.set (ACE_OS::atoi (argv[1]), 0); + + // Set up the periodic interval timer. + if (ACE_Reactor::instance ()->schedule_timer + (&my_handler, + "hello", + period, + period) == -1) + ACE_ERROR_RETURN ((LM_DEBUG, + "%p\n", + "schedule_timer"), + -1); + + // Set up an ACE signal handler. + + if (ACE_Reactor::instance ()->register_handler + (SIGINT, + &my_handler) == -1) + ACE_ERROR_RETURN ((LM_DEBUG, + "%p\n", + "register_handler"), + -1); + + // Set up a non-ACE signal handler. When this goes off, the Reactor + // should return from its <run_event_loop> method. + ACE_Sig_Action sig ((ACE_SignalHandler) my_signal_function, + SIGQUIT); + ACE_UNUSED_ARG (sig); + + ACE_DEBUG ((LM_DEBUG, + "starting event loop that runs until you've typed ^C a total of 10 times or ^\\ once.\n")); + + // This call executes the reactor events until we're finished. + int result = ACE_Reactor::run_event_loop (); + + ACE_DEBUG ((LM_DEBUG, + "result = %d\n", + result)); + + // Make sure to remove my_handler before exiting main() since + // otherwise weird things can happen... + if (ACE_Reactor::instance ()->cancel_timer (&my_handler) == -1) + ACE_ERROR_RETURN ((LM_DEBUG, + "%p\n", + "cancel_timer"), + -1); + return 0; +} diff --git a/ACE/examples/Reactor/Misc/test_signals_2.cpp b/ACE/examples/Reactor/Misc/test_signals_2.cpp new file mode 100644 index 00000000000..466ab58482f --- /dev/null +++ b/ACE/examples/Reactor/Misc/test_signals_2.cpp @@ -0,0 +1,291 @@ +// $Id$ + +// Test the ability of the Reactor/Signal_Handler to register multiple +// handler per-signal. + +/* This test works as follows: + + 1. To test the "original" semantics of ACE (i.e., only one + ACE_Event_Handler can be registered per signal), you don't + need to do anything special. Existing programs work the + same since giving the Reactor's constructor a 0 value + (which is the default argument, BTW) instructs it to behave + as before. When a 0 is given, the ACE_Reactor's + constructor/open method creates an instance of + ACE_Sig_Handler and assigns this to an internal pointer. + This pointer is then used to dispatch all signal-related + methods within the Reactor. The default ACE_Sig_Handler + only allows *one* ACE_Event_Handler to be registered + per-signal. + + To run this version of the test do the following: + + % ./test-signal + ./test_signals + waiting for SIGINT or SIGQUIT + ^C + signal Interrupt occurred in Sig_Handler_2 (fruity, 0, 0) with count = 1 + waiting for SIGINT or SIGQUIT + ^\ + signal Quit occurred in Sig_Handler_2 (fruity, 0, 0) with count = 2 + shutting down SIGQUIT in Sig_Handler_2 (fruity, 0, 0) + waiting for SIGINT or SIGQUIT + ^C + signal Interrupt occurred in Sig_Handler_2 (fruity, 0, 0) with count = 3 + waiting for SIGINT or SIGQUIT + ^\Quit (core dumped) + + Note that in this test only one handler (the last one -- + "Sig_Handler_2 (fruity)") is actually registered. BTW, the + core dump is the expected behavior since the default + disposition is restored when there are no more handlers + (see the code below). + + 2. To test the "multiple handlers per-signal semantics", you + need to pass the constructor/open method of the ACE_Reactor + a pointer to a an instance of ACE_Sig_Handlers (note the + plural "s"). ACE_Sig_Handlers is a class that derives from + ACE_Sig_Handler. The difference between these two classes + is that (1) ACE_Sig_Handlers::register_signal allows + multiple ACE_Event_Handlers to be registered per-signal and + (2) it enables SA_RESTART by default. This class also + implements Detlef Becker's algorithm for integrating ACE + signal handling with 3rd party libraries. + + To run this version of the test do the following: + + % ./test_signals 1 + + waiting for SIGINT or SIGQUIT + ^C + signal Interrupt occurred in external handler! + signal Interrupt occurred in Sig_Handler_1 (howdy, 3, 1) with count = 1 + shutting down SIGINT in Sig_Handler_1 (howdy, 3, 1) + signal Interrupt occurred in Sig_Handler_1 (doody, 5, 4) with count = 1 + shutting down SIGINT in Sig_Handler_1 (doody, 5, 4) + signal Interrupt occurred in Sig_Handler_2 (tutty, 7, 6) with count = 1 + signal Interrupt occurred in Sig_Handler_2 (fruity, 9, 8) with count = 1 + waiting for SIGINT or SIGQUIT + ^\ + signal Quit occurred in Sig_Handler_1 (howdy, 3, 1) with count = 2 + shutting down SIGQUIT in Sig_Handler_1 (howdy, 3, 1) + signal Quit occurred in Sig_Handler_1 (doody, 5, 4) with count = 2 + shutting down SIGQUIT in Sig_Handler_1 (doody, 5, 4) + signal Quit occurred in Sig_Handler_2 (tutty, 7, 6) with count = 2 + shutting down SIGQUIT in Sig_Handler_2 (tutty, 7, 6) + signal Quit occurred in Sig_Handler_2 (fruity, 9, 8) with count = 2 + shutting down SIGQUIT in Sig_Handler_2 (fruity, 9, 8) + waiting for SIGINT or SIGQUIT + ^C + signal Interrupt occurred in external handler! + signal Interrupt occurred in Sig_Handler_2 (tutty, 7, 6) with count = 3 + signal Interrupt occurred in Sig_Handler_2 (fruity, 9, 8) with count = 3 + waiting for SIGINT or SIGQUIT + ^\Quit (core dumped) + + When this test begins all four handlers are registered and + dispatched when a SIGINT or SIGQUIT occurs. After the + first SIGINT, the handle_signal method of the Sig_Handler_1 + objects unregister themselves. At that point there are 4 + SIGQUIT handlers left, but only 2 of our SIGINT handlers + left (and the 1 external handler). After the first + SIGQUIT, there are no SIGQUIT handlers left since they all + deregister themselves (which restores the "SIG_DFL" + disposition). On the second SIGINT there are only 3 + handlers left (2 of ours and 1 external). Finally, on the + second SIGQUIT we exit and dump core since that's what + happens with the default disposition for SIGQUIT. */ + + +#include "ace/Reactor.h" +#include "ace/WFMO_Reactor.h" +#include "ace/Select_Reactor.h" +#include "ace/Log_Msg.h" +#include "ace/Signal.h" + +ACE_RCSID(Misc, test_signals_2, "$Id$") + +class Sig_Handler_1 : public ACE_Event_Handler +{ +public: + Sig_Handler_1 (ACE_Reactor &reactor, const char *msg) + : msg_ (msg), + count_ (0), + reactor_ (reactor) + { + // Register the signal handlers. + this->quit_sigkey_ = + reactor.register_handler (SIGQUIT, this); + this->int_sigkey_ = + reactor.register_handler (SIGINT, this); + + if (this->quit_sigkey_ == -1 || this->int_sigkey_ == -1) + ACE_ERROR ((LM_ERROR, + "%p\n", + "register_handler")); + } + + // @@ Note that this code is not portable to all OS platforms since + // it does print statements within the signal handler. + virtual int handle_signal (int signum, + siginfo_t *, + ucontext_t *) + { + this->count_++; + ACE_DEBUG ((LM_DEBUG, + "\nsignal %S occurred in Sig_Handler_1 (%s, %d, %d) with count = %d", + signum, + this->msg_, + this->int_sigkey_, + this->quit_sigkey_, + this->count_)); + + if (this->count_ != 1 && signum == SIGQUIT) + { + if (this->reactor_.remove_handler (SIGQUIT, + 0, + 0, + this->quit_sigkey_) == -1) + ACE_ERROR ((LM_ERROR, + "\n%p", + "remove_handler")); + else + ACE_DEBUG ((LM_DEBUG, + "\nshutting down SIGQUIT in Sig_Handler_1 (%s, %d, %d)", + this->msg_, + this->int_sigkey_, + this->quit_sigkey_)); + } + else if (this->count_ != 2 && signum == SIGINT) + { + if (this->reactor_.remove_handler (SIGINT, + 0, + 0, + this->int_sigkey_) == -1) + ACE_ERROR ((LM_ERROR, + "\n%p", + "remove_handler")); + else + ACE_DEBUG ((LM_DEBUG, + "\nshutting down SIGINT in Sig_Handler_1 (%s, %d, %d)", + this->msg_, + this->int_sigkey_, + this->quit_sigkey_)); + } + return 0; + } + +protected: + const char *msg_; + int count_; + int int_sigkey_; + int quit_sigkey_; + ACE_Reactor &reactor_; +}; + +class Sig_Handler_2 : public Sig_Handler_1 +{ +public: + Sig_Handler_2 (ACE_Reactor &reactor, const char *msg) + : Sig_Handler_1 (reactor, msg) + { + } + + virtual int handle_signal (int signum, + siginfo_t *, + ucontext_t *) + { + this->count_++; + ACE_DEBUG ((LM_DEBUG, + "\nsignal %S occurred in Sig_Handler_2 (%s, %d, %d) with count = %d", + signum, + this->msg_, + this->int_sigkey_, + this->quit_sigkey_, + this->count_)); + if (this->count_ != 0 && signum == SIGQUIT) + { + if (this->reactor_.remove_handler (SIGQUIT, 0, 0, + this->quit_sigkey_) == -1) + ACE_ERROR ((LM_ERROR, + "\n%p", + "remove_handler")); + else + ACE_DEBUG ((LM_DEBUG, + "\nshutting down SIGQUIT in Sig_Handler_2 (%s, %d, %d)", + this->msg_, + this->int_sigkey_, + this->quit_sigkey_)); + } + return 0; + } +}; + +static void +external_handler (int signum) +{ + ACE_DEBUG ((LM_DEBUG, + "\nsignal %S occurred in external handler!", + signum)); +} + +#if !defined (HPUX) +int +ACE_TMAIN (int argc, ACE_TCHAR *[]) +{ + // If argc > 1 then allow multiple handlers per-signal, else just + // allow 1 handler per-signal. + ACE_Sig_Handlers multi_handlers; + +#if defined (ACE_WIN32) + ACE_WFMO_Reactor reactor_impl (argc > 1 + ? &multi_handlers + : (ACE_Sig_Handler *) 0); +#else + ACE_Select_Reactor reactor_impl (argc > 1 + ? &multi_handlers + : (ACE_Sig_Handler *) 0); +#endif /* ACE_WIN32 */ + ACE_Reactor reactor (&reactor_impl); + + if (argc > 1) + { + // Register an "external" signal handler so that the + // ACE_Sig_Handlers code will have something to incorporate! + + ACE_SignalHandler eh = (ACE_SignalHandler) external_handler; + ACE_Sig_Action sa (eh); + + sa.register_action (SIGINT); + } + + // Create a bevy of handlers. + Sig_Handler_1 h1 (reactor, "howdy"); + Sig_Handler_1 h2 (reactor, "doody"); + Sig_Handler_2 h3 (reactor, "tutty"); + Sig_Handler_2 h4 (reactor, "fruity"); + + // Wait for user to type SIGINT and SIGQUIT. + + for (;;) + { + ACE_DEBUG ((LM_DEBUG, + "\nwaiting for SIGINT or SIGQUIT\n")); + + if (reactor.handle_events () == -1) + ACE_ERROR ((LM_ERROR, + "%p\n", + "handle_events")); + } + + ACE_NOTREACHED (return 0); +} +#else +int +main (int, char *[]) +{ + ACE_ERROR_RETURN ((LM_ERROR, + "The HP C++ compiler is too lame to support this feature\n"), + -1); +} +#endif /* HPUX */ diff --git a/ACE/examples/Reactor/Misc/test_time_value.cpp b/ACE/examples/Reactor/Misc/test_time_value.cpp new file mode 100644 index 00000000000..a1c1c874b78 --- /dev/null +++ b/ACE/examples/Reactor/Misc/test_time_value.cpp @@ -0,0 +1,83 @@ +// $Id$ + +// FUZZ: disable check_for_streams_include +#include "ace/streams.h" + +#include "ace/Log_Msg.h" +#include "ace/Time_Value.h" + +ACE_RCSID(Misc, test_time_value, "$Id$") + +inline int my_abs (int d) { return d > 0 ? d : -d; } + +ostream & +operator<< (ostream &stream, const ACE_Time_Value &tv) +{ + if (tv.usec () < 0 || tv.sec () < 0) + stream << "-"; + + stream << my_abs (int (tv.sec ())) << "." +// << setw (6) << setfill ('0') + << my_abs (int (tv.usec ())); + return stream; +} + +int +main (int, char *[]) +{ + ACE_Time_Value tv1; + ACE_Time_Value tv2 (2); + ACE_Time_Value tv3 (100); + ACE_Time_Value tv4 (1, 1000000); + ACE_Time_Value tv5 (2); + ACE_Time_Value tv6 (1, -1000000); + + ACE_ASSERT (tv1 == ACE_Time_Value (0)); + ACE_ASSERT (tv2 < tv3); + ACE_ASSERT (tv2 <= tv2); + ACE_ASSERT (tv2 >= tv4); + ACE_ASSERT (tv5 >= tv6); + ACE_ASSERT (tv2 == ACE_Time_Value (1, 1000000)); + ACE_ASSERT (tv5 == tv4); + ACE_ASSERT (tv2 == tv4); + ACE_ASSERT (tv1 != tv2); + ACE_ASSERT (tv6 == tv1); + +# if defined (ACE_NDEBUG) + ACE_UNUSED_ARG (tv1); + ACE_UNUSED_ARG (tv2); + ACE_UNUSED_ARG (tv3); + ACE_UNUSED_ARG (tv4); + ACE_UNUSED_ARG (tv5); + ACE_UNUSED_ARG (tv6); +# endif /* ACE_NDEBUG */ + + cout << "0,0 :\t\t" << ACE_Time_Value (0,0) << endl; + cout << "-0,0 :\t\t" << ACE_Time_Value (-0,0) << endl; + cout << "0,-0 :\t\t" << ACE_Time_Value (0,-0) << endl; + cout << "-0,-0 :\t\t" << ACE_Time_Value (-0,-0) << endl; + cout << endl; + + cout << "0,1 :\t\t" << ACE_Time_Value (0,1) << endl; + cout << "1,0 :\t\t" << ACE_Time_Value (1,0) << endl; + cout << "-1,0 :\t\t" << ACE_Time_Value (-1,0) << endl; + cout << "-1,-0 :\t\t" << ACE_Time_Value (-1,-0) << endl; + cout << endl; + + cout << "1,1 :\t\t" << ACE_Time_Value (1,1) << endl; + cout << "-1,1 :\t\t" << ACE_Time_Value (-1,1) << endl; + cout << "1,-1 :\t\t" << ACE_Time_Value (1,-1) << endl; + cout << "-1,-1 :\t\t" << ACE_Time_Value (-1,-1) << endl; + cout << endl; + + cout << "1,-1111111 :\t" << ACE_Time_Value (1,-1111111) << endl; + cout << "1,-100000 :\t" << ACE_Time_Value (1,-100000) << endl; + cout << "1,-1000000 :\t" << ACE_Time_Value (1,-1000000) << endl; + cout << "-1,1000000 :\t" << ACE_Time_Value (-1,1000000) << endl; + cout << "5,-1000000 :\t" << ACE_Time_Value (5,-1000000) << endl; + cout << "5,-1500000 :\t" << ACE_Time_Value (5,-1500000) << endl; + cout << "2,-2500000 :\t" << ACE_Time_Value (2,-2500000) << endl; + cout << "2,-4500000 :\t" << ACE_Time_Value (2,-4500000) << endl; + + return 0; +} diff --git a/ACE/examples/Reactor/Misc/test_timer_queue.cpp b/ACE/examples/Reactor/Misc/test_timer_queue.cpp new file mode 100644 index 00000000000..64138e13daf --- /dev/null +++ b/ACE/examples/Reactor/Misc/test_timer_queue.cpp @@ -0,0 +1,115 @@ +// $Id$ + +#include "ace/OS_NS_sys_time.h" +#include "ace/Timer_Heap.h" +#include "ace/Timer_List.h" +#include "ace/Timer_Queue.h" +#include "ace/Log_Msg.h" +#include "ace/Recursive_Thread_Mutex.h" +#include "ace/Null_Mutex.h" + +ACE_RCSID(Misc, test_timer_queue, "$Id$") + +class Example_Handler : public ACE_Event_Handler +{ +public: + Example_Handler (void) + : count_ (1) + {} + + virtual int handle_timeout (const ACE_Time_Value &, const void *arg) + { + int *times = (int *) arg; + + ACE_DEBUG ((LM_DEBUG, + "yow, the time has come and gone %d times %d, Horatio!\n", + this->count_++, + *times)); + delete times; + return 0; + } + +private: + int count_; +}; + +static void +test_functionality (ACE_Timer_Queue *tq) +{ + Example_Handler eh; + + ACE_ASSERT (tq->is_empty ()); + ACE_ASSERT (ACE_Time_Value::zero == ACE_Time_Value (0)); + const void *timer_act = 0; + + ACE_NEW (timer_act, int (1)); + long timer_id1 = tq->schedule (&eh, timer_act, ACE_OS::gettimeofday ()); + + // Use timer_id outside of an assert, so that we don't get compile + // warnings with ACE_NDEBUG about it being unused. + if (timer_id1 == -1) + ACE_ERROR ((LM_ERROR, "%p\n", "schedule () failed")); + ACE_ASSERT (timer_id1 != -1); + + ACE_NEW (timer_act, int (42)); + long result = tq->schedule (&eh, timer_act, ACE_OS::gettimeofday ()); + ACE_ASSERT (result != -1); + ACE_NEW (timer_act, int (42)); + result = tq->schedule (&eh, timer_act, ACE_OS::gettimeofday ()); + ACE_ASSERT (result != -1); + + result = tq->cancel (timer_id1, &timer_act); + ACE_ASSERT (result == 1); + delete (int *) timer_act; + result = tq->is_empty (); + ACE_ASSERT (!result); + + result = tq->expire (); + ACE_ASSERT (result == 2); + + ACE_NEW (timer_act, int (4)); + timer_id1 = tq->schedule (&eh, timer_act, ACE_OS::gettimeofday ()); + ACE_ASSERT (timer_id1 != -1); + ACE_NEW (timer_act, int (5)); + long timer_id2 = tq->schedule (&eh, timer_act, ACE_OS::gettimeofday ()); + ACE_ASSERT (timer_id2 != -1); + + result = tq->cancel (timer_id1, &timer_act); + ACE_ASSERT (result == 1); + delete (int *) timer_act; + result = tq->cancel (timer_id2, &timer_act); + ACE_ASSERT (result == 1); + delete (int *) timer_act; + result = tq->is_empty (); + ACE_ASSERT (result == 1); + result = tq->expire (); + ACE_ASSERT (result == 0); +} + +struct Timer_Queues +{ + ACE_Timer_Queue *queue_; + // Pointer to the subclass of <ACE_Timer_Queue> that we're testing. + + const char *name_; + // Name of the Queue that we're testing. +}; + +static Timer_Queues timer_queues[] = +{ + { new ACE_Timer_List, "ACE_Timer_List" }, + { new ACE_Timer_Heap, "ACE_Timer_Heap" }, + { 0, 0 }, +}; + +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + for (int i = 0; timer_queues[i].name_ != 0; i++) + { + test_functionality (timer_queues[i].queue_); + delete timer_queues[i].queue_; + } + + return 0; +} diff --git a/ACE/examples/Reactor/Multicast/.cvsignore b/ACE/examples/Reactor/Multicast/.cvsignore new file mode 100644 index 00000000000..955ffdc75d5 --- /dev/null +++ b/ACE/examples/Reactor/Multicast/.cvsignore @@ -0,0 +1,4 @@ +client +client +server +server diff --git a/ACE/examples/Reactor/Multicast/Log_Wrapper.cpp b/ACE/examples/Reactor/Multicast/Log_Wrapper.cpp new file mode 100644 index 00000000000..055b57b9975 --- /dev/null +++ b/ACE/examples/Reactor/Multicast/Log_Wrapper.cpp @@ -0,0 +1,81 @@ +// $Id$ + +// client.C + +#include "Log_Wrapper.h" +#include "ace/OS_NS_unistd.h" +#include "ace/OS_NS_sys_utsname.h" +#include "ace/OS_NS_string.h" +#include "ace/OS_NS_netdb.h" + +ACE_RCSID(Multicast, Log_Wrapper, "$Id$") + +Log_Wrapper::Log_Wrapper (void) +{ + sequence_number_ = 0; + this->log_msg_.app_id = ACE_OS::getpid (); +} + +Log_Wrapper::~Log_Wrapper (void) +{ +} + +// Set the log_msg_ host address. + +int +Log_Wrapper::open (const int port, const char *mcast_addr) +{ + struct hostent *host_info; + ACE_utsname host_data; + + if (ACE_OS::uname (&host_data) < 0) + return -1; + +#if defined (ACE_LACKS_UTSNAME_T) + if ((host_info = ACE_OS::gethostbyname + (ACE_TEXT_ALWAYS_CHAR(host_data.nodename))) == NULL) +#else + if ((host_info = ACE_OS::gethostbyname (host_data.nodename)) == NULL) +#endif + return -1; + else + ACE_OS::memcpy ((char *) &this->log_msg_.host, + (char *) host_info->h_addr, + host_info->h_length); + + // This starts out initialized to all zeros! + server_ = ACE_INET_Addr (port, mcast_addr); + + if (logger_.subscribe (server_) == -1) + perror("can't subscribe to multicast group"), exit(1); + + // success. + return 0; +} + +// Send the message to a logger object. +// This wrapper fills in all the log_record info for you. +// uses iovector stuff to make contiguous header and message. + +int +Log_Wrapper::log_message (Log_Priority type, char *message) +{ + sequence_number_++; + + this->log_msg_.type = type; + this->log_msg_.time = time (0); + this->log_msg_.msg_length = ACE_OS::strlen(message)+1; + this->log_msg_.sequence_number = htonl(sequence_number_); + + iovec iovp[2]; + iovp[0].iov_base = reinterpret_cast<char*> (&log_msg_); + iovp[0].iov_len = sizeof (log_msg_); + iovp[1].iov_base = message; + iovp[1].iov_len = log_msg_.msg_length; + + logger_.send (iovp, 2); + + // success. + return 0; +} + diff --git a/ACE/examples/Reactor/Multicast/Log_Wrapper.h b/ACE/examples/Reactor/Multicast/Log_Wrapper.h new file mode 100644 index 00000000000..10458f706bc --- /dev/null +++ b/ACE/examples/Reactor/Multicast/Log_Wrapper.h @@ -0,0 +1,68 @@ +/* -*- C++ -*- */ +// $Id$ + +// log_wrapper.h + +#include "ace/Profile_Timer.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/INET_Addr.h" +#include "ace/SOCK_Dgram_Mcast.h" + +#ifndef _LOG_WRAPPER_H +#define _LOG_WRAPPER_H + +class Log_Wrapper + // = TITLE + // Provide a wrapper around sending log messages via IP + // multicast. +{ +public: + Log_Wrapper (void); + ~Log_Wrapper (void); + + // = Types of logging messages. + enum Log_Priority + { + LM_MESSAGE, + LM_DEBUG, + LM_WARNING, + LM_ERROR, + LM_EMERG + }; + + int open (const int port, const char* mcast_addr); + // Subscribe to a given UDP multicast group + + int log_message (Log_Priority type, char *message); + // send a string to the logger + + // = Format of the logging record. + struct Log_Record + { + u_long sequence_number; + Log_Priority type; + long host; + long time; + long app_id; + long msg_length; + }; + +private: + ACE_INET_Addr server_; + // Server address where records are logged. + + u_long sequence_number_; + // Keep track of the sequence. + + Log_Record log_msg_; + // One record used for many log messages. + + ACE_SOCK_Dgram_Mcast logger_; + // A logger object. +}; + +#endif /* _LOG_WRAPPER_H */ diff --git a/ACE/examples/Reactor/Multicast/Makefile.am b/ACE/examples/Reactor/Multicast/Makefile.am new file mode 100644 index 00000000000..60d65e7ebe8 --- /dev/null +++ b/ACE/examples/Reactor/Multicast/Makefile.am @@ -0,0 +1,50 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +ACE_BUILDDIR = $(top_builddir) +ACE_ROOT = $(top_srcdir) + +## Makefile.Reactor_Multicast_Client.am +noinst_PROGRAMS = client + +client_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +client_SOURCES = \ + Log_Wrapper.cpp \ + client.cpp \ + Log_Wrapper.h + +client_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Reactor_Multicast_Server.am +noinst_PROGRAMS += server + +server_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +server_SOURCES = \ + Log_Wrapper.cpp \ + server.cpp \ + Log_Wrapper.h + +server_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Clean up template repositories, etc. +clean-local: + -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.* + -rm -f gcctemp.c gcctemp so_locations *.ics + -rm -rf cxx_repository ptrepository ti_files + -rm -rf templateregistry ir.out + -rm -rf ptrepository SunWS_cache Templates.DB diff --git a/ACE/examples/Reactor/Multicast/README b/ACE/examples/Reactor/Multicast/README new file mode 100644 index 00000000000..85f64cc8120 --- /dev/null +++ b/ACE/examples/Reactor/Multicast/README @@ -0,0 +1,15 @@ +The following test illustrates the SOCK Mcast multicast wrappers in +conjunction with the Reactor. This test was written by Tim Harrison +(harrison@cs.wustl.edu). + +To run the server type: + +% server & + +It will wait for the first message sent to it and then read for 5 seconds. + +To run the client type any of these: + +% client -m max_message_size -i iterations +% client < <filename> +% client diff --git a/ACE/examples/Reactor/Multicast/Reactor_Multicast.mpc b/ACE/examples/Reactor/Multicast/Reactor_Multicast.mpc new file mode 100644 index 00000000000..a15c53340e4 --- /dev/null +++ b/ACE/examples/Reactor/Multicast/Reactor_Multicast.mpc @@ -0,0 +1,17 @@ +// -*- MPC -*- +// $Id$ + +project(*client) : aceexe { + exename = client + Source_Files { + client.cpp + Log_Wrapper.cpp + } +} +project(*server) : aceexe { + exename = server + Source_Files { + server.cpp + Log_Wrapper.cpp + } +} diff --git a/ACE/examples/Reactor/Multicast/client.cpp b/ACE/examples/Reactor/Multicast/client.cpp new file mode 100644 index 00000000000..25b18c2ae6c --- /dev/null +++ b/ACE/examples/Reactor/Multicast/client.cpp @@ -0,0 +1,126 @@ +// $Id$ + +// This program reads in messages from stdin and sends them to a +// Log_Wrapper. + +#include "ace/OS_main.h" +#include "ace/OS_NS_stdlib.h" +#include "ace/OS_NS_string.h" +#include "ace/OS_NS_unistd.h" +#include "ace/OS_Memory.h" +#include "ace/Get_Opt.h" +#include "ace/Log_Msg.h" +#include "Log_Wrapper.h" + +ACE_RCSID(Multicast, client, "$Id$") + +// Multi-cast address. +static const char *MCAST_ADDR = ACE_DEFAULT_MULTICAST_ADDR; + +// UDP port. +static const int UDP_PORT = ACE_DEFAULT_MULTICAST_PORT; + +// Maximum message size. +static int max_message_size = BUFSIZ; + +// Number of times to send message of max_message_size. +static int iterations = 0; + +static void +parse_args (int argc, ACE_TCHAR *argv[]) +{ + ACE_LOG_MSG->open (argv[0]); + + // Start at argv[1] + ACE_Get_Opt getopt (argc, argv, ACE_TEXT("m:ui:"), 1); + + for (int c; (c = getopt ()) != -1; ) + switch (c) + { + case 'm': + max_message_size = ACE_OS::atoi (getopt.opt_arg ()) * BUFSIZ; + break; + case 'i': + iterations = ACE_OS::atoi (getopt.opt_arg ()); + break; + case 'u': + // usage fallthrough + default: + ACE_ERROR ((LM_ERROR, + "%n: -m max_message_size (in k) -i iterations\n%a", + 1)); + /* NOTREACHED */ + } +} + +int +ACE_TMAIN (int argc, ACE_TCHAR **argv) +{ + int user_prompt; + + parse_args (argc,argv); + + ACE_DEBUG ((LM_DEBUG, "max buffer size = %d\n", max_message_size)); + + // Instantiate a log wrapper for logging + Log_Wrapper log; + + // Make a connection to a logger. + if (log.open (UDP_PORT, MCAST_ADDR) == -1) + ACE_ERROR_RETURN ((LM_ERROR, "%p\n" "open"), -1); + + char *buf; + ACE_NEW_RETURN (buf, char[max_message_size], -1); + + // If -i has been specified, send max_message_size messages + // iterations number of times. + if (iterations) + { + ACE_OS::memset (buf, 1, max_message_size); + + while (iterations--) + if (log.log_message (Log_Wrapper::LM_DEBUG, buf) == -1) + ACE_ERROR_RETURN ((LM_ERROR, "%p\n" "log"), -1); + } + + // otherwise, a file has been redirected, or give prompts + else + { + // If a file has been redirected, don't activate user prompts. + if (ACE_OS::isatty (0)) + user_prompt = 1; + else + user_prompt = 0; + + // Continually read messages from stdin and log them. + + for (int count = 1;;) + { + if (user_prompt) + ACE_DEBUG ((LM_DEBUG, "\nEnter message ('Q':quit):\n")); + + ssize_t nbytes = ACE_OS::read (ACE_STDIN, buf, max_message_size); + + if (nbytes <= 0) + break; // End of file or error. + buf[nbytes - 1] = '\0'; + + // Quitting? + if (user_prompt) + { + if (buf[0] == 'Q' || buf[0] == 'q') + break; + } + else // Keep from overrunning the receiver. + ACE_OS::sleep (1); + + // Send the message to the logger. + if (log.log_message (Log_Wrapper::LM_DEBUG, buf) == -1) + ACE_ERROR_RETURN ((LM_ERROR, "%p\n" "log_message"), -1); + ACE_DEBUG ((LM_DEBUG, "finished sending message %d\n", count++)); + } + } + + ACE_DEBUG ((LM_DEBUG, "Client done.\n")); + return 0; +} diff --git a/ACE/examples/Reactor/Multicast/server.cpp b/ACE/examples/Reactor/Multicast/server.cpp new file mode 100644 index 00000000000..65e39b97d1a --- /dev/null +++ b/ACE/examples/Reactor/Multicast/server.cpp @@ -0,0 +1,247 @@ +// $Id$ + +// server.cpp (written by Tim Harrison) + +// Listens to multicast address for client log messages. Prints +// Mbits/sec received from client. + +#include "ace/OS_main.h" +#include "ace/SOCK_Dgram.h" +#include "ace/INET_Addr.h" +#include "ace/SOCK_Dgram_Mcast.h" +#include "ace/Reactor.h" +#include "ace/Log_Msg.h" +#include "Log_Wrapper.h" +#include "ace/OS_NS_string.h" +#include "ace/OS_NS_unistd.h" +#include "ace/os_include/os_netdb.h" + +ACE_RCSID(Multicast, server, "$Id$") + +#if defined (ACE_HAS_IP_MULTICAST) +class Server_Events : public ACE_Event_Handler +{ +public: + Server_Events (u_short port, + const char *mcast_addr, + long time_interval = 0); + ~Server_Events (void); + + virtual int handle_input (ACE_HANDLE fd); + virtual int handle_timeout (const ACE_Time_Value &tv, + const void *arg); + + virtual ACE_HANDLE get_handle (void) const; + + ACE_Time_Value *wait_time (void); + +private: + char *message_; + Log_Wrapper::Log_Record *log_record_; + char buf_[4 * BUFSIZ]; + char hostname_[MAXHOSTNAMELEN]; + + int initialized_; + int count_; + long interval_; + // time interval to log messages + + ACE_Time_Value *how_long_; + ACE_Reactor *reactor_; + ACE_SOCK_Dgram_Mcast mcast_dgram_; + ACE_INET_Addr remote_addr_; + ACE_INET_Addr mcast_addr_; + + // = statistics on messages received + double total_bytes_received_; + int total_messages_received_; + int last_sequence_number_; +}; + +static const char MCAST_ADDR[] = ACE_DEFAULT_MULTICAST_ADDR; +static const int UDP_PORT = ACE_DEFAULT_MULTICAST_PORT; +static const int DURATION = 5; + +ACE_HANDLE +Server_Events::get_handle (void) const +{ + return this->mcast_dgram_.get_handle (); +} + +ACE_Time_Value * +Server_Events::wait_time (void) +{ + return this->how_long_; +} + +Server_Events::Server_Events (u_short port, + const char *mcast_addr, + long time_interval) + : initialized_ (0), + count_ (1), + interval_ (time_interval), + mcast_addr_ (port, mcast_addr), + total_bytes_received_ (0) +{ + // Use ACE_SOCK_Dgram_Mcast factory to subscribe to multicast group. + + if (ACE_OS::hostname (this->hostname_, + MAXHOSTNAMELEN) == -1) + ACE_ERROR ((LM_ERROR, + "%p\n", + "hostname")); + + else if (this->mcast_dgram_.subscribe (this->mcast_addr_) == -1) + ACE_ERROR ((LM_ERROR, + "%p\n", + "subscribe")); + else + { + // Point to NULL so that we block in the beginning. + this->how_long_ = 0; + + this->log_record_ = (Log_Wrapper::Log_Record *) &buf_; + this->message_ = &buf_[sizeof (Log_Wrapper::Log_Record)]; + } +} + +// A destructor that emacs refuses to color blue ;-) + +Server_Events::~Server_Events (void) +{ + this->mcast_dgram_.unsubscribe (); + + ACE_DEBUG ((LM_DEBUG, + "total bytes received = %d after %d second\n", + this->total_bytes_received_, + this->interval_)); + + ACE_DEBUG ((LM_DEBUG, + "Mbits/sec = %.2f\n", + (float) (total_bytes_received_ * 8 / (float) (1024*1024*interval_)))); + + ACE_DEBUG ((LM_DEBUG, + "last sequence number = %d\ntotal messages received = %d\ndiff = %d\n", + this->last_sequence_number_, + this->total_messages_received_, + this->last_sequence_number_ - total_messages_received_)); +} + +int +Server_Events::handle_timeout (const ACE_Time_Value &, + const void *arg) +{ + ACE_DEBUG ((LM_DEBUG, "\t%d timeout%s occurred for %s.\n", + this->count_, + this->count_ == 1 ? "" : "s", + (char *) arg)); + + // Don't let the timeouts continue if there's no activity since + // otherwise we use up a lot of CPU time unnecessarily. + if (this->count_ == 5) + { + reactor ()->cancel_timer (this); + this->initialized_ = 0; + + ACE_DEBUG ((LM_DEBUG, + "\tcancelled timeout for %s to avoid busy waiting.\n", + (char *) arg)); + } + + this->count_++; + return 0; +} + +int +Server_Events::handle_input (ACE_HANDLE) +{ + // Receive message from multicast group. + iovec iovp[2]; + iovp[0].iov_base = buf_; + iovp[0].iov_len = sizeof (log_record_); + iovp[1].iov_base = &buf_[sizeof (log_record_)]; + iovp[1].iov_len = 4 * BUFSIZ - sizeof (log_record_); + + ssize_t retcode = + this->mcast_dgram_.recv (iovp, + 2, + this->remote_addr_); + if (retcode != -1) + { + total_messages_received_++; + total_bytes_received_ += retcode; + last_sequence_number_ = + ntohl (log_record_->sequence_number); + + for (char *message_end = this->message_ + ACE_OS::strlen (this->message_) - 1; + ACE_OS::strchr ("\r\n \t", *message_end) != 0; + ) + { + *message_end-- = '\0'; + if (message_end == this->message_) + break; + } + + ACE_DEBUG ((LM_DEBUG, + "sequence number = %d\n", + last_sequence_number_)); + ACE_DEBUG ((LM_DEBUG, + "message = '%s'\n", + this->message_)); + + if (this->initialized_ == 0) + { + // Restart the timer since we've received events again. + if (reactor()->schedule_timer (this, + (void *) this->hostname_, + ACE_Time_Value::zero, + ACE_Time_Value (DURATION)) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "schedule_timer"), + -1); + this->initialized_ = 1; + } + + this->count_ = 1; + return 0; + } + else + return -1; +} + +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + // Instantiate a server which will receive messages for DURATION + // seconds. + Server_Events server_events (UDP_PORT, + MCAST_ADDR, + DURATION); + // Instance of the ACE_Reactor. + ACE_Reactor reactor; + + if (reactor.register_handler (&server_events, + ACE_Event_Handler::READ_MASK) == -1) + ACE_ERROR ((LM_ERROR, + "%p\n%a", + "register_handler", + 1)); + + ACE_DEBUG ((LM_DEBUG, + "starting up server\n")); + + for (;;) + reactor.handle_events (server_events.wait_time ()); + + ACE_NOTREACHED (return 0;) +} +#else +int +main (int, char *argv[]) +{ + ACE_ERROR_RETURN ((LM_ERROR, + "error: %s must be run on a platform that support IP multicast\n", + argv[0]), -1); +} +#endif /* ACE_HAS_IP_MULTICAST */ diff --git a/ACE/examples/Reactor/Ntalker/.cvsignore b/ACE/examples/Reactor/Ntalker/.cvsignore new file mode 100644 index 00000000000..a9350d173bf --- /dev/null +++ b/ACE/examples/Reactor/Ntalker/.cvsignore @@ -0,0 +1,2 @@ +ntalker +ntalker diff --git a/ACE/examples/Reactor/Ntalker/Makefile.am b/ACE/examples/Reactor/Ntalker/Makefile.am new file mode 100644 index 00000000000..6efc3521a32 --- /dev/null +++ b/ACE/examples/Reactor/Ntalker/Makefile.am @@ -0,0 +1,33 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +ACE_BUILDDIR = $(top_builddir) +ACE_ROOT = $(top_srcdir) + +## Makefile.Reactor_Ntalker.am +noinst_PROGRAMS = ntalker + +ntalker_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +ntalker_SOURCES = \ + ntalker.cpp + +ntalker_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Clean up template repositories, etc. +clean-local: + -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.* + -rm -f gcctemp.c gcctemp so_locations *.ics + -rm -rf cxx_repository ptrepository ti_files + -rm -rf templateregistry ir.out + -rm -rf ptrepository SunWS_cache Templates.DB diff --git a/ACE/examples/Reactor/Ntalker/README b/ACE/examples/Reactor/Ntalker/README new file mode 100644 index 00000000000..191cef9256f --- /dev/null +++ b/ACE/examples/Reactor/Ntalker/README @@ -0,0 +1,17 @@ +This test program illustrates how the ACE datagram multicast feature +works. To run the test simply do the following on multiple machines: + +# Machine 1 +% ./ntalker + +# Machine 2 +% ./ntalker + +# Machine 3 +% ./ntalker + +Then, on one (or all) of the machines, type input into the keyboard. +This input will be multicast to all the machines using IP multicast +via the ACE_SOCK_Dgram_Mcast wrapper. + +When you want to shut down the sender, just type ^D. diff --git a/ACE/examples/Reactor/Ntalker/Reactor_Ntalker.mpc b/ACE/examples/Reactor/Ntalker/Reactor_Ntalker.mpc new file mode 100644 index 00000000000..ef2fb84d9a0 --- /dev/null +++ b/ACE/examples/Reactor/Ntalker/Reactor_Ntalker.mpc @@ -0,0 +1,6 @@ +// -*- MPC -*- +// $Id$ + +project : aceexe { + exename = ntalker +} diff --git a/ACE/examples/Reactor/Ntalker/ntalker.cpp b/ACE/examples/Reactor/Ntalker/ntalker.cpp new file mode 100644 index 00000000000..80873ead1a9 --- /dev/null +++ b/ACE/examples/Reactor/Ntalker/ntalker.cpp @@ -0,0 +1,231 @@ +// $Id$ + +// Listens to multicast address. After first message received, will +// listen for 5 more seconds. Prints Mbits/sec received from client. + +#include "ace/OS_main.h" +#include "ace/OS_NS_unistd.h" +#include "ace/INET_Addr.h" +#include "ace/SOCK_Dgram_Mcast.h" +#include "ace/Reactor.h" +#include "ace/Get_Opt.h" +#include "ace/Thread_Manager.h" +#include "ace/Service_Config.h" + +ACE_RCSID(Ntalker, ntalker, "$Id$") + +#if defined (ACE_HAS_IP_MULTICAST) +// Network interface to subscribe to. This is hardware specific. use +// netstat(1M) to find whether your interface is le0 or ie0 + +static const ACE_TCHAR *INTERFACE = 0; +static const char *MCAST_ADDR = ACE_DEFAULT_MULTICAST_ADDR; +static const u_short UDP_PORT = ACE_DEFAULT_MULTICAST_PORT; + +class Handler : public ACE_Event_Handler +{ + // = TITLE + // Handle both multicast and stdin events. +public: + // = Initialization and termination methods. + Handler (u_short udp_port, + const char *ip_addr, + const ACE_TCHAR *a_interface, + ACE_Reactor & ); + // Constructor. + + ~Handler (void); + // Destructor. + + // Event demuxer hooks. + virtual int handle_input (ACE_HANDLE); + virtual int handle_close (ACE_HANDLE, + ACE_Reactor_Mask); + virtual ACE_HANDLE get_handle (void) const; + +private: + ACE_SOCK_Dgram_Mcast mcast_; + // Multicast wrapper. +}; + +ACE_HANDLE +Handler::get_handle (void) const +{ + return this->mcast_.get_handle (); +} + +int +Handler::handle_input (ACE_HANDLE h) +{ + char buf[BUFSIZ]; + + if (h == ACE_STDIN) + { + ssize_t result = ACE_OS::read (h, buf, BUFSIZ); + + if (result > 0) + { + if (this->mcast_.send (buf, result) != result) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "send error"), + -1); + return 0; + } + else if (result == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "can't read from STDIN"), + -1); + else // result == 0 + { + ACE_Reactor::end_event_loop (); + return -1; + } + } + else + { + ACE_INET_Addr remote_addr; + + // Receive message from multicast group. + ssize_t result = this->mcast_.recv (buf, + sizeof buf, + remote_addr); + + if (result != -1) + { + ACE_DEBUG ((LM_DEBUG, + "received datagram from host %s on port %d bytes = %d\n", + remote_addr.get_host_name (), + remote_addr.get_port_number (), + result)); + ACE_OS::write (ACE_STDERR, buf, result); + ACE_DEBUG ((LM_DEBUG, + "\n")); + return 0; + } + + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "something amiss"), + -1); + } +} + +int +Handler::handle_close (ACE_HANDLE h, ACE_Reactor_Mask) +{ + if (h == ACE_STDIN) + { + ACE_DEBUG ((LM_DEBUG, + "STDIN_Events handle removed from reactor.\n")); + if (ACE_Reactor::instance ()->remove_handler + (this, ACE_Event_Handler::READ_MASK) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "remove_handler"), + -1); + } + else + ACE_DEBUG ((LM_DEBUG, + "Mcast_Events handle removed from reactor.\n")); + return 0; +} + +Handler::~Handler (void) +{ + if (this->mcast_.unsubscribe () == -1) + ACE_ERROR ((LM_ERROR, + "%p\n", + "unsubscribe fails")); +} + +Handler::Handler (u_short udp_port, + const char *ip_addr, + const ACE_TCHAR *a_interface, + ACE_Reactor &reactor) +{ + // Create multicast address to listen on. + + ACE_INET_Addr sockmc_addr (udp_port, ip_addr); + + // subscribe to multicast group. + + if (this->mcast_.subscribe (sockmc_addr, 1, a_interface) == -1) + { + ACE_ERROR ((LM_ERROR, + "%p\n", + "can't subscribe to multicast group")); + } + // Disable loopbacks. + // if (this->mcast_.set_option (IP_MULTICAST_LOOP, 0) == -1 ) + // ACE_OS::perror (" can't disable loopbacks " ), ACE_OS::exit (1); + + // Register callbacks with the ACE_Reactor. + else if (reactor.register_handler (this->mcast_.get_handle (), + this, + ACE_Event_Handler::READ_MASK) == -1) + ACE_ERROR ((LM_ERROR, + "%p\n", + "can't register with Reactor\n")); + // Register the STDIN handler. + else if (ACE_Event_Handler::register_stdin_handler (this, + ACE_Reactor::instance (), + ACE_Thread_Manager::instance ()) == -1) + ACE_ERROR ((LM_ERROR, + "%p\n", + "register_stdin_handler")); +} + +static void +parse_args (int argc, ACE_TCHAR *argv[]) +{ + ACE_Get_Opt get_opt (argc, argv, ACE_TEXT("i:u")); + + int c; + + while ((c = get_opt ()) != -1) + switch (c) + { + case 'i': + INTERFACE = get_opt.opt_arg (); + break; + case 'u': + // Usage fallthrough. + default: + ACE_DEBUG ((LM_DEBUG, + "%s -i interface\n", + argv[0])); + ACE_OS::exit (1); + } +} + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + parse_args (argc, argv); + + Handler handler (UDP_PORT, + MCAST_ADDR, + INTERFACE, + *ACE_Reactor::instance ()); + + // Run the event loop. + ACE_Reactor::run_event_loop (); + + ACE_DEBUG ((LM_DEBUG, + "talker Done.\n")); + return 0; +} + +#else +int +ACE_TMAIN (int, ACE_TCHAR *argv[]) +{ + ACE_ERROR_RETURN ((LM_ERROR, + "error: %s must be run on a platform that support IP multicast\n", + argv[0]), + 0); +} +#endif /* ACE_HAS_IP_MULTICAST */ + diff --git a/ACE/examples/Reactor/Proactor/.cvsignore b/ACE/examples/Reactor/Proactor/.cvsignore new file mode 100644 index 00000000000..34179361b75 --- /dev/null +++ b/ACE/examples/Reactor/Proactor/.cvsignore @@ -0,0 +1,7 @@ +test_cancel +test_end_event_loop +test_multiple_loops +test_post_completions +test_proactor +test_timeout +test_udp_proactor diff --git a/ACE/examples/Reactor/Proactor/Aio_Platform_Test_C.cpp b/ACE/examples/Reactor/Proactor/Aio_Platform_Test_C.cpp new file mode 100644 index 00000000000..be720fdef40 --- /dev/null +++ b/ACE/examples/Reactor/Proactor/Aio_Platform_Test_C.cpp @@ -0,0 +1,137 @@ +// $Id$ +// ============================================================================ +// +// = FILENAME +// aio_platform_test_c.cpp +// +// = DESCRITPTION +// Testing the platform for POSIX Asynchronous I/O. This is the C +// version of the $ACE_ROOT/tests/Aio_Platform_Test.cpp. Useful +// to send bug reports. +// +// = AUTHOR +// Programming for the Real World. Bill O. GallMeister. +// Modified by Alexander Babu Arulanthu <alex@cs.wustl.edu> +// +// ===================================================================== + + +#include <unistd.h> +#include <fcntl.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <signal.h> +#include <string.h> +#include <errno.h> +#include <stdio.h> + +#include <limits.h> + +#include <aio.h> + +int do_sysconf (void); +int have_asynchio (void); + +static int file_handle = -1; +char mb1 [BUFSIZ + 1]; +char mb2 [BUFSIZ + 1]; +aiocb aiocb1, aiocb2; +sigset_t completion_signal; + +// For testing the <aio> stuff. +int test_aio_calls (void); +int issue_aio_calls (void); +int query_aio_completions (void); +int setup_signal_delivery (void); +int do_sysconf (void); +int have_asynchio (void); + +int +do_sysconf (void) +{ + // Call sysconf to find out runtime values. + errno = 0; +#if defined (_SC_LISTIO_AIO_MAX) + printf ("Runtime value of LISTIO_AIO_MAX is %d, errno = %d\n", + sysconf(_SC_LISTIO_AIO_MAX), + errno); +#else + printf ("Runtime value of AIO_LISTIO_MAX is %d, errno = %d\n", + sysconf(_SC_AIO_LISTIO_MAX), + errno); +#endif + + errno = 0; + printf ("Runtime value of AIO_MAX is %d, errno = %d\n", + sysconf (_SC_AIO_MAX), + errno); + + errno = 0; + printf ("Runtime value of _POSIX_ASYNCHRONOUS_IO is %d, errno = %d\n", + sysconf (_SC_ASYNCHRONOUS_IO), + errno); + + errno = 0; + printf ("Runtime value of _POSIX_REALTIME_SIGNALS is %d, errno = %d\n", + sysconf (_SC_REALTIME_SIGNALS), + errno); + + errno = 0; + printf ("Runtime value of RTSIG_MAX %d, Errno = %d\n", + sysconf (_SC_RTSIG_MAX), + errno); + + errno = 0; + printf ("Runtime value of SIGQUEUE_MAX %d, Errno = %d\n", + sysconf (_SC_SIGQUEUE_MAX), + errno); + return 0; +} + +int +have_asynchio (void) +{ +#if defined (_POSIX_ASYNCHRONOUS_IO) + // POSIX Asynch IO is present in this system. +#if defined (_POSIX_ASYNC_IO) + // If this is defined and it is not -1, POSIX_ASYNCH is supported + // everywhere in the system. +#if _POSIX_ASYNC_IO == -1 + printf ("_POSIX_ASYNC_IO = -1.. ASYNCH IO NOT supported at all\n"); + return -1; +#else /* Not _POSIX_ASYNC_IO == -1 */ + printf ("_POSIX_ASYNC_IO = %d\n ASYNCH IO is supported FULLY\n", + _POSIX_ASYNC_IO); +#endif /* _POSIX_ASYNC_IO == -1 */ + +#else /* Not defined _POSIX_ASYNC_IO */ + printf ("_POSIX_ASYNC_IO is not defined.\n"); + printf ("AIO might *not* be supported on some paths\n"); +#endif /* _POSIX_ASYNC_IO */ + + // System defined POSIX Values. + printf ("System claims to have POSIX_ASYNCHRONOUS_IO\n"); + + printf ("_POSIX_AIO_LISTIO_MAX = %d\n", _POSIX_AIO_LISTIO_MAX); + printf ("_POSIX_AIO_MAX = %d\n", _POSIX_AIO_MAX); + + // Check and print the run time values. + do_sysconf (); + + return 0; + +#else /* Not _POSIX_ASYNCHRONOUS_IO */ + printf ("No support._POSIX_ASYNCHRONOUS_IO itself is not defined\n"); + return -1; +#endif /* _POSIX_ASYNCHRONOUS_IO */ +} + +int +main (int, char *[]) +{ + if (have_asynchio () == 0) + printf ("Test successful\n"); + else + printf ("Test not successful\n"); + return 0; +} diff --git a/ACE/examples/Reactor/Proactor/Makefile.am b/ACE/examples/Reactor/Proactor/Makefile.am new file mode 100644 index 00000000000..7f1bc4b8a57 --- /dev/null +++ b/ACE/examples/Reactor/Proactor/Makefile.am @@ -0,0 +1,153 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +ACE_BUILDDIR = $(top_builddir) +ACE_ROOT = $(top_srcdir) + +noinst_PROGRAMS = + +## Makefile.Proactor_Cancel.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS += test_cancel + +test_cancel_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +test_cancel_SOURCES = \ + test_cancel.cpp \ + test_cancel.h + +test_cancel_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Makefile.Proactor_End_Event_Loops.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS += test_end_event_loop + +test_end_event_loop_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +test_end_event_loop_SOURCES = \ + test_end_event_loop.cpp \ + test_cancel.h \ + test_proactor.h + +test_end_event_loop_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Makefile.Proactor_Multiple_Loops.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS += test_multiple_loops + +test_multiple_loops_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +test_multiple_loops_SOURCES = \ + test_multiple_loops.cpp \ + test_cancel.h \ + test_proactor.h + +test_multiple_loops_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Makefile.Proactor_Post_Completions.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS += test_post_completions + +test_post_completions_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +test_post_completions_SOURCES = \ + post_completions.cpp \ + test_cancel.h \ + test_proactor.h + +test_post_completions_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Makefile.Proactor_Proactor.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS += test_proactor + +test_proactor_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +test_proactor_SOURCES = \ + test_proactor.cpp \ + test_proactor.h + +test_proactor_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Makefile.Proactor_Timeout.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS += test_timeout + +test_timeout_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +test_timeout_SOURCES = \ + test_timeout.cpp \ + test_cancel.h \ + test_proactor.h + +test_timeout_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Makefile.Proactor_Udp_Proactor.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS += test_udp_proactor + +test_udp_proactor_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +test_udp_proactor_SOURCES = \ + test_udp_proactor.cpp \ + test_cancel.h \ + test_proactor.h + +test_udp_proactor_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Clean up template repositories, etc. +clean-local: + -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.* + -rm -f gcctemp.c gcctemp so_locations *.ics + -rm -rf cxx_repository ptrepository ti_files + -rm -rf templateregistry ir.out + -rm -rf ptrepository SunWS_cache Templates.DB diff --git a/ACE/examples/Reactor/Proactor/Proactor.mpc b/ACE/examples/Reactor/Proactor/Proactor.mpc new file mode 100644 index 00000000000..c2c52207ca1 --- /dev/null +++ b/ACE/examples/Reactor/Proactor/Proactor.mpc @@ -0,0 +1,59 @@ +// -*- MPC -*- +// $Id$ + +project(*cancel) : aceexe { + avoids += ace_for_tao + exename = test_cancel + Source_Files { + test_cancel.cpp + } +} + +project(*end_event_loops) : aceexe { + avoids += ace_for_tao + exename = test_end_event_loop + Source_Files { + test_end_event_loop.cpp + } +} + +project(*multiple_loops) : aceexe { + avoids += ace_for_tao + exename = test_multiple_loops + Source_Files { + test_multiple_loops.cpp + } +} + +project(*post_completions) : aceexe { + avoids += ace_for_tao + exename = test_post_completions + Source_Files { + post_completions.cpp + } +} + +project(*proactor) : aceexe { + avoids += ace_for_tao + exename = test_proactor + Source_Files { + test_proactor.cpp + } +} + +project(*timeout) : aceexe { + avoids += ace_for_tao + exename = test_timeout + Source_Files { + test_timeout.cpp + } +} + +project(*udp_proactor) : aceexe { + avoids += ace_for_tao + exename = test_udp_proactor + Source_Files { + test_udp_proactor.cpp + } +} + diff --git a/ACE/examples/Reactor/Proactor/README b/ACE/examples/Reactor/Proactor/README new file mode 100644 index 00000000000..29f2a0b1832 --- /dev/null +++ b/ACE/examples/Reactor/Proactor/README @@ -0,0 +1,75 @@ +$Id$ + +This README file lists all the example applications for the Proactor framework. + +Test/Example Applications for Proactor: +========================================= + +The following tests are available. + +o $ACE_ROOT/tests/Aio_Platform_Test.cpp : Tests basic limits + pertaining to the POSIX features + +o $ACE_ROOT/examples/Reactor/Proactor/test_aiocb.cpp : + This is a C++ program for testing the AIOCB (AIO Control + Blocks) based completion approach which uses <aio_suspend> for + completion querying. + +o $ACE_ROOT/examples/Reactor/Proactor/test_aiosig.cpp : This is a + C++ program for testing the Signal based completion approach + that uses <sigtimedwait> for completion querying. + +o $ACE_ROOT/examples/Reactor/Proactor/test_aiocb_ace.cpp: Portable + version of test_aiocb.cpp. (Same as test_aiocb.cpp, but uses + ACE_DEBUGs instead of printf's and ACE_Message_Blocks instead + of char*'s. + +o $ACE_ROOT/examples/Reactor/Proactor/test_aiosig_ace.cpp: Portable + version of test_aiosig.cpp. (Same as test_aiosig.cpp, but uses + ACE_DEBUGs instead of printf's and ACE_Message_Blocks instead + of char*'s. + +o test_proactor.cpp (with ACE_POSIX_AIOCB_Proactor) : Test for + ACE_Proactor which uses AIOCB (AIO Control Blocks) based + completions strategy Proactor. (#define + ACE_POSIX_AIOCB_PROACTOR in the config file, but this is the + default option) + +o test_proactor.cpp (with ACE_POSIX_SIG_Proactor) : Test for + ACE_Proactor which uses real time signal based completion + strategy proactor. (#define ACE_POSIX_SIG_PROACTOR in the + config file) + +o test_multiple_loops.cpp : This example application shows how + to write programs that combine the Proactor and Reactor event + loops. This is possible only on WIN32 platform. + +o test_timeout.cpp : Multithreaded application testing the Timers + mechanism of the Proactor. + +o test_timeout_st.cpp : Single-threaded version of test_timeout.cpp. + +o post_completions.cpp : Tests the completion posting mechanism of + the Proactor. + +o test_end_event_loop.cpp : Tests the event loop mechanism of the + Proactor. + +o test_cancel.cpp : Tests <cancel> interface of the + Asynch_Operation class. + +Behavior of POSIX AIO of various platforms: +========================================== + +Sun 5.6 : POSIX4 Real-Time signals implementation is broken in + this platform. + Only POSIX AIOCB Proactor works in this platform. + Therefore, it is not possible to use multiple threads + with in the framework. + +Sun 5.7 : AIOCB and SIG Proactors work fine. + +LynxOS 3.0.0 : <pthread_sigmask> is not available in this + platform. So, only AIOCB Proactor works here. + + diff --git a/ACE/examples/Reactor/Proactor/post_completions.cpp b/ACE/examples/Reactor/Proactor/post_completions.cpp new file mode 100644 index 00000000000..e6545241953 --- /dev/null +++ b/ACE/examples/Reactor/Proactor/post_completions.cpp @@ -0,0 +1,306 @@ +// $Id$ +// ============================================================================ +// +// = FILENAME +// post_completions.cpp +// +// = DESCRITPTION +// This program demonstrates how to post fake completions to The +// Proactor. It also shows the how to specify the particular +// real-time signals to post completions. The Real-time signal +// based completion strategy is implemented with +// ACE_POSIX_SIG_PROACTOR. +// (So, it can be used only if both ACE_HAS_AIO_CALLS and +// ACE_HAS_POSIX_REALTIME_SIGNALS are defined.) +// Since it is faking results, you have to pay by knowing and +// using platform-specific implementation objects for Asynchronous +// Result classes. +// This example shows using an arbitrary result class for faking +// completions. You can also use the predefined Result classes for +// faking. The factory methods in the Proactor class create the +// Result objects. +// +// = COMPILATION +// make +// +// = RUN +// ./post_completions +// +// = AUTHOR +// Alexander Babu Arulanthu <alex@cs.wustl.edu> +// +// ===================================================================== + +#include "ace/OS_NS_unistd.h" +#include "ace/OS_main.h" +#include "ace/Proactor.h" +#include "ace/Task.h" +#include "ace/WIN32_Proactor.h" +#include "ace/POSIX_Proactor.h" +#include "ace/Atomic_Op.h" +#include "ace/Thread_Mutex.h" + +// Keep track of how many completions are still expected. +static ACE_Atomic_Op <ACE_SYNCH_MUTEX, size_t> Completions_To_Go; + + +#if (defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)) || \ + defined (ACE_HAS_AIO_CALLS) +// This only works on Win32 platforms and on Unix platforms supporting +// POSIX aio calls. + +#if defined (ACE_HAS_AIO_CALLS) +#define RESULT_CLASS ACE_POSIX_Asynch_Result +#elif defined (ACE_WIN32) && !defined (ACE_HAS_WINCE) +#define RESULT_CLASS ACE_WIN32_Asynch_Result +#endif /* ACE_HAS_AIO_CALLS */ + +class My_Result : public RESULT_CLASS +{ + // = TITLE + // + // Result Object that we will post to the Proactor. + // + // = DESCRIPTION + // + +public: + My_Result (ACE_Handler &handler, + const void *act, + int signal_number, + size_t sequence_number) + : RESULT_CLASS (handler.proxy (), + act, + ACE_INVALID_HANDLE, + 0, // Offset + 0, // OffsetHigh + 0, // Priority + signal_number), + sequence_number_ (sequence_number) + {} + // Constructor. + + virtual ~My_Result (void) + {} + // Destructor. + + void complete (size_t, + int success, + const void *completion_key, + u_long error) + // This is the method that will be called by the Proactor for + // dispatching the completion. This method generally calls one of + // the call back hood methods defined in the ACE_Handler + // class. But, we will just handle the completions here. + { + this->success_ = success; + this->completion_key_ = completion_key; + this->error_ = error; + + size_t to_go = --Completions_To_Go; + + // Print the completion details. + ACE_DEBUG ((LM_DEBUG, + "(%t) Completion sequence number %d, success : %d, error : %d, signal_number : %d, %u more to go\n", + this->sequence_number_, + this->success_, + this->error_, + this->signal_number (), + to_go)); + + // Sleep for a while. + ACE_OS::sleep (4); + } + +private: + size_t sequence_number_; + // Sequence number for the result object. +}; + +class My_Handler : public ACE_Handler +{ + // = TITLE + // + // Handler class for faked completions. + // + // = DESCRIPTION + // + +public: + My_Handler (void) {} + // Constructor. + + virtual ~My_Handler (void) {} + // Destructor. +}; + +class My_Task: public ACE_Task <ACE_NULL_SYNCH> +{ + // = TITLE + // + // Contains thread functions which execute event loops. Each + // thread waits for a different signal. + // +public: + My_Task (void) {} + // Constructor. + + virtual ~My_Task (void) {} + // Destructor. + + int open (void *proactor) + { + // Store the proactor. + this->proactor_ = (ACE_Proactor *) proactor; + + // Activate the Task. + this->activate (THR_NEW_LWP, 5); + return 0; + } + + int svc (void) + { + // Handle events for 13 seconds. + ACE_Time_Value run_time (13); + + ACE_DEBUG ((LM_DEBUG, "(%t):Starting svc routine\n")); + + if (this->proactor_->handle_events (run_time) == -1) + ACE_ERROR_RETURN ((LM_ERROR, "(%t):%p.\n", "Worker::svc"), -1); + + ACE_DEBUG ((LM_DEBUG, "(%t) work complete\n")); + + return 0; + } + +private: + ACE_Proactor *proactor_; + // Proactor for this task. +}; + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + ACE_UNUSED_ARG (argc); + ACE_UNUSED_ARG (argv); + + ACE_DEBUG ((LM_DEBUG, + "(%P | %t):Test starts \n")); + + // = Get two POSIX_SIG_Proactors, one with SIGRTMIN and one with + // SIGRTMAX. + + ACE_Proactor proactor1; + // Proactor1. SIGRTMIN Proactor. (default). + + // = Proactor2. SIGRTMAX Proactor. +#if defined (ACE_HAS_AIO_CALLS) && defined (ACE_HAS_POSIX_REALTIME_SIGNALS) + + ACE_DEBUG ((LM_DEBUG, "Using ACE_POSIX_SIG_Proactor\n")); + + sigset_t signal_set; + // Signal set that we want to mask. + + // Clear the signal set. + if (sigemptyset (&signal_set) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "Error:%p\n", + "sigemptyset failed"), + 1); + + // Add the SIGRTMAX to the signal set. + if (sigaddset (&signal_set, ACE_SIGRTMAX) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "Error:%p\n", + "sigaddset failed"), + 1); + + // Make the POSIX Proactor. + ACE_POSIX_SIG_Proactor posix_proactor (signal_set); + // Get the Proactor interface out of it. + ACE_Proactor proactor2 (&posix_proactor); +#else /* ACE_HAS_AIO_CALLS && ACE_HAS_POSIX_REALTIME_SIGNALS */ + ACE_Proactor proactor2; +#endif /* ACE_HAS_AIO_CALLS && ACE_HAS_POSIX_REALTIME_SIGNALS */ + + // = Create Tasks. One pool of threads to handle completions on + // SIGRTMIN and the other one to handle completions on SIGRTMAX. + My_Task task1, task2; + task1.open (&proactor1); + task2.open (&proactor2); + + // Handler for completions. + My_Handler handler; + + // = Create a few MyResult objects and post them to Proactor. + const size_t NrCompletions (10); + My_Result *result_objects [NrCompletions]; + int signal_number = ACE_SIGRTMAX; + size_t ri = 0; + + Completions_To_Go = NrCompletions; + + // Creation. + for (ri = 0; ri < NrCompletions; ri++) + { + // Use RTMIN and RTMAX proactor alternatively, to post + // completions. + if (ri % 2) + signal_number = ACE_SIGRTMIN; + else + signal_number = ACE_SIGRTMAX; + // Create the result. + ACE_NEW_RETURN (result_objects [ri], + My_Result (handler, + 0, + signal_number, + ri), + 1); + } + ACE_OS::sleep(5); + // Post all the result objects. + ACE_Proactor *proactor; + for (ri = 0; ri < NrCompletions; ri++) + { + // Use RTMIN and RTMAX Proactor alternatively, to post + // completions. + if (ri % 2) + proactor = &proactor1; + else + proactor = &proactor2; + if (result_objects [ri]->post_completion (proactor->implementation ()) + == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "Test failed\n"), + 1); + } + + ACE_Thread_Manager::instance ()->wait (); + + int status = 0; + size_t to_go = Completions_To_Go.value (); + if (size_t (0) != to_go) + { + ACE_ERROR ((LM_ERROR, + "Fail! Expected all completions to finish but %u to go\n", + to_go)); + status = 1; + } + + ACE_DEBUG ((LM_DEBUG, + "(%P | %t):Test ends\n")); + return status; +} + +#else /* ACE_WIN32 && !ACE_HAS_WINCE || ACE_HAS_AIO_CALLS && !ACE_POSIX_AIOCB_PROACTOR*/ + +int +main (int, char *[]) +{ + ACE_DEBUG ((LM_DEBUG, + "This example cannot work with AIOCB_Proactor.\n")); + return 1; +} + +#endif /* ACE_WIN32 && !ACE_HAS_WINCE || ACE_HAS_AIO_CALLS && !ACE_POSIX_AIOCB_PROACTOR*/ + diff --git a/ACE/examples/Reactor/Proactor/simple_test_proactor.cpp b/ACE/examples/Reactor/Proactor/simple_test_proactor.cpp new file mode 100644 index 00000000000..1f4557d7df5 --- /dev/null +++ b/ACE/examples/Reactor/Proactor/simple_test_proactor.cpp @@ -0,0 +1,269 @@ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// examples +// +// = FILENAME +// simple_test_proactor.cpp +// +// = DESCRIPTION +// Very simple version of test_proactor.cpp. +// +// = AUTHOR +// Alexander Babu Arulanthu (alex@cs.wustl.edu) +// +// ============================================================================ + +#include "ace/Service_Config.h" +#include "ace/Proactor.h" +#include "ace/Asynch_IO.h" +#include "ace/Asynch_IO_Impl.h" +#include "ace/Message_Block.h" +#include "ace/Get_Opt.h" +#include "ace/OS_main.h" + +ACE_RCSID(Proactor, test_proactor, "simple_test_proactor.cpp,v 1.1 1999/05/18 22:15:30 alex Exp") + +#if ((defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)) || (defined (ACE_HAS_AIO_CALLS))) + // This only works on Win32 platforms and on Unix platforms supporting + // POSIX aio calls. + +static ACE_TCHAR *file = ACE_TEXT("simple_test_proactor.cpp"); +static ACE_TCHAR *dump_file = ACE_TEXT("simple_output"); + +class Simple_Tester : public ACE_Handler +{ + // = TITLE + // + // Simple_Tester + // + // = DESCRIPTION + // + // The class will be created by main(). This class reads a block + // from the file and write that to the dump file. + +public: + Simple_Tester (void); + // Constructor. + + ~Simple_Tester (void); + + int open (void); + // Open the operations and initiate read from the file. + +protected: + // = These methods are called by the freamwork. + + virtual void handle_read_file (const ACE_Asynch_Read_File::Result &result); + // This is called when asynchronous reads from the socket complete. + + virtual void handle_write_file (const ACE_Asynch_Write_File::Result &result); + // This is called when asynchronous writes from the socket complete. + +private: + int initiate_read_file (void); + + ACE_Asynch_Read_File rf_; + // rf (read file): for writing from the file. + + ACE_Asynch_Write_File wf_; + // ws (write File): for writing to the file. + + ACE_HANDLE input_file_; + // File to read from. + + ACE_HANDLE dump_file_; + // File for dumping data. + + // u_long file_offset_; + // Current file offset + + // u_long file_size_; + // File size +}; + + +Simple_Tester::Simple_Tester (void) + : input_file_ (ACE_INVALID_HANDLE), + dump_file_ (ACE_INVALID_HANDLE) +{ +} + +Simple_Tester::~Simple_Tester (void) +{ + ACE_OS::close (this->input_file_); + ACE_OS::close (this->dump_file_); +} + + +int +Simple_Tester::open (void) +{ + // Initialize stuff + + // Open input file (in OVERLAPPED mode) + this->input_file_ = ACE_OS::open (file, + GENERIC_READ | FILE_FLAG_OVERLAPPED); + if (this->input_file_ == ACE_INVALID_HANDLE) + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "ACE_OS::open"), -1); + + // Open dump file (in OVERLAPPED mode) + this->dump_file_ = ACE_OS::open (dump_file, + O_CREAT | O_RDWR | O_TRUNC | FILE_FLAG_OVERLAPPED, + 0644); + if (this->dump_file_ == ACE_INVALID_HANDLE) + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "ACE_OS::open"), -1); + + // Open ACE_Asynch_Read_File + if (this->rf_.open (*this, this->input_file_) == -1) + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "ACE_Asynch_Read_File::open"), -1); + + // Open ACE_Asynch_Write_File + if (this->wf_.open (*this, this->dump_file_) == -1) + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "ACE_Asynch_Write_File::open"), -1); + + ACE_DEBUG ((LM_DEBUG, + "Simple_Tester::open: Files and Asynch Operations opened sucessfully\n")); + + + // Start an asynchronous read file + if (this->initiate_read_file () == -1) + return -1; + + return 0; +} + + +int +Simple_Tester::initiate_read_file (void) +{ + // Create Message_Block + ACE_Message_Block *mb = 0; + ACE_NEW_RETURN (mb, ACE_Message_Block (BUFSIZ + 1), -1); + + // Inititiate an asynchronous read from the file + if (this->rf_.read (*mb, + mb->size () - 1) == -1) + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "ACE_Asynch_Read_File::read"), -1); + + ACE_DEBUG ((LM_DEBUG, + "Simple_Tester:initiate_read_file: Asynch Read File issued sucessfully\n")); + + return 0; +} + +void +Simple_Tester::handle_read_file (const ACE_Asynch_Read_File::Result &result) +{ + ACE_DEBUG ((LM_DEBUG, "handle_read_file called\n")); + + result.message_block ().rd_ptr ()[result.bytes_transferred ()] = '\0'; + + ACE_DEBUG ((LM_DEBUG, "********************\n")); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "bytes_to_read", result.bytes_to_read ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "handle", result.handle ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "bytes_transfered", result.bytes_transferred ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "act", (u_long) result.act ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "success", result.success ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "completion_key", (u_long) result.completion_key ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "error", result.error ())); + ACE_DEBUG ((LM_DEBUG, "********************\n")); + // Watch out if you need to enable this... the ACE_Log_Record::MAXLOGMSGLEN + // value controls to max length of a log record, and a large output + // buffer may smash it. +#if 0 + ACE_DEBUG ((LM_DEBUG, "%s = %s\n", + "message_block", + result.message_block ().rd_ptr ())); +#endif /* 0 */ + + if (result.success ()) + { + // Read successful: write this to the file. + if (this->wf_.write (result.message_block (), + result.bytes_transferred ()) == -1) + { + ACE_ERROR ((LM_ERROR, "%p\n", "ACE_Asynch_Write_File::write")); + return; + } + } +} + +void +Simple_Tester::handle_write_file (const ACE_Asynch_Write_File::Result &result) +{ + ACE_DEBUG ((LM_DEBUG, "handle_write_File called\n")); + + // Reset pointers + result.message_block ().rd_ptr (result.message_block ().rd_ptr () - result.bytes_transferred ()); + + result.message_block ().rd_ptr ()[result.bytes_transferred ()] = '\0'; + + ACE_DEBUG ((LM_DEBUG, "********************\n")); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "bytes_to_write", result.bytes_to_write ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "handle", result.handle ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "bytes_transfered", result.bytes_transferred ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "act", (u_long) result.act ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "success", result.success ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "completion_key", (u_long) result.completion_key ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "error", result.error ())); + ACE_DEBUG ((LM_DEBUG, "********************\n")); + // Watch out if you need to enable this... the ACE_Log_Record::MAXLOGMSGLEN + // value controls to max length of a log record, and a large output + // buffer may smash it. +#if 0 + ACE_DEBUG ((LM_DEBUG, "%s = %s\n", + "message_block", + result.message_block ().rd_ptr ())); +#endif /* 0 */ + ACE_Proactor::end_event_loop (); +} + +static int +parse_args (int argc, ACE_TCHAR *argv[]) +{ + ACE_Get_Opt get_opt (argc, argv, ACE_TEXT("f:d:")); + int c; + + while ((c = get_opt ()) != EOF) + switch (c) + { + case 'f': + file = get_opt.opt_arg (); + break; + case 'd': + dump_file = get_opt.opt_arg (); + break; + default: + ACE_ERROR ((LM_ERROR, "%p.\n", + "usage :\n" + "-d <dumpfile>\n" + "-f <file>\n")); + return -1; + } + + return 0; +} + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + if (parse_args (argc, argv) == -1) + return -1; + + Simple_Tester Simple_Tester; + + if (Simple_Tester.open () == -1) + return -1; + + int success = 1; + + // dispatch events + success = !(ACE_Proactor::run_event_loop () == -1); + + return success ? 0 : 1; +} + +#endif /* ACE_WIN32 && !ACE_HAS_WINCE || ACE_HAS_AIO_CALLS*/ diff --git a/ACE/examples/Reactor/Proactor/test_aiocb.cpp b/ACE/examples/Reactor/Proactor/test_aiocb.cpp new file mode 100644 index 00000000000..c9c0d280f1b --- /dev/null +++ b/ACE/examples/Reactor/Proactor/test_aiocb.cpp @@ -0,0 +1,239 @@ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// proactor +// +// = FILENAME +// test_aiocb.cpp +// +// = DESCRIPTION +// Checkout $ACE_ROOT/examples/Reactor/Proactor/test_aiocb_ace.cpp, +// which is the ACE'ified version of this program. +// +// = COMPILE and RUN +// % CC -g -o test_aiocb -lrt test_aiocb.cpp +// % ./test_aiocb +// +// = AUTHOR +// Alexander Babu Arulanthu <alex@cs.wustl.edu> +// +// ============================================================================ + +#include <unistd.h> +#include <fcntl.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <signal.h> +#include <string.h> +#include <errno.h> +#include <stdio.h> +#include <iostream.h> + +#include <aio.h> + +class Test_Aio +{ +public: + Test_Aio (void); + // Default constructor. + + int init (void); + // Initting the output file and the buffer. + + int do_aio (void); + // Doing the testing stuff. + + ~Test_Aio (void); + // Destructor. +private: + int out_fd_; + // Output file descriptor. + + struct aiocb *aiocb_write_; + // For writing to the file. + + struct aiocb *aiocb_read_; + // Reading stuff from the file. + + char *buffer_write_; + // The buffer to be written to the out_fd. + + char *buffer_read_; + // The buffer to be read back from the file. +}; + +Test_Aio::Test_Aio (void) + : aiocb_write_ (new struct aiocb), + aiocb_read_ (new struct aiocb), + buffer_write_ (0), + buffer_read_ (0) +{ +} + +Test_Aio::~Test_Aio (void) +{ + delete aiocb_write_; + delete aiocb_read_; + delete buffer_write_; + delete buffer_read_; +} + +// Init the output file and init the buffer. +int +Test_Aio::init (void) +{ + // Open the output file. + this->out_fd_ = open ("test_aio.log", O_RDWR | O_CREAT | O_TRUNC, 0666); + if (this->out_fd_ == 0) + { + cout << "Error : Opening file" << endl; + return -1; + } + + // Init the buffers. + this->buffer_write_ = strdup ("Welcome to the world of AIO... AIO Rules !!!"); + cout << "The buffer : " << this->buffer_write_ << endl; + this->buffer_read_ = new char [strlen (this->buffer_write_) + 1]; + return 0; +} + +// Set the necessary things for the AIO stuff. +// Write the buffer asynchly.hmm Disable signals. +// Go on aio_suspend. Wait for completion. +// Print out the result. +int +Test_Aio::do_aio (void) +{ + // = Write to the file. + + // Setup AIOCB. + this->aiocb_write_->aio_fildes = this->out_fd_; + this->aiocb_write_->aio_offset = 0; + this->aiocb_write_->aio_buf = this->buffer_write_; + this->aiocb_write_->aio_nbytes = strlen (this->buffer_write_); + this->aiocb_write_->aio_reqprio = 0; + this->aiocb_write_->aio_sigevent.sigev_notify = SIGEV_NONE; + //this->this->aiocb_.aio_sigevent.sigev_signo = SIGRTMAX; + this->aiocb_write_->aio_sigevent.sigev_value.sival_ptr = + (void *) this->aiocb_write_; + + // Fire off the aio write. + if (aio_write (this->aiocb_write_) != 0) + { + perror ("aio_write"); + return -1; + } + + // = Read from that file. + + // Setup AIOCB. + this->aiocb_read_->aio_fildes = this->out_fd_; + this->aiocb_read_->aio_offset = 0; + this->aiocb_read_->aio_buf = this->buffer_read_; + this->aiocb_read_->aio_nbytes = strlen (this->buffer_write_); + this->aiocb_read_->aio_reqprio = 0; + this->aiocb_read_->aio_sigevent.sigev_notify = SIGEV_NONE; + //this->this->aiocb_.aio_sigevent.sigev_signo = SIGRTMAX; + this->aiocb_read_->aio_sigevent.sigev_value.sival_ptr = + (void *) this->aiocb_read_; + + // Fire off the aio write. If it doesnt get queued, carry on to get + // the completion for the first one. + if (aio_read (this->aiocb_read_) < 0) + perror ("aio_read"); + + // Wait for the completion on aio_suspend. + struct aiocb *list_aiocb[2]; + list_aiocb [0] = this->aiocb_write_; + list_aiocb [1] = this->aiocb_read_; + + // Do suspend till all the aiocbs in the list are done. + int done = 0; + int return_val = 0; + while (!done) + { + return_val = aio_suspend (list_aiocb, + 2, + 0); + cerr << "Return value :" << return_val << endl; + + // Analyze return and error values. + if (list_aiocb[0] != 0) + { + if (aio_error (list_aiocb [0]) != EINPROGRESS) + { + if (aio_return (list_aiocb [0]) == -1) + { + perror ("aio_return"); + return -1; + } + else + { + // Successful. Store the pointer somewhere and make the + // entry NULL in the list. + this->aiocb_write_ = list_aiocb [0]; + list_aiocb [0] = 0; + } + } + else + cout << "AIO write in progress" << endl; + } + + if (list_aiocb[1] != 0) + { + if (aio_error (list_aiocb [1]) != EINPROGRESS) + { + int read_return = aio_return (list_aiocb[1]); + if (read_return == -1) + { + perror ("aio_return"); + return -1; + } + else + { + // Successful. Store the pointer somewhere and make the + // entry NULL in the list. + this->aiocb_read_ = list_aiocb [1]; + list_aiocb [1] = 0; + this->buffer_read_[read_return] = '\0'; + } + } + else + cout << "AIO read in progress" << endl; + } + + // Is it done? + if ((list_aiocb [0] == 0) && (list_aiocb [1] == 0)) + done = 1; + } + + cout << "Both the AIO operations done." << endl; + cout << "The buffer is :" << this->buffer_read_ << endl; + + return 0; +} + +int +main (int argc, char **argv) +{ + Test_Aio test_aio; + + if (test_aio.init () != 0) + { + printf ("AIOCB test failed:\n" + "ACE_POSIX_AIOCB_PROACTOR may not work in this platform\n"); + return -1; + } + + if (test_aio.do_aio () != 0) + { + printf ("AIOCB test failed:\n" + "ACE_POSIX_AIOCB_PROACTOR may not work in this platform\n"); + return -1; + } + printf ("AIOCB test successful:\n" + "ACE_POSIX_AIOCB_PROACTOR should work in this platform\n"); + return 0; +} diff --git a/ACE/examples/Reactor/Proactor/test_aiocb_ace.cpp b/ACE/examples/Reactor/Proactor/test_aiocb_ace.cpp new file mode 100644 index 00000000000..17705de1f03 --- /dev/null +++ b/ACE/examples/Reactor/Proactor/test_aiocb_ace.cpp @@ -0,0 +1,259 @@ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// proactor +// +// = FILENAME +// test_aiocb_ace.cpp +// +// = DESCRIPTION +// This program helps you to test the <aio_*> calls on a +// platform. +// +// Before running this test, make sure the platform can +// support POSIX <aio_> calls, using +// ACE_ROOT/tests/Aio_Platform_Test. +// +// This program tests the AIOCB (AIO Control Blocks) based +// completion approach which uses <aio_suspend> for completion +// querying. +// +// If this test is successful, ACE_POSIX_AIOCB_PROACTOR +// can be used on this platform. +// +// = COMPILE and RUN +// % make +// % ./test_aiocb_ace +// +// = AUTHOR +// Alexander Babu Arulanthu <alex@cs.wustl.edu> +// +// ============================================================================ + +#include "ace/ACE.h" +#include "ace/Log_Msg.h" +#include "ace/os_include/os_aio.h" +#include "ace/OS_NS_string.h" + +class Test_Aio +{ +public: + Test_Aio (void); + // Default constructor. + + int init (void); + // Initting the output file and the buffer. + + int do_aio (void); + // Doing the testing stuff. + + ~Test_Aio (void); + // Destructor. +private: + int out_fd_; + // Output file descriptor. + + struct aiocb *aiocb_write_; + // For writing to the file. + + struct aiocb *aiocb_read_; + // Reading stuff from the file. + + char *buffer_write_; + // The buffer to be written to the out_fd. + + char *buffer_read_; + // The buffer to be read back from the file. +}; + +Test_Aio::Test_Aio (void) + : aiocb_write_ (0), + aiocb_read_ (0), + buffer_write_ (0), + buffer_read_ (0) +{ + ACE_NEW (this->aiocb_write_, + struct aiocb); + ACE_NEW (this->aiocb_read_, + struct aiocb); +} + +Test_Aio::~Test_Aio (void) +{ + delete aiocb_write_; + delete aiocb_read_; + delete buffer_write_; + delete buffer_read_; +} + +// Init the output file and init the buffer. +int +Test_Aio::init (void) +{ + // Open the output file. + this->out_fd_ = ACE_OS::open ("test_aio.log", + O_RDWR | O_CREAT | O_TRUNC, + 0666); + if (this->out_fd_ == 0) + ACE_ERROR_RETURN ((LM_ERROR, + "Error: Opening file\n"), + -1); + + // Init the buffers. + this->buffer_write_ = ACE::strnew ("Welcome to the world of AIO... AIO Rules !!!"); + ACE_DEBUG ((LM_DEBUG, + "The buffer : %s\n", + this->buffer_write_)); + + // Allocate memory for the read buffer. + ACE_NEW_RETURN (this->buffer_read_, + char [ACE_OS::strlen (this->buffer_write_)], + -1); + + return 0; +} + +// Set the necessary things for the AIO stuff. +// Write the buffer asynchly.hmm Disable signals. +// Go on aio_suspend. Wait for completion. +// Print out the result. +int +Test_Aio::do_aio (void) +{ + // = Write to the file. + + // Setup AIOCB. + this->aiocb_write_->aio_fildes = this->out_fd_; + this->aiocb_write_->aio_offset = 0; + this->aiocb_write_->aio_buf = this->buffer_write_; + this->aiocb_write_->aio_nbytes = ACE_OS::strlen (this->buffer_write_); + this->aiocb_write_->aio_reqprio = 0; + this->aiocb_write_->aio_sigevent.sigev_notify = SIGEV_NONE; + //this->this->aiocb_.aio_sigevent.sigev_signo = SIGRTMAX; + this->aiocb_write_->aio_sigevent.sigev_value.sival_ptr = + (void *) this->aiocb_write_; + + // Fire off the aio write. + if (aio_write (this->aiocb_write_) != 0) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "aio_write"), + -1); + + // = Read from that file. + + // Setup AIOCB. + this->aiocb_read_->aio_fildes = this->out_fd_; + this->aiocb_read_->aio_offset = 0; + this->aiocb_read_->aio_buf = this->buffer_read_; + this->aiocb_read_->aio_nbytes = ACE_OS::strlen (this->buffer_write_); + this->aiocb_read_->aio_reqprio = 0; + this->aiocb_read_->aio_sigevent.sigev_notify = SIGEV_NONE; + //this->this->aiocb_.aio_sigevent.sigev_signo = SIGRTMAX; + this->aiocb_read_->aio_sigevent.sigev_value.sival_ptr = + (void *) this->aiocb_read_; + + // Fire off the aio write. If it doesnt get queued, carry on to get + // the completion for the first one. + if (aio_read (this->aiocb_read_) < 0) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "aio_read"), + -1); + + // Wait for the completion on aio_suspend. + struct aiocb *list_aiocb[2]; + list_aiocb [0] = this->aiocb_write_; + list_aiocb [1] = this->aiocb_read_; + + // Do suspend till all the aiocbs in the list are done. + int to_finish = 2; + int return_val = 0; + while (to_finish > 0) + { + return_val = aio_suspend (list_aiocb, + to_finish, + 0); + ACE_DEBUG ((LM_DEBUG, + "Result of <aio_suspend> : %d\n", + return_val)); + + // Analyze return and error values. + if (to_finish > 1) + { + if (aio_error (list_aiocb [1]) != EINPROGRESS) + { + if (aio_return (list_aiocb [1]) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "aio_return, item 1"), + -1); + else + { + // Successful. Remember we have one less thing to finish. + --to_finish; + list_aiocb [1] = 0; + } + } + else + ACE_DEBUG ((LM_DEBUG, + "aio_error says aio 1 is in progress\n")); + } + + if (aio_error (list_aiocb [0]) != EINPROGRESS) + { + if (aio_return (list_aiocb [0]) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "aio_return, item 0"), + -1); + else + { + // Successful. Store the pointer somewhere and bump the + // read entry up to the front, if it is still not done. + --to_finish; + list_aiocb [0] = this->aiocb_read_; + } + } + else + ACE_DEBUG ((LM_DEBUG, + "aio_error says aio 0 is in progress\n")); + } + + ACE_DEBUG ((LM_DEBUG, + "Both the AIO operations done.\n" + "The buffer is : %s\n", + this->buffer_read_)); + + return 0; +} + +int +main (int argc, char **argv) +{ + + ACE_UNUSED_ARG (argc); + ACE_UNUSED_ARG (argv); + + Test_Aio test_aio; + + if (test_aio.init () != 0) + ACE_ERROR_RETURN ((LM_ERROR, + "AIOCB test failed:\n" + "ACE_POSIX_AIOCB_PROACTOR may not work in this platform\n"), + -1); + + if (test_aio.do_aio () != 0) + ACE_ERROR_RETURN ((LM_ERROR, + "AIOCB test failed:\n" + "ACE_POSIX_AIOCB_PROACTOR may not work in this platform\n"), + -1); + + ACE_DEBUG ((LM_DEBUG, + "AIOCB test successful:\n" + "ACE_POSIX_AIOCB_PROACTOR should work in this platform\n")); + + return 0; +} diff --git a/ACE/examples/Reactor/Proactor/test_aiosig.cpp b/ACE/examples/Reactor/Proactor/test_aiosig.cpp new file mode 100644 index 00000000000..1746a10a49c --- /dev/null +++ b/ACE/examples/Reactor/Proactor/test_aiosig.cpp @@ -0,0 +1,294 @@ +// $Id$ +// ============================================================================ +// +// = FILENAME +// test_aiosig.cpp +// +// = DESCRITPTION +// Check out test_aiosig_ace.cpp, the ACE'ified version of this +// program. This program may not be uptodate. +// +// = COMPILATION +// CC -g -o test_aiosig -lrt test_aiosig.cpp +// +// = RUN +// ./test_aiosig +// +// = AUTHOR +// Programming for the Real World. Bill O. GallMeister. +// Modified by Alexander Babu Arulanthu <alex@cs.wustl.edu> +// +// ===================================================================== + + +#include <unistd.h> +#include <fcntl.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <signal.h> +#include <string.h> +#include <errno.h> +#include <stdio.h> + +#include <limits.h> + +#include <aio.h> + +int file_handle = -1; +char mb1 [BUFSIZ + 1]; +char mb2 [BUFSIZ + 1]; +aiocb aiocb1, aiocb2; +sigset_t completion_signal; + +// Function prototypes. +int setup_signal_delivery (void); +int issue_aio_calls (void); +int query_aio_completions (void); +int test_aio_calls (void); +int setup_signal_handler (void); +int setup_signal_handler (int signal_number); + +int +setup_signal_delivery (void) +{ + // Make the sigset_t consisting of the completion signal. + if (sigemptyset (&completion_signal) == -1) + { + perror ("Error:Couldnt init the RT completion signal set\n"); + return -1; + } + + if (sigaddset (&completion_signal, SIGRTMIN) == -1) + { + perror ("Error:Couldnt init the RT completion signal set\n"); + return -1; + } + + // Mask them. + if (pthread_sigmask (SIG_BLOCK, &completion_signal, 0) == -1) + { + perror ("Error:Couldnt maks the RT completion signals\n"); + return -1; + } + + return setup_signal_handler (SIGRTMIN); +} + +int +issue_aio_calls (void) +{ + // Setup AIOCB. + aiocb1.aio_fildes = file_handle; + aiocb1.aio_offset = 0; + aiocb1.aio_buf = mb1; + aiocb1.aio_nbytes = BUFSIZ; + aiocb1.aio_reqprio = 0; + aiocb1.aio_sigevent.sigev_notify = SIGEV_SIGNAL; + aiocb1.aio_sigevent.sigev_signo = SIGRTMIN; + aiocb1.aio_sigevent.sigev_value.sival_ptr = (void *) &aiocb1; + + // Fire off the aio write. + if (aio_read (&aiocb1) == -1) + { + // Queueing failed. + perror ("Error:Asynch_Read_Stream: aio_read queueing failed\n"); + return -1; + } + + // Setup AIOCB. + aiocb2.aio_fildes = file_handle; + aiocb2.aio_offset = BUFSIZ + 1; + aiocb2.aio_buf = mb2; + aiocb2.aio_nbytes = BUFSIZ; + aiocb2.aio_reqprio = 0; + aiocb2.aio_sigevent.sigev_notify = SIGEV_SIGNAL; + aiocb2.aio_sigevent.sigev_signo = SIGRTMIN; + aiocb2.aio_sigevent.sigev_value.sival_ptr = (void *) &aiocb2; + + // Fire off the aio write. + if (aio_read (&aiocb2) == -1) + { + // Queueing failed. + perror ("Error:Asynch_Read_Stream: aio_read queueing failed\n"); + return -1; + } + return 0; +} + +int +query_aio_completions (void) +{ + int result = 0; + size_t number_of_compleions = 0; + for (number_of_compleions = 0; + number_of_compleions < 2; + number_of_compleions ++) + { + // Wait for <milli_seconds> amount of time. + // @@ Assigning <milli_seconds> to tv_sec. + timespec timeout; + timeout.tv_sec = INT_MAX; + timeout.tv_nsec = 0; + + // To get back the signal info. + siginfo_t sig_info; + + // Await the RT completion signal. + int sig_return = sigtimedwait (&completion_signal, + &sig_info, + &timeout); + + // Error case. + // If failure is coz of timeout, then return *0* but set + // errno appropriately. This is what the WinNT proactor + // does. + if (sig_return == -1) + { + perror ("Error:Error waiting for RT completion signals\n"); + return -1; + } + + // RT completion signals returned. + if (sig_return != SIGRTMIN) + { + printf ("Unexpected signal (%d) has been received while waiting for RT Completion Signals\n", + sig_return); + return -1; + } + + // @@ Debugging. + printf ("Sig number found in the sig_info block : %d\n", + sig_info.si_signo); + + // Is the signo returned consistent? + if (sig_info.si_signo != sig_return) + { + printf ("Inconsistent signal number (%d) in the signal info block\n", + sig_info.si_signo); + return -1; + } + + // @@ Debugging. + printf ("Signal code for this signal delivery : %d\n", + sig_info.si_code); + + // Is the signal code an aio completion one? + if ((sig_info.si_code != SI_ASYNCIO) && + (sig_info.si_code != SI_QUEUE)) + { + printf ("Unexpected signal code (%d) returned on completion querying\n", + sig_info.si_code); + return -1; + } + + // Retrive the aiocb. + aiocb* aiocb_ptr = (aiocb *) sig_info.si_value.sival_ptr; + + // Analyze error and return values. Return values are + // actually <errno>'s associated with the <aio_> call + // corresponding to aiocb_ptr. + int error_code = aio_error (aiocb_ptr); + if (error_code == -1) + { + perror ("Error:Invalid control block was sent to <aio_error> for compleion querying\n"); + return -1; + } + + if (error_code != 0) + { + // Error occurred in the <aio_>call. Return the errno + // corresponding to that <aio_> call. + printf ("Error:An AIO call has failed:Error code = %d\n", + error_code); + return -1; + } + + // No error occured in the AIO operation. + int nbytes = aio_return (aiocb_ptr); + if (nbytes == -1) + { + perror ("Error:Invalid control block was send to <aio_return>\n"); + return -1; + } + + if (number_of_compleions == 0) + // Print the buffer. + printf ("Number of bytes transferred : %d\n The buffer : %s \n", + nbytes, + mb1); + else + // Print the buffer. + printf ("Number of bytes transferred : %d\n The buffer : %s \n", + nbytes, + mb2); + } + return 0; +} + +int +test_aio_calls (void) +{ + // Set up the input file. + // Open file (in SEQUENTIAL_SCAN mode) + file_handle = open ("test_aiosig.cpp", O_RDONLY); + + if (file_handle == -1) + { + perror ("Error:Opening the inputfile"); + return -1; + } + + if (setup_signal_delivery () < 0) + return -1; + + if (issue_aio_calls () < 0) + return -1; + + if (query_aio_completions () < 0) + return -1; + + return 0; +} + +int +setup_signal_handler (int signal_number) +{ + // Setting up the handler(!) for these signals. + struct sigaction reaction; + sigemptyset (&reaction.sa_mask); // Nothing else to mask. + reaction.sa_flags = SA_SIGINFO; // Realtime flag. +#if defined (SA_SIGACTION) + // Lynx says, it is better to set this bit to be portable. + reaction.sa_flags &= SA_SIGACTION; +#endif /* SA_SIGACTION */ + reaction.sa_sigaction = null_handler; // Null handler. + int sigaction_return = sigaction (SIGRTMIN, + &reaction, + 0); + if (sigaction_return == -1) + { + perror ("Error:Proactor couldnt do sigaction for the RT SIGNAL"); + return -1; + } + + return 0; +} + +void +null_handler (int /* signal_number */, + siginfo_t * /* info */, + void * /* context */) +{ +} + +int +main (int, char *[]) +{ + if (test_aio_calls () == 0) + printf ("RT SIG test successful:\n" + "ACE_POSIX_SIG_PROACTOR should work in this platform\n"); + else + printf ("RT SIG test failed:\n" + "ACE_POSIX_SIG_PROACTOR may not work in this platform\n"); + return 0; +} diff --git a/ACE/examples/Reactor/Proactor/test_aiosig_ace.cpp b/ACE/examples/Reactor/Proactor/test_aiosig_ace.cpp new file mode 100644 index 00000000000..34c1b9b5ab2 --- /dev/null +++ b/ACE/examples/Reactor/Proactor/test_aiosig_ace.cpp @@ -0,0 +1,358 @@ +// $Id$ + +// ============================================================================ +// +// = FILENAME +// test_aiosig_sig.cpp +// +// = DESCRITPTION +// This program helps you to test the <aio_*> calls on a +// platform. +// Before running this test, make sure the platform can +// support POSIX <aio_> calls, using ACE_ROOT/tests/Aio_Plaform_Test.cpp +// +// This program tests the Signal based completion approach which +// uses <sigtimedwait> for completion querying. +// If this test is successful, ACE_POSIX_SIG_PROACTOR +// can be used on this platform. +// +// This program is a ACE version of the +// $ACE_ROOT/examples/Reactor/Proactor/test_aiosig.cpp, with +// ACE_DEBUGs and Message_Blocks. +// +// This test does the following: +// Issue two <aio_read>s. +// Assign SIGRTMIN as the notification signal. +// Mask these signals from delivery. +// Receive this signal by doing <sigtimedwait>. +// Wait for two completions (two signals) +// +// = COMPILATION +// make +// +// = RUN +// ./test_aiosig_ace +// +// = AUTHOR +// Programming for the Real World. Bill O. GallMeister. +// Modified by Alexander Babu Arulanthu <alex@cs.wustl.edu> +// +// ===================================================================== + +#include "ace/Message_Block.h" +#include "ace/Log_Msg.h" +#include "ace/os_include/os_aio.h" +#include "ace/OS_NS_signal.h" +#include "ace/OS_NS_unistd.h" +#include "ace/OS_NS_fcntl.h" +#include "ace/Asynch_IO.h" // for ACE_INFINITE + +static ACE_HANDLE file_handle = ACE_INVALID_HANDLE; +static ACE_Message_Block mb1 (BUFSIZ + 1); +static ACE_Message_Block mb2 (BUFSIZ + 1); +static aiocb aiocb1; +static aiocb aiocb2; +static aiocb aiocb3; +static sigset_t completion_signal; + +// Function prototypes. +static int setup_signal_delivery (void); +static int issue_aio_calls (void); +static int query_aio_completions (void); +static int test_aio_calls (void); +static void null_handler (int signal_number, siginfo_t *info, void *context); +static int setup_signal_handler (int signal_number); + +static int +setup_signal_delivery (void) +{ + // = Mask all the signals. + + sigset_t full_set; + + // Get full set. + if (sigfillset (&full_set) != 0) + ACE_ERROR_RETURN ((LM_ERROR, + "Error:(%P | %t):%p\n", + "sigfillset failed"), + -1); + + // Mask them. + if (ACE_OS::pthread_sigmask (SIG_SETMASK, &full_set, 0) != 0) + ACE_ERROR_RETURN ((LM_ERROR, + "Error:(%P | %t):%p\n", + "pthread_sigmask failed"), + -1); + + // = Make a mask with SIGRTMIN only. We use only that signal to + // issue <aio_>'s. + + if (sigemptyset (&completion_signal) == -1) + ACE_ERROR_RETURN ((LM_ERROR, "Error: %p\n", + "Couldnt init the RT completion signal set"), + -1); + + if (sigaddset (&completion_signal, + SIGRTMIN) == -1) + ACE_ERROR_RETURN ((LM_ERROR, "Error: %p\n", + "Couldnt init the RT completion signal set"), + -1); + + // Set up signal handler for this signal. + return setup_signal_handler (SIGRTMIN); +} + +static int +setup_signal_handler (int signal_number) +{ + ACE_UNUSED_ARG (signal_number); + + // Setting up the handler(!) for these signals. + struct sigaction reaction; + sigemptyset (&reaction.sa_mask); // Nothing else to mask. + reaction.sa_flags = SA_SIGINFO; // Realtime flag. +#if defined (SA_SIGACTION) + // Lynx says, it is better to set this bit to be portable. + reaction.sa_flags &= SA_SIGACTION; +#endif /* SA_SIGACTION */ + reaction.sa_sigaction = null_handler; // Null handler. + int sigaction_return = sigaction (SIGRTMIN, + &reaction, + 0); + if (sigaction_return == -1) + ACE_ERROR_RETURN ((LM_ERROR, "Error: %p\n", + "Proactor couldnt do sigaction for the RT SIGNAL"), + -1); + return 0; +} + + +static int +issue_aio_calls (void) +{ + // Setup AIOCB. + aiocb1.aio_fildes = file_handle; + aiocb1.aio_offset = 0; + aiocb1.aio_buf = mb1.wr_ptr (); + aiocb1.aio_nbytes = BUFSIZ; + aiocb1.aio_reqprio = 0; + aiocb1.aio_sigevent.sigev_notify = SIGEV_SIGNAL; + aiocb1.aio_sigevent.sigev_signo = SIGRTMIN; + aiocb1.aio_sigevent.sigev_value.sival_ptr = (void *) &aiocb1; + + // Fire off the aio read. + if (aio_read (&aiocb1) == -1) + // Queueing failed. + ACE_ERROR_RETURN ((LM_ERROR, "Error: %p\n", + "Asynch_Read_Stream: aio_read queueing failed"), + -1); + + // Setup AIOCB. + aiocb2.aio_fildes = file_handle; + aiocb2.aio_offset = BUFSIZ + 1; + aiocb2.aio_buf = mb2.wr_ptr (); + aiocb2.aio_nbytes = BUFSIZ; + aiocb2.aio_reqprio = 0; + aiocb2.aio_sigevent.sigev_notify = SIGEV_SIGNAL; + aiocb2.aio_sigevent.sigev_signo = SIGRTMIN; + aiocb2.aio_sigevent.sigev_value.sival_ptr = (void *) &aiocb2; + + // Fire off the aio read. + if (aio_read (&aiocb2) == -1) + // Queueing failed. + ACE_ERROR_RETURN ((LM_ERROR, "Error: %p\n", + "Asynch_Read_Stream: aio_read queueing failed"), + -1); + + // Setup sigval. + aiocb3.aio_fildes = ACE_INVALID_HANDLE; + aiocb3.aio_offset = 0; + aiocb3.aio_buf = 0; + aiocb3.aio_nbytes = 0; + aiocb3.aio_reqprio = 0; + aiocb3.aio_sigevent.sigev_notify = SIGEV_SIGNAL; + aiocb3.aio_sigevent.sigev_signo = SIGRTMIN; + aiocb3.aio_sigevent.sigev_value.sival_ptr = (void *) &aiocb3; + sigval value; + value.sival_ptr = reinterpret_cast<void *> (&aiocb3); + // Queue this one for completion right now. + if (sigqueue (ACE_OS::getpid (), SIGRTMIN, value) == -1) + // Queueing failed. + ACE_ERROR_RETURN ((LM_ERROR, + "Error: %p\n", "sigqueue"), + -1); + + return 0; +} + +static int +query_aio_completions (void) +{ + for (size_t number_of_compleions = 0; + number_of_compleions < 3; + number_of_compleions ++) + { + // Wait for <milli_seconds> amount of time. @@ Assigning + // <milli_seconds> to tv_sec. + timespec timeout; + timeout.tv_sec = ACE_INFINITE; + timeout.tv_nsec = 0; + + // To get back the signal info. + siginfo_t sig_info; + + // Await the RT completion signal. + int sig_return = sigtimedwait (&completion_signal, + &sig_info, + &timeout); + + // Error case. + // If failure is coz of timeout, then return *0* but set + // errno appropriately. This is what the WinNT proactor + // does. + if (sig_return == -1) + ACE_ERROR_RETURN ((LM_ERROR, "Error: %p\n", + "Error waiting for RT completion signals"), + -1); + + // RT completion signals returned. + if (sig_return != SIGRTMIN) + ACE_ERROR_RETURN ((LM_ERROR, + "Unexpected signal (%d) has been received while waiting for RT Completion Signals\n", + sig_return), + -1); + + // @@ Debugging. + ACE_DEBUG ((LM_DEBUG, + "Sig number found in the sig_info block : %d\n", + sig_info.si_signo)); + + // Is the signo returned consistent? + if (sig_info.si_signo != sig_return) + ACE_ERROR_RETURN ((LM_ERROR, + "Inconsistent signal number (%d) in the signal info block\n", + sig_info.si_signo), + -1); + + // @@ Debugging. + ACE_DEBUG ((LM_DEBUG, + "Signal code for this signal delivery : %d\n", + sig_info.si_code)); + + // Is the signal code an aio completion one? + if ((sig_info.si_code != SI_ASYNCIO) && + (sig_info.si_code != SI_QUEUE)) + ACE_ERROR_RETURN ((LM_DEBUG, + "Unexpected signal code (%d) returned on completion querying\n", + sig_info.si_code), + -1); + + // Retrive the aiocb. + aiocb* aiocb_ptr = (aiocb *) sig_info.si_value.sival_ptr; + if (aiocb_ptr == &aiocb3) + { + ACE_ASSERT (sig_info.si_code == SI_QUEUE); + ACE_DEBUG ((LM_DEBUG, "sigqueue caught... good\n")); + } + else + { + // Analyze error and return values. Return values are + // actually <errno>'s associated with the <aio_> call + // corresponding to aiocb_ptr. + int error_code = aio_error (aiocb_ptr); + if (error_code == -1) + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", + "Invalid control block was sent to <aio_error> for completion querying"), + -1); + + if (error_code != 0) + // Error occurred in the <aio_>call. Return the errno + // corresponding to that <aio_> call. + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", + "An AIO call has failed"), + error_code); + + // No error occured in the AIO operation. + int nbytes = aio_return (aiocb_ptr); + if (nbytes == -1) + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", + "Invalid control block was send to <aio_return>"), + -1); + if (number_of_compleions == 0) + { + // Print the buffer. + ACE_DEBUG ((LM_DEBUG, + "\n Number of bytes transferred : %d\n", + nbytes)); + // Note... the dumps of the buffers are disabled because they + // may easily overrun the ACE_Log_Msg output buffer. If you need + // to turn the on for some reason, be careful of this. +#if 0 + ACE_DEBUG ((LM_DEBUG, "The buffer : %s \n", mb1.rd_ptr ())); +#endif /* 0 */ + } + else + { + // Print the buffer. + ACE_DEBUG ((LM_DEBUG, + "\n Number of bytes transferred : %d\n", + nbytes)); +#if 0 + ACE_DEBUG ((LM_DEBUG, "The buffer : %s \n", mb2.rd_ptr ())); +#endif /* 0 */ + } + } + } + + return 0; +} + +static int +test_aio_calls (void) +{ + // Set up the input file. + // Open file (in SEQUENTIAL_SCAN mode) + file_handle = ACE_OS::open ("test_aiosig_ace.cpp", + O_RDONLY); + + if (file_handle == ACE_INVALID_HANDLE) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "ACE_OS::open"), + -1); + + if (setup_signal_delivery () == -1) + return -1; + + if (issue_aio_calls () == -1) + return -1; + + if (query_aio_completions () == -1) + return -1; + + return 0; +} + +static void +null_handler (int signal_number, + siginfo_t */* info */, + void * /* context */) +{ + ACE_ERROR ((LM_ERROR, + "Error:%s:Signal number %d\n" + "Mask all the RT signals for this thread", + "ACE_POSIX_SIG_Proactor::null_handler called", + signal_number)); +} + +int +main (int, char *[]) +{ + if (test_aio_calls () == 0) + printf ("RT SIG test successful:\n" + "ACE_POSIX_SIG_PROACTOR should work in this platform\n"); + else + printf ("RT SIG test failed:\n" + "ACE_POSIX_SIG_PROACTOR may not work in this platform\n"); + return 0; +} diff --git a/ACE/examples/Reactor/Proactor/test_cancel.cpp b/ACE/examples/Reactor/Proactor/test_cancel.cpp new file mode 100644 index 00000000000..c10f8e9be2c --- /dev/null +++ b/ACE/examples/Reactor/Proactor/test_cancel.cpp @@ -0,0 +1,246 @@ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// examples +// +// = FILENAME +// test_cancel.cpp +// +// = DESCRIPTION +// This program tests cancelling an Asynchronous Operation in the +// Proactor framework. +// +// This tests accepts a connection and issues an Asynchronous Read +// Stream. It reads <read_size> (option -s) number of bytes and +// when this operation completes, it issues another Asynchronous +// Read Stream to <read_size> and immediately calls <cancel> to +// cancel the operation and so the program exits closing the +// connection. +// +// Works fine on NT. On Solaris platforms, the asynch read is +// pending, but the cancel returns with the value <AIO_ALLDONE> +// indicating all the operations in that handle are done. +// But, LynxOS has a good <aio_cancel> implementation. It works +// fine. +// +// = RUN +// ./test_cancel -p <port_number> +// Then telnet to this port and send <read_size> bytes and your +// connection should get closed down. +// +// = AUTHOR +// Irfan Pyarali (irfan@cs.wustl.edu) +// +// ============================================================================ + +#include "ace/OS_main.h" +#include "ace/Service_Config.h" +#include "ace/Proactor.h" +#include "ace/Asynch_IO.h" +#include "ace/Asynch_IO_Impl.h" +#include "ace/Asynch_Acceptor.h" +#include "ace/INET_Addr.h" +#include "ace/SOCK_Connector.h" +#include "ace/SOCK_Acceptor.h" +#include "ace/SOCK_Stream.h" +#include "ace/Message_Block.h" +#include "ace/Get_Opt.h" +#include "ace/Log_Msg.h" +#include "ace/OS_NS_sys_socket.h" + +ACE_RCSID (Proactor, test_proactor, "$Id$") + +#if ((defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)) || (defined (ACE_HAS_AIO_CALLS))) + // This only works on Win32 platforms and on Unix platforms supporting + // POSIX aio calls. + +#include "test_cancel.h" + +static u_short port = ACE_DEFAULT_SERVER_PORT; +static int done = 0; +static int read_size = 2; + + +Receiver::Receiver (void) + : mb_ (read_size + 1), + handle_ (ACE_INVALID_HANDLE) +{ +} + +Receiver::~Receiver (void) +{ + ACE_DEBUG ((LM_DEBUG, + "Receiver: Closing down Remote connection:%d\n", + this->handle_)); + + ACE_OS::closesocket (this->handle_); +} + +void +Receiver::open (ACE_HANDLE handle, + ACE_Message_Block &) +{ + // New connection, initiate stuff + + ACE_DEBUG ((LM_DEBUG, "%N:%l:Receiver::open called\n")); + + // Cache the new connection + this->handle_ = handle; + + // Initiate ACE_Asynch_Read_Stream + if (this->rs_.open (*this, this->handle_) == -1) + { + ACE_ERROR ((LM_ERROR, "%p\n", "ACE_Asynch_Read_Stream::open")); + return; + } + + // Try to read <n> bytes from the stream. + + ACE_DEBUG ((LM_DEBUG, + "Receiver::open: Issuing Asynch Read of (%d) bytes from the stream\n", + read_size)); + + if (this->rs_.read (this->mb_, + read_size) == -1) + ACE_ERROR ((LM_ERROR, + "%p\n", + "Receiver::open: Failed to issue the read")); +} + +void +Receiver::handle_read_stream (const ACE_Asynch_Read_Stream::Result &result) +{ + ACE_DEBUG ((LM_DEBUG, "handle_read_stream called\n")); + + // Reset pointers + result.message_block ().rd_ptr ()[result.bytes_transferred ()] = '\0'; + + ACE_DEBUG ((LM_DEBUG, "********************\n")); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "bytes_to_read", result.bytes_to_read ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "handle", result.handle ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "bytes_transfered", result.bytes_transferred ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "act", (u_long) result.act ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "success", result.success ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "completion_key", (u_long) result.completion_key ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "error", result.error ())); + ACE_DEBUG ((LM_DEBUG, "********************\n")); + ACE_DEBUG ((LM_DEBUG, "%s = %s\n", "message_block", result.message_block ().rd_ptr ())); + + if (result.success () && !result.error ()) + { + // Successful read: No error. + + // Set the pointers back in the message block. + result.message_block ().wr_ptr (result.message_block ().rd_ptr ()); + + // Issue another read, but immediately cancel it. + + // Issue the read. + + ACE_DEBUG ((LM_DEBUG, + "Issuing Asynch Read of (%d) bytes from the stream\n", + read_size)); + + if (this->rs_.read (this->mb_, + read_size) == -1) + ACE_ERROR ((LM_ERROR, + "%p\n", + "Receiver::handle_read_stream: Failed to issue the read")); + + // Cancel the read. + + ACE_DEBUG ((LM_DEBUG, + "Cacelling Asynch Read ")); + + int ret_val = this->rs_.cancel (); + if (ret_val == -1) + ACE_ERROR ((LM_ERROR, + "%p\n", + "Receiver::handle_read_stream: Failed to cancel the read")); + + ACE_DEBUG ((LM_DEBUG, "Asynch IO : Cancel : Result = %d\n", + ret_val)); + } + else + { + done = 1; + + ACE_DEBUG ((LM_DEBUG, "Receiver completed\n")); + + // Print the error message if any. + if (result.error () != 0) + { + errno = result.error (); + + ACE_ERROR ((LM_ERROR, + "%p\n", + "Asynch Read Stream Error: ")); + } + } +} + +static int +parse_args (int argc, ACE_TCHAR *argv[]) +{ + ACE_Get_Opt get_opt (argc, argv, ACE_TEXT("p:s:")); + int c; + + while ((c = get_opt ()) != EOF) + switch (c) + { + case 'p': + port = ACE_OS::atoi (get_opt.opt_arg ()); + break; + case 's': + read_size = ACE_OS::atoi (get_opt.opt_arg ()); + break; + default: + ACE_ERROR ((LM_ERROR, "%p.\n", + "usage :\n" + "-p <port>\n" + "-s <read_size>\n")); + return -1; + } + + return 0; +} + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + if (parse_args (argc, argv) == -1) + return -1; + + // Note: acceptor parameterized by the Receiver + ACE_Asynch_Acceptor<Receiver> acceptor; + + // Listening passively. + if (acceptor.open (ACE_INET_Addr (port), + read_size, + 1) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "ACE:acceptor::open failed\n"), + 1); + + int success = 1; + + while (success > 0 && !done) + // dispatch events + success = ACE_Proactor::instance ()->handle_events (); + + return 0; +} + +#else /* ACE_WIN32 && !ACE_HAS_WINCE || ACE_HAS_AIO_CALLS*/ + +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_DEBUG ((LM_DEBUG, + "This example does not work on this platform.\n")); + return 1; +} + +#endif /* ACE_WIN32 && !ACE_HAS_WINCE || ACE_HAS_AIO_CALLS*/ diff --git a/ACE/examples/Reactor/Proactor/test_cancel.h b/ACE/examples/Reactor/Proactor/test_cancel.h new file mode 100644 index 00000000000..45c4bfbc85b --- /dev/null +++ b/ACE/examples/Reactor/Proactor/test_cancel.h @@ -0,0 +1,47 @@ +/* +** $Id$ +*/ + +#ifndef _TEST_CANCEL_H +#define _TEST_CANCEL_H + +#include "ace/Asynch_IO.h" + +class Receiver : public ACE_Service_Handler +{ + // = TITLE + // + // Receiver + // + // = DESCRIPTION + // + // The class will be created by ACE_Asynch_Acceptor when new + // connections arrive. This class will then receive data from + // the network connection and dump it to a file. + +public: + Receiver (void); + ~Receiver (void); + + virtual void open (ACE_HANDLE handle, + ACE_Message_Block &message_block); + // This is called after the new connection has been accepted. + +protected: + // These methods are called by the framework + + virtual void handle_read_stream (const ACE_Asynch_Read_Stream::Result &result); + // This is called when asynchronous read from the socket complete + +private: + ACE_Asynch_Read_Stream rs_; + // rs (read stream): for reading from a socket + + ACE_Message_Block mb_; + // Message block to read from the stream. + + ACE_HANDLE handle_; + // Handle for IO to remote peer +}; + +#endif /* _TEST_CANCEL_H */ diff --git a/ACE/examples/Reactor/Proactor/test_end_event_loop.cpp b/ACE/examples/Reactor/Proactor/test_end_event_loop.cpp new file mode 100644 index 00000000000..096f77b089d --- /dev/null +++ b/ACE/examples/Reactor/Proactor/test_end_event_loop.cpp @@ -0,0 +1,168 @@ +// $Id$ +// ============================================================================ +// +// = FILENAME +// test_end_event_loop.cpp +// +// = DESCRITPTION +// This program tests the event loop mechanism of the +// Proactor. To end the event loop, threads that are blocked in +// waiting for completions are woken up and the event loop comes +// to the end. This is tested in this program. +// +// Threads are doing <run_event_loop> with/without time_out +// values and the main thread calls <end_event_loop>. +// +// = COMPILATION +// make +// +// = RUN +// ./test_end_event_loop +// +// = AUTHOR +// Alexander Babu Arulanthu <alex@cs.wustl.edu> +// +// ===================================================================== + +#include "ace/OS_NS_unistd.h" +#include "ace/Proactor.h" +#include "ace/Task.h" +#include "ace/WIN32_Proactor.h" +#include "ace/POSIX_Proactor.h" +#include "ace/OS_main.h" + +#if ((defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)) || \ + (defined (ACE_HAS_AIO_CALLS)) && !defined (ACE_POSIX_AIOCB_PROACTOR)) +// This only works on Win32 platforms and on Unix platforms supporting +// POSIX aio calls. + +class My_Task: public ACE_Task <ACE_NULL_SYNCH> +{ + // = TITLE + // + // Contains thread functions which execute event loops. Each + // thread waits for a different signal. + // +public: + // Constructor. + My_Task (void) + : time_flag_ (0) + {} + + + virtual ~My_Task (void) {} + // Destructor. + + // If time_flag is zero do the eventloop indefinitely, otherwise do + // it for finite amount of time (13secs!!!). + int open (void *timed_event_loop) + { + // Set the local variable. + if (timed_event_loop == 0) + this->time_flag_ = 0; + else + this->time_flag_ = 1; + + // Spawn the threads. + if (this->activate (THR_NEW_LWP, 5) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%N:%l:%p\n", + "My_Task:open: <activate> failed"), + -1); + + return 0; + } + + // Thread function. + int svc (void) + { + ACE_DEBUG ((LM_DEBUG, + "(%P|%t):Starting svc routine\n")); + + if (this->time_flag_) + { + ACE_DEBUG ((LM_DEBUG, + "(%P|%t):Going to do *timed* <run_event_loop> \n")); + + ACE_Time_Value run_time (13); + + if (ACE_Proactor::instance ()->run_event_loop (run_time) == -1) + ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t):%p.\n", + "<Proactor::run_event_loop> failed"), + -1); + } + else + { + ACE_DEBUG ((LM_DEBUG, + "(%P|%t):Going to do *indefinite* <run_event_loop> \n")); + + if (ACE_Proactor::instance ()->run_event_loop () == -1) + ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t):%p.\n", + "<Proactor::run_event_loop> failed"), + -1); + } + return 0; + }; + +private: + int time_flag_; + // If zero, indefinite event loop, otherwise timed event loop. +}; + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv []) +{ + ACE_UNUSED_ARG (argc); + ACE_UNUSED_ARG (argv); + + ACE_DEBUG ((LM_DEBUG, + "(%P | %t):Test starts \n")); + + // Let us get the singleton proactor created here. This is very + // important. This will mask the signal used in the Proactor masked + // for the main thread (and all the threads). + ACE_Proactor *proactor = ACE_Proactor::instance (); + ACE_UNUSED_ARG (proactor); + + My_Task task1, task2; + + // Test the indefinite run event loop. + if (task1.open (0) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%N:%l:(%P | %t):Failed to <open> the task\n"), + 1); + + // Test the indefinite run event loop. Just pass a non-zero. + if (task2.open ((void *)&task2) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%N:%l:(%P | %t):Failed to <open> the task\n"), + 1); + + // Give a gap. + ACE_OS::sleep (3); + + // End the event loop. + if (ACE_Proactor::instance ()->end_event_loop () == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%N:%l:(%P | %t):Failed to <end_event_loop>\n"), + 1); + + ACE_Thread_Manager::instance ()->wait (); + + ACE_DEBUG ((LM_DEBUG, + "(%P | %t):Test ends\n")); + return 0; +} + +#else /* ACE_WIN32 && !ACE_HAS_WINCE || ACE_HAS_AIO_CALLS && !ACE_POSIX_AIOCB_PROACTOR*/ + +int +main (int, char *[]) +{ + ACE_DEBUG ((LM_DEBUG, + "This example cannot work with AIOCB_Proactor.\n")); + return 1; +} + +#endif /* ACE_WIN32 && !ACE_HAS_WINCE || ACE_HAS_AIO_CALLS && !ACE_POSIX_AIOCB_PROACTOR*/ + diff --git a/ACE/examples/Reactor/Proactor/test_multiple_loops.cpp b/ACE/examples/Reactor/Proactor/test_multiple_loops.cpp new file mode 100644 index 00000000000..ac4228ab641 --- /dev/null +++ b/ACE/examples/Reactor/Proactor/test_multiple_loops.cpp @@ -0,0 +1,140 @@ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// examples +// +// = FILENAME +// test_multiple_loops.cpp +// +// = DESCRIPTION +// +// This example application shows how to write programs that +// combine the Proactor and Reactor event loops. This is possible +// only on WIN32 platform. +// +// = AUTHOR +// Irfan Pyarali +// +// ============================================================================ + +#include "ace/Task.h" +#include "ace/Proactor.h" +#include "ace/WIN32_Proactor.h" +#include "ace/Atomic_Op.h" +#include "ace/OS_NS_unistd.h" + +ACE_RCSID(Proactor, test_multiple_loops, "$Id$") + +#if (defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)) + +class Timeout_Handler : public ACE_Handler, public ACE_Event_Handler +{ + // = TITLE + // Generic timeout handler. + +public: + Timeout_Handler (void) + { + } + + // This is called by the Proactor. This is declared in ACE_Handler. + virtual void handle_time_out (const ACE_Time_Value &tv, + const void *arg) + { + // Print out when timeouts occur. + ACE_DEBUG ((LM_DEBUG, "(%t) %d timeout occurred for %s @ %d.\n", + ++count_, + (char *) arg, + tv.sec ())); + + // Since there is only one thread that can do the timeouts in + // Reactor, lets keep the handle_timeout short for that + // thread. + if (ACE_OS::strcmp ((char *) arg, "Proactor") == 0) + // Sleep for a while + ACE_OS::sleep (1); + } + + // This method is declared in ACE_Event_Handler. + virtual int handle_timeout (const ACE_Time_Value &tv, + const void *arg) + { + this->handle_time_out (tv, arg); + return 0; + } + +private: + ACE_Atomic_Op <ACE_Thread_Mutex, int> count_; +}; + +class Worker : public ACE_Task <ACE_NULL_SYNCH> +{ +public: + + // Thread fuction. + int svc (void) + { + ACE_DEBUG ((LM_DEBUG, "(%t) Worker started\n")); + + // Handle events for 13 seconds. + ACE_Time_Value run_time (13); + + // Try to become the owner + ACE_Reactor::instance ()->owner (ACE_Thread::self ()); + + if (ACE_Reactor::run_event_loop (run_time) == -1) + ACE_ERROR_RETURN ((LM_ERROR, "%p.\n", "Worker::svc"), -1); + else + ACE_DEBUG ((LM_DEBUG, "(%t) work complete\n")); + + return 0; + } +}; + +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + Timeout_Handler handler; + ACE_WIN32_Proactor win32_proactor (0, 1); + ACE_Proactor proactor (&win32_proactor, 0, 0); + + ACE_Reactor::instance ()->register_handler (proactor.implementation ()); + + // Register a 2 second timer. + ACE_Time_Value foo_tv (2); + if (proactor.schedule_timer (handler, + (void *) "Proactor", + ACE_Time_Value::zero, + foo_tv) == -1) + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "schedule_timer"), -1); + + // Register a 3 second timer. + ACE_Time_Value bar_tv (3); + if (ACE_Reactor::instance ()->schedule_timer (&handler, + (void *) "Reactor", + ACE_Time_Value::zero, + bar_tv) == -1) + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "schedule_timer"), -1); + + Worker worker; + + if (worker.activate (THR_NEW_LWP, 10) == -1) + ACE_ERROR_RETURN ((LM_ERROR, "%p.\n", "main"), -1); + + ACE_Thread_Manager::instance ()->wait (); + + // Remove from reactor + ACE_Reactor::instance ()->remove_handler (&proactor, + ACE_Event_Handler::DONT_CALL); + + return 0; +} +#else +int +main (int, char *[]) +{ + return 0; +} +#endif /* ACE_WIN32 && !ACE_HAS_WINCE */ diff --git a/ACE/examples/Reactor/Proactor/test_proactor.cpp b/ACE/examples/Reactor/Proactor/test_proactor.cpp new file mode 100644 index 00000000000..035a2facf6a --- /dev/null +++ b/ACE/examples/Reactor/Proactor/test_proactor.cpp @@ -0,0 +1,679 @@ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// examples +// +// = FILENAME +// test_proactor.cpp +// +// = DESCRIPTION +// This program illustrates how the <ACE_Proactor> can be used to +// implement an application that does various asynchronous +// operations. +// +// = AUTHOR +// Irfan Pyarali <irfan@cs.wustl.edu> +// +// ============================================================================ + +#include "ace/OS_NS_string.h" +#include "ace/OS_main.h" +#include "ace/Service_Config.h" +#include "ace/Proactor.h" +#include "ace/Asynch_IO.h" +#include "ace/Asynch_IO_Impl.h" +#include "ace/Asynch_Acceptor.h" +#include "ace/INET_Addr.h" +#include "ace/SOCK_Connector.h" +#include "ace/SOCK_Acceptor.h" +#include "ace/SOCK_Stream.h" +#include "ace/Message_Block.h" +#include "ace/Get_Opt.h" +#include "ace/Log_Msg.h" +#include "ace/OS_NS_sys_stat.h" +#include "ace/OS_NS_sys_socket.h" +#include "ace/OS_NS_unistd.h" +#include "ace/OS_NS_fcntl.h" + +ACE_RCSID(Proactor, test_proactor, "$Id$") + +#if ((defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)) || (defined (ACE_HAS_AIO_CALLS))) + // This only works on Win32 platforms and on Unix platforms supporting + // POSIX aio calls. + +#include "test_proactor.h" + + +// Host that we're connecting to. +static ACE_TCHAR *host = 0; + +// Port that we're receiving connections on. +static u_short port = ACE_DEFAULT_SERVER_PORT; + +// File that we're sending. +static const ACE_TCHAR *file = ACE_TEXT("test_proactor.cpp"); + +// Name of the output file. +static const ACE_TCHAR *dump_file = ACE_TEXT("output"); + +// Keep track of when we're done. +static int done = 0; + +// Size of each initial asynchronous <read> operation. +static int initial_read_size = BUFSIZ; + + +Receiver::Receiver (void) + : dump_file_ (ACE_INVALID_HANDLE), + handle_ (ACE_INVALID_HANDLE) +{ +} + +Receiver::~Receiver (void) +{ + ACE_OS::close (this->dump_file_); + ACE_OS::closesocket (this->handle_); +} + +void +Receiver::open (ACE_HANDLE handle, + ACE_Message_Block &message_block) +{ + ACE_DEBUG ((LM_DEBUG, + "%N:%l:Receiver::open called\n")); + + // New connection, so initiate stuff. + + // Cache the new connection + this->handle_ = handle; + + // File offset starts at zero + this->file_offset_ = 0; + + // Open dump file (in OVERLAPPED mode) + this->dump_file_ = ACE_OS::open (dump_file, + O_CREAT | O_RDWR | O_TRUNC | \ + FILE_FLAG_OVERLAPPED); + if (this->dump_file_ == ACE_INVALID_HANDLE) + { + ACE_ERROR ((LM_ERROR, + "%p\n", + "ACE_OS::open")); + return; + } + + // Initiate <ACE_Asynch_Write_File>. + if (this->wf_.open (*this, + this->dump_file_) == -1) + { + ACE_ERROR ((LM_ERROR, + "%p\n", + "ACE_Asynch_Write_File::open")); + return; + } + + // Initiate <ACE_Asynch_Read_Stream>. + if (this->rs_.open (*this, this->handle_) == -1) + { + ACE_ERROR ((LM_ERROR, + "%p\n", + "ACE_Asynch_Read_Stream::open")); + return; + } + + // Fake the result and make the <handle_read_stream> get + // called. But, not, if there is '0' is transferred. + if (message_block.length () != 0) + { + // Duplicate the message block so that we can keep it around. + ACE_Message_Block &duplicate = + *message_block.duplicate (); + + // Fake the result so that we will get called back. + ACE_Asynch_Read_Stream_Result_Impl *fake_result = + ACE_Proactor::instance ()->create_asynch_read_stream_result (this->proxy (), + this->handle_, + duplicate, + initial_read_size, + 0, + ACE_INVALID_HANDLE, + 0, + 0); + + size_t bytes_transferred = message_block.length (); + + // <complete> for Accept would have already moved the <wr_ptr> + // forward. Update it to the beginning position. + duplicate.wr_ptr (duplicate.wr_ptr () - bytes_transferred); + + // This will call the callback. + fake_result->complete (message_block.length (), + 1, + 0); + + // Zap the fake result. + delete fake_result; + } + else + // Otherwise, make sure we proceed. Initiate reading the socket + // stream. + if (this->initiate_read_stream () == -1) + return; +} + +int +Receiver::initiate_read_stream (void) +{ + // Create a new <Message_Block>. Note that this message block will + // be used both to <read> data asynchronously from the socket and to + // <write> data asynchronously to the file. + ACE_Message_Block *mb = 0; + ACE_NEW_RETURN (mb, + ACE_Message_Block (BUFSIZ + 1), + -1); + + // Inititiate read + if (this->rs_.read (*mb, + mb->size () - 1) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "ACE_Asynch_Read_Stream::read"), + -1); + return 0; +} + +void +Receiver::handle_read_stream (const ACE_Asynch_Read_Stream::Result &result) +{ + ACE_DEBUG ((LM_DEBUG, + "handle_read_stream called\n")); + + // Reset pointers. + result.message_block ().rd_ptr ()[result.bytes_transferred ()] = '\0'; + + ACE_DEBUG ((LM_DEBUG, "********************\n")); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "bytes_to_read", result.bytes_to_read ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "handle", result.handle ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "bytes_transfered", result.bytes_transferred ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "act", (u_long) result.act ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "success", result.success ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "completion_key", (u_long) result.completion_key ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "error", result.error ())); + ACE_DEBUG ((LM_DEBUG, "********************\n")); +#if 0 + // This can overrun the ACE_Log_Msg buffer and do bad things. + // Re-enable it at your risk. + ACE_DEBUG ((LM_DEBUG, "%s = %s\n", "message_block", result.message_block ().rd_ptr ())); +#endif /* 0 */ + + if (result.success () && result.bytes_transferred () != 0) + { + // Successful read: write the data to the file asynchronously. + // Note how we reuse the <ACE_Message_Block> for the writing. + // Therefore, we do not delete this buffer because it is handled + // in <handle_write_stream>. + if (this->wf_.write (result.message_block (), + result.bytes_transferred (), + this->file_offset_) == -1) + { + ACE_ERROR ((LM_ERROR, + "%p\n", + "ACE_Asynch_Write_File::write")); + return; + } + + // Initiate new read from the stream. + if (this->initiate_read_stream () == -1) + return; + } + else + { + ACE_DEBUG ((LM_DEBUG, + "Receiver completed\n")); + + // No need for this message block anymore. + result.message_block ().release (); + + // Note that we are done with the test. + done = 1; + + // We are done: commit suicide. + delete this; + } +} + +void +Receiver::handle_write_file (const ACE_Asynch_Write_File::Result &result) +{ + ACE_DEBUG ((LM_DEBUG, "handle_write_file called\n")); + + ACE_DEBUG ((LM_DEBUG, "********************\n")); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "bytes_to_write", result.bytes_to_write ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "handle", result.handle ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "bytes_transfered", result.bytes_transferred ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "act", (u_long) result.act ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "success", result.success ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "completion_key", (u_long) result.completion_key ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "error", result.error ())); + ACE_DEBUG ((LM_DEBUG, "********************\n")); + + result.message_block ().release (); + + if (result.success ()) + // Write successful: Increment file offset + this->file_offset_ += result.bytes_transferred (); + + // This code is not robust enough to deal with short file writes + // (which hardly ever happen) ;-) + ACE_ASSERT (result.bytes_to_write () == result.bytes_transferred ()); +} + +class Sender : public ACE_Handler +{ + // = TITLE + // The class will be created by <main>. After connecting to the + // host, this class will then read data from a file and send it + // to the network connection. +public: + Sender (void); + ~Sender (void); + int open (const ACE_TCHAR *host, + u_short port); + ACE_HANDLE handle (void) const; + void handle (ACE_HANDLE); + +protected: + // These methods are called by the freamwork + + virtual void handle_transmit_file (const ACE_Asynch_Transmit_File::Result &result); + // This is called when asynchronous transmit files complete + virtual void handle_write_stream (const ACE_Asynch_Write_Stream::Result &result); + // This is called when asynchronous writes from the socket complete + virtual void handle_read_file (const ACE_Asynch_Read_File::Result &result); + // This is called when asynchronous reads from the socket complete + +private: + int transmit_file (void); + // Transmit the entire file in one fell swoop. + + int initiate_read_file (void); + // Initiate an asynchronous file read. + + ACE_SOCK_Stream stream_; + // Network I/O handle + + ACE_Asynch_Write_Stream ws_; + // ws (write stream): for writing to the socket + + ACE_Asynch_Read_File rf_; + // rf (read file): for writing from the file + + ACE_Asynch_Transmit_File tf_; + // Transmit file. + + ACE_HANDLE input_file_; + // File to read from + + u_long file_offset_; + // Current file offset + + u_long file_size_; + // File size + + ACE_Message_Block welcome_message_; + // Welcome message + + ACE_Asynch_Transmit_File::Header_And_Trailer header_and_trailer_; + // Header and trailer which goes with transmit_file + + int stream_write_done_; + int transmit_file_done_; + // These flags help to determine when to close down the event loop +}; + +Sender::Sender (void) + : input_file_ (ACE_INVALID_HANDLE), + file_offset_ (0), + file_size_ (0), + stream_write_done_ (0), + transmit_file_done_ (0) +{ + // Moment of inspiration... :-) + static const char *data = "Welcome to Irfan World! Irfan RULES here !!\n"; + this->welcome_message_.init (data, + ACE_OS::strlen (data)); + this->welcome_message_.wr_ptr (ACE_OS::strlen (data)); +} + +Sender::~Sender (void) +{ + this->stream_.close (); +} + +ACE_HANDLE +Sender::handle (void) const +{ + return this->stream_.get_handle (); +} + +void +Sender::handle (ACE_HANDLE handle) +{ + this->stream_.set_handle (handle); +} + +int +Sender::open (const ACE_TCHAR *host, + u_short port) +{ + // Initialize stuff + + // Open input file (in OVERLAPPED mode) + this->input_file_ = + ACE_OS::open (file, GENERIC_READ | FILE_FLAG_OVERLAPPED); + if (this->input_file_ == ACE_INVALID_HANDLE) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "ACE_OS::open"), -1); + + // Find file size + this->file_size_ = + ACE_OS::filesize (this->input_file_); + + // Connect to remote host + ACE_INET_Addr address (port, host); + ACE_SOCK_Connector connector; + if (connector.connect (this->stream_, + address) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "ACE_SOCK_Connector::connect"), + -1); + + // Open ACE_Asynch_Write_Stream + if (this->ws_.open (*this) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "ACE_Asynch_Write_Stream::open"), + -1); + + // Open ACE_Asynch_Read_File + if (this->rf_.open (*this, this->input_file_) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "ACE_Asynch_Read_File::open"), + -1); + + // Start an asynchronous transmit file + if (this->transmit_file () == -1) + return -1; + + // Start an asynchronous read file + if (this->initiate_read_file () == -1) + return -1; + + return 0; +} + +int +Sender::transmit_file (void) +{ + // Open file (in SEQUENTIAL_SCAN mode) + ACE_HANDLE file_handle = + ACE_OS::open (file, GENERIC_READ | FILE_FLAG_SEQUENTIAL_SCAN); + if (file_handle == ACE_INVALID_HANDLE) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "ACE_OS::open"), + -1); + + // Open ACE_Asynch_Transmit_File + if (this->tf_.open (*this) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "ACE_Asynch_Transmit_File::open"), + -1); + + // Header and trailer data for the file. + // @@ What happens if header and trailer are the same? + this->header_and_trailer_.header_and_trailer (&this->welcome_message_, + this->welcome_message_.length (), + &this->welcome_message_, + this->welcome_message_.length ()); + + // Send the entire file in one fell swoop! + if (this->tf_.transmit_file (file_handle, + &this->header_and_trailer_) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "ACE_Asynch_Transmit_File::transmit_file"), + -1); + + return 0; +} + +void +Sender::handle_transmit_file (const ACE_Asynch_Transmit_File::Result &result) +{ + ACE_DEBUG ((LM_DEBUG, + "handle_transmit_file called\n")); + + ACE_DEBUG ((LM_DEBUG, "********************\n")); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "socket", result.socket ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "file", result.file ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "bytes_to_write", result.bytes_to_write ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "bytes_per_send", result.bytes_per_send ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "flags", result.flags ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "bytes_transfered", result.bytes_transferred ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "act", (u_long) result.act ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "success", result.success ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "completion_key", (u_long) result.completion_key ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "error", result.error ())); + ACE_DEBUG ((LM_DEBUG, "********************\n")); + + // Done with file + ACE_OS::close (result.file ()); + + this->transmit_file_done_ = 1; + if (this->stream_write_done_) + done = 1; +} + +int +Sender::initiate_read_file (void) +{ + // Create a new <Message_Block>. Note that this message block will + // be used both to <read> data asynchronously from the file and to + // <write> data asynchronously to the socket. + ACE_Message_Block *mb = 0; + ACE_NEW_RETURN (mb, + ACE_Message_Block (BUFSIZ + 1), + -1); + + // Inititiate an asynchronous read from the file + if (this->rf_.read (*mb, + mb->size () - 1, + this->file_offset_) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "ACE_Asynch_Read_File::read"), + -1); + return 0; +} + +void +Sender::handle_read_file (const ACE_Asynch_Read_File::Result &result) +{ + ACE_DEBUG ((LM_DEBUG, + "handle_read_file called\n")); + + result.message_block ().rd_ptr ()[result.bytes_transferred ()] = '\0'; + + ACE_DEBUG ((LM_DEBUG, "********************\n")); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "bytes_to_read", result.bytes_to_read ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "handle", result.handle ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "bytes_transfered", result.bytes_transferred ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "act", (u_long) result.act ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "success", result.success ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "completion_key", (u_long) result.completion_key ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "error", result.error ())); + ACE_DEBUG ((LM_DEBUG, "********************\n")); + //ACE_DEBUG ((LM_DEBUG, "%s = %s\n", "message_block", result.message_block ().rd_ptr ())); + + if (result.success ()) + { + // Read successful: increment offset and write data to network. + // Note how we reuse the <ACE_Message_Block> for the writing. + // Therefore, we do not delete this buffer because it is handled + // in <handle_write_stream>. + + this->file_offset_ += result.bytes_transferred (); + if (this->ws_.write (result.message_block (), + result.bytes_transferred ()) == -1) + { + ACE_ERROR ((LM_ERROR, + "%p\n", + "ACE_Asynch_Write_Stream::write")); + return; + } + + if (this->file_size_ > this->file_offset_) + { + // Start an asynchronous read file. + if (initiate_read_file () == -1) + return; + } + } +} + +void +Sender::handle_write_stream (const ACE_Asynch_Write_Stream::Result &result) +{ + ACE_DEBUG ((LM_DEBUG, + "handle_write_stream called\n")); + + // Reset pointers. + result.message_block ().rd_ptr (result.message_block ().rd_ptr () - result.bytes_transferred ()); + + ACE_DEBUG ((LM_DEBUG, "********************\n")); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "bytes_to_write", result.bytes_to_write ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "handle", result.handle ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "bytes_transfered", result.bytes_transferred ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "act", (u_long) result.act ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "success", result.success ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "completion_key", (u_long) result.completion_key ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "error", result.error ())); + ACE_DEBUG ((LM_DEBUG, "********************\n")); +#if 0 + ACE_DEBUG ((LM_DEBUG, "%s = %s\n", "message_block", result.message_block ().rd_ptr ())); +#endif + + if (result.success ()) + { + // Partial write to socket + int unsent_data = result.bytes_to_write () - result.bytes_transferred (); + if (unsent_data != 0) + { + // Reset pointers + result.message_block ().rd_ptr (result.bytes_transferred ()); + + // Duplicate the message block and retry remaining data + if (this->ws_.write (*result.message_block ().duplicate (), + unsent_data) == -1) + { + ACE_ERROR ((LM_ERROR, + "%p\n", + "ACE_Asynch_Write_Stream::write")); + return; + } + } + else if (!(this->file_size_ > this->file_offset_)) + { + this->stream_write_done_ = 1; + if (this->transmit_file_done_) + done = 1; + } + } + + // Release message block. + result.message_block ().release (); +} + +static int +parse_args (int argc, ACE_TCHAR *argv[]) +{ + ACE_Get_Opt get_opt (argc, argv, ACE_TEXT("h:p:f:d:")); + int c; + + while ((c = get_opt ()) != EOF) + switch (c) + { + case 'h': + host = get_opt.opt_arg (); + break; + case 'p': + port = ACE_OS::atoi (get_opt.opt_arg ()); + break; + case 'f': + file = get_opt.opt_arg (); + break; + case 'd': + dump_file = get_opt.opt_arg (); + break; + default: + ACE_ERROR ((LM_ERROR, "%p.\n", + "usage :\n" + "-h <host>\n" + "-p <port>\n" + "-f <file>\n")); + return -1; + } + + return 0; +} + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + if (parse_args (argc, argv) == -1) + return -1; + + Sender sender; + + // Note: acceptor parameterized by the Receiver. + ACE_Asynch_Acceptor<Receiver> acceptor; + + // If passive side + if (host == 0) + { + if (acceptor.open (ACE_INET_Addr (port), + initial_read_size, + 1) == -1) + return -1; + } + // If active side + else if (sender.open (host, port) == -1) + return -1; + + int success = 1; + + while (success > 0 && !done) + // Dispatch events via Proactor singleton. + success = ACE_Proactor::instance ()->handle_events (); + + return 0; +} + +#else /* ACE_WIN32 && !ACE_HAS_WINCE || ACE_HAS_AIO_CALLS*/ + +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_DEBUG ((LM_DEBUG, + "This example does not work on this platform.\n")); + return 1; +} + +#endif /* ACE_WIN32 && !ACE_HAS_WINCE || ACE_HAS_AIO_CALLS*/ diff --git a/ACE/examples/Reactor/Proactor/test_proactor.h b/ACE/examples/Reactor/Proactor/test_proactor.h new file mode 100644 index 00000000000..482e176041e --- /dev/null +++ b/ACE/examples/Reactor/Proactor/test_proactor.h @@ -0,0 +1,56 @@ +/* +** $Id$ +*/ + +#ifndef _TEST_PROACTOR_H +#define _TEST_PROACTOR_H + +#include "ace/Asynch_IO.h" + +class Receiver : public ACE_Service_Handler +{ + // = TITLE + // The class will be created by <ACE_Asynch_Acceptor> when new + // connections arrive. This class will then receive data from + // the network connection and dump it to a file. +public: + // = Initialization and termination. + Receiver (void); + ~Receiver (void); + + virtual void open (ACE_HANDLE handle, + ACE_Message_Block &message_block); + // This is called after the new connection has been accepted. + +protected: + // These methods are called by the framework + + virtual void handle_read_stream (const ACE_Asynch_Read_Stream::Result &result); + // This is called when asynchronous <read> operation from the socket + // complete. + + virtual void handle_write_file (const ACE_Asynch_Write_File::Result &result); + // This is called when an asynchronous <write> to the file + // completes. + +private: + int initiate_read_stream (void); + // Initiate an asynchronous <read> operation on the socket. + + ACE_Asynch_Read_Stream rs_; + // rs (read stream): for reading from a socket. + + ACE_HANDLE dump_file_; + // File for dumping data. + + ACE_Asynch_Write_File wf_; + // wf (write file): for writing to a file. + + u_long file_offset_; + // Offset for the file. + + ACE_HANDLE handle_; + // Handle for IO to remote peer. +}; + +#endif /* _TEST_PROACTOR_H */ diff --git a/ACE/examples/Reactor/Proactor/test_proactor2.cpp b/ACE/examples/Reactor/Proactor/test_proactor2.cpp new file mode 100644 index 00000000000..cd5cbf7092e --- /dev/null +++ b/ACE/examples/Reactor/Proactor/test_proactor2.cpp @@ -0,0 +1,808 @@ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// examples +// +// = FILENAME +// test_proactor2.cpp +// +// = DESCRIPTION +// Alexander Libman <Alibman@baltimore.com> modified +// <test_proactor> and made this test. Instead of writing received +// data to the file, the receiver sends them back to the +// sender,i.e. ACE_Asynch_Write_File wf_ has been changed to +// ACE_Asynch_Write_Stream wf_. +// +// = AUTHOR +// Irfan Pyarali <irfan@cs.wustl.edu> and Alexander Libman +// <Alibman@baltimore.com>. +// ============================================================================ + +#include "ace/Signal.h" + +#include "ace/Service_Config.h" +#include "ace/Proactor.h" +#include "ace/Asynch_IO.h" +#include "ace/Asynch_IO_Impl.h" +#include "ace/Asynch_Acceptor.h" +#include "ace/INET_Addr.h" +#include "ace/SOCK_Connector.h" +#include "ace/SOCK_Acceptor.h" +#include "ace/SOCK_Stream.h" +#include "ace/Message_Block.h" +#include "ace/Get_Opt.h" + +// FUZZ: disable check_for_streams_include +#include "ace/streams.h" + +#include "ace/Task.h" +#include "ace/OS_main.h" + +ACE_RCSID(Proactor, test_proactor2, "test_proactor2.cpp,v 1.27 2000/03/07 17:15:56 schmidt Exp") + +#if ((defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)) || (defined (ACE_HAS_AIO_CALLS))) + // This only works on Win32 platforms and on Unix platforms supporting + // POSIX aio calls. + +#if defined (ACE_WIN32) && !defined (ACE_HAS_WINCE) + +#include "ace/WIN32_Proactor.h" + +#elif defined (ACE_HAS_AIO_CALLS) + +#include "ace/POSIX_Proactor.h" + +#endif + + // Some debug helper functions + int DisableSignal ( int SigNum ); +int PrintSigMask (); + +#define COUT(X) cout << X ; cout.flush (); + +// Host that we're connecting to. +static ACE_TCHAR *host = 0; + +// duplex mode: ==0 half-duplex +// !=0 full duplex +static int duplex = 0 ; + +// number threads in the Proactor thread pool +static int nThreads = 1; + +// Port that we're receiving connections on. +static u_short port = ACE_DEFAULT_SERVER_PORT; + +// Size of each initial asynchronous <read> operation. +static int initial_read_size = BUFSIZ; + + +#define MyMutex ACE_Recursive_Thread_Mutex +//#define MyMutex ACE_Thread_Mutex +//#define MyMutex ACE_Null_Mutex + +//-------------------------------------------------------------------------- +// MyTask plays role for Proactor threads pool +//-------------------------------------------------------------------------- +class MyTask: public ACE_Task<ACE_MT_SYNCH> +{ + +public: + + int svc (void) ; +}; + + +int MyTask::svc (void ) +{ + ACE_DEBUG ((LM_DEBUG, "(%t) MyTask started\n")); + + while ( ACE_Proactor::event_loop_done () == 0 ) + { + ACE_Proactor::run_event_loop (); + } + + ACE_DEBUG ((LM_DEBUG, "(%t) MyTask finished\n")); + return 0 ; +} + +//----------------------------------------------------------- +// Receiver +//----------------------------------------------------------- +class Receiver : public ACE_Service_Handler +{ +public: + + Receiver (void); + ~Receiver (void); + + virtual void open (ACE_HANDLE handle, + ACE_Message_Block &message_block); + // This is called after the new connection has been accepted. + +protected: + // These methods are called by the framework + + virtual void handle_read_stream (const ACE_Asynch_Read_Stream::Result + &result); + // This is called when asynchronous <read> operation from the socket + // complete. + + virtual void handle_write_stream (const ACE_Asynch_Write_Stream::Result + &result); + // This is called when an asynchronous <write> to the file + // completes. + +private: + int initiate_read_stream (void); + int initiate_write_stream (ACE_Message_Block & mb, int nBytes ); + bool check_destroy () ; + + ACE_Asynch_Read_Stream rs_; + ACE_Asynch_Write_Stream ws_; + ACE_HANDLE handle_; + MyMutex m_Mtx ; + long nIOCount ; + static long nSessions ; +}; + + +long Receiver::nSessions = 0 ; + +Receiver::Receiver (void) + : handle_ (ACE_INVALID_HANDLE), + nIOCount ( 0 ) +{ + ACE_Guard<MyMutex> locker (m_Mtx) ; + nSessions ++ ; + ACE_DEBUG ((LM_DEBUG, "Receiver Ctor nSessions=%d\n", nSessions )); +} + +Receiver::~Receiver (void) +{ + ACE_Guard<MyMutex> locker (m_Mtx) ; + nSessions -- ; + ACE_OS::closesocket (this->handle_); + ACE_DEBUG ((LM_DEBUG, "~Receiver Dtor nSessions=%d\n", nSessions )); +} + +//--------------------------------------------------------------------- +// return true if we alive, false we commited suicide +// +//--------------------------------------------------------------------- +bool Receiver::check_destroy () +{ + { + ACE_Guard<MyMutex> locker (m_Mtx) ; + + if ( nIOCount > 0 ) + { + return true ; + } + } + + delete this ; + return false ; +} + + +void Receiver::open (ACE_HANDLE handle, + ACE_Message_Block &message_block) +{ + ACE_UNUSED_ARG (message_block); + + ACE_DEBUG ((LM_DEBUG, + "%N:%l:Receiver::open called\n")); + + + this->handle_ = handle; + + if (this->ws_.open (*this, this->handle_ ) == -1) + { + ACE_ERROR ((LM_ERROR, + "%p\n", + "ACE_Asynch_Write_Stream::open")); + + } + else if (this->rs_.open (*this, this->handle_) == -1) + { + ACE_ERROR ((LM_ERROR, + "%p\n", + "ACE_Asynch_Read_Stream::open")); + } + else + { + initiate_read_stream (); + } + + + check_destroy (); +} + +int Receiver::initiate_read_stream (void) +{ + ACE_Guard<MyMutex> locker (m_Mtx) ; + + // Create a new <Message_Block>. Note that this message block will + // be used both to <read> data asynchronously from the socket and to + // <write> data asynchronously to the file. + ACE_DEBUG ((LM_DEBUG, + "initiate_read_stream called\n")); + + + ACE_Message_Block *mb = 0; + ACE_NEW_RETURN (mb, + ACE_Message_Block (BUFSIZ + 1), + -1); + + // Inititiate read + if (this->rs_.read (*mb, mb->size ()- 1) == -1) + { + mb->release () ; + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "ACE_Asynch_Read_Stream::read"), + -1); + } + + nIOCount++ ; + return 0; +} + +int Receiver::initiate_write_stream (ACE_Message_Block & mb, int nBytes ) +{ + ACE_Guard<MyMutex> locker (m_Mtx) ; + if (this->ws_.write (mb , nBytes ) == -1) + { + mb.release (); + ACE_ERROR_RETURN((LM_ERROR, + "%p\n", + "ACE_Asynch_Write_File::write"), + -1); + } + + nIOCount++ ; + return 0; +} + +void +Receiver::handle_read_stream (const ACE_Asynch_Read_Stream::Result &result) +{ + ACE_DEBUG ((LM_DEBUG, + "handle_read_stream called\n")); + + // Reset pointers. + result.message_block ().rd_ptr ()[result.bytes_transferred ()] = + '\0'; + + ACE_DEBUG ((LM_DEBUG, "********************\n")); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "bytes_to_read", result.bytes_to_read + ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "handle", result.handle ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "bytes_transfered", + result.bytes_transferred ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "act", (u_long) result.act ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "success", result.success ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "completion_key", (u_long) + result.completion_key ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "error", result.error ())); + ACE_DEBUG ((LM_DEBUG, "********************\n")); + ACE_DEBUG ((LM_DEBUG, "%s = %s\n", "message_block", + result.message_block ().rd_ptr ())); + + if ( result.success () && result.bytes_transferred () != 0) + { + // Successful read: write the data to the file asynchronously. + // Note how we reuse the <ACE_Message_Block> for the writing. + // Therefore, we do not delete this buffer because it is handled + // in <handle_write_stream>. + + if(this->initiate_write_stream (result.message_block (), + + result.bytes_transferred () ) == 0 ) + { + if ( duplex != 0 ) + { + // Initiate new read from the stream. + this->initiate_read_stream () ; + } + } + } + else + { + result.message_block ().release (); + ACE_DEBUG ((LM_DEBUG, "Receiver completed\n")); + } + + { + ACE_Guard<MyMutex> locker (m_Mtx) ; + nIOCount-- ; + } + check_destroy () ; +} + +void +Receiver::handle_write_stream (const ACE_Asynch_Write_Stream::Result + &result) +{ + ACE_DEBUG ((LM_DEBUG, "handle_write_stream called\n")); + + ACE_DEBUG ((LM_DEBUG, "********************\n")); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "bytes_to_write", + result.bytes_to_write ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "handle", result.handle ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "bytes_transfered", + result.bytes_transferred ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "act", (u_long) result.act ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "success", result.success ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "completion_key", (u_long) + result.completion_key ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "error", result.error ())); + ACE_DEBUG ((LM_DEBUG, "********************\n")); + + result.message_block ().release (); + + if (result.success ()) + { + // This code is not robust enough to deal with short file writes + // (which hardly ever happen) ;-) + //ACE_ASSERT (result.bytes_to_write () == result.bytes_transferred ()); + + if ( duplex == 0 ) + { + initiate_read_stream () ; + } + } + + { + ACE_Guard<MyMutex> locker (m_Mtx) ; + nIOCount-- ; + } + check_destroy () ; +} + +//------------------------------------------------------------------------- +// Sender: sends indefinetely welcome message +// and recieves it back +//------------------------------------------------------------------------ +class Sender : public ACE_Handler +{ +public: + Sender (void); + ~Sender (void); + int open (const ACE_TCHAR *host, u_short port); + void close (); + ACE_HANDLE handle (void) const; + void handle (ACE_HANDLE); + +protected: +// These methods are called by the freamwork + +virtual void handle_read_stream (const ACE_Asynch_Read_Stream::Result +&result); +// This is called when asynchronous reads from the socket complete + +virtual void handle_write_stream (const ACE_Asynch_Write_Stream::Result +&result); +// This is called when asynchronous writes from the socket complete + +private: + +int initiate_read_stream (void); +int initiate_write_stream (void); + +ACE_SOCK_Stream stream_; +// Network I/O handle + +ACE_Asynch_Write_Stream ws_; +// ws (write stream): for writing to the socket + +ACE_Asynch_Read_Stream rs_; +// rs (read file): for reading from the socket + +ACE_Message_Block welcome_message_; +// Welcome message + +MyMutex m_Mtx ; +long nIOCount ; +}; + +static char *data = "Welcome to Irfan World! Irfan RULES here !!\n"; + +Sender::Sender (void) + :nIOCount ( 0 ) +{ + // Moment of inspiration... :-) + this->welcome_message_.init (data, ACE_OS::strlen (data)); +} + +Sender::~Sender (void) +{ + close (); +} + +void Sender::close () +{ + this->stream_.close (); +} + +ACE_HANDLE Sender::handle (void) const +{ + return this->stream_.get_handle (); +} + +void Sender::handle (ACE_HANDLE handle) +{ + this->stream_.set_handle (handle); +} + +int Sender::open (const ACE_TCHAR *host, u_short port) +{ + // Initialize stuff + // Connect to remote host + ACE_INET_Addr address (port, host); + ACE_SOCK_Connector connector; + + if (connector.connect (this->stream_, + address) == -1) + { + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "ACE_SOCK_Connector::connect"), + -1); + } + + // Open ACE_Asynch_Write_Stream + if (this->ws_.open (*this) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "ACE_Asynch_Write_Stream::open"), + -1); + + // Open ACE_Asynch_Read_Stream + if (this->rs_.open (*this) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "ACE_Asynch_Read_File::open"), + -1); + + // Start an asynchronous transmit file + if ( this->initiate_write_stream () == -1) + return -1; + + if ( duplex != 0 ) + { + // Start an asynchronous read file + if (this->initiate_read_stream () == -1) + return -1; + } + + return 0; +} + +int Sender::initiate_write_stream (void) +{ + ACE_Guard<MyMutex> locker (m_Mtx) ; + + + welcome_message_.rd_ptr( welcome_message_.base ()); + welcome_message_.wr_ptr( welcome_message_.base ()); + welcome_message_.wr_ptr (ACE_OS::strlen (data)); + + if (this->ws_.write (welcome_message_, + welcome_message_.length () + ) == -1) + { + ACE_ERROR_RETURN((LM_ERROR, + "%p\n", + "ACE_Asynch_Write_File::write"), + -1); + } + + nIOCount++ ; + return 0; +} + +int Sender::initiate_read_stream (void) +{ + ACE_Guard<MyMutex> locker (m_Mtx) ; + + // Create a new <Message_Block>. Note that this message block will + // be used both to <read> data asynchronously from the socket and to + // <write> data asynchronously to the file. + ACE_DEBUG ((LM_DEBUG, + "initiate_read_stream called\n")); + + + ACE_Message_Block *mb = 0; + ACE_NEW_RETURN (mb, + ACE_Message_Block (BUFSIZ + 1), + -1); + + // Inititiate read + if (this->rs_.read (*mb, mb->size ()- 1) == -1) + { + mb->release () ; + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "ACE_Asynch_Read_Stream::read"), + -1); + } + + nIOCount++ ; + return 0; +} + + +void Sender::handle_write_stream (const ACE_Asynch_Write_Stream::Result + &result) +{ + ACE_DEBUG ((LM_DEBUG, + "handle_write_stream called\n")); + + // Reset pointers. + result.message_block ().rd_ptr (result.message_block ().rd_ptr () - + result.bytes_transferred ()); + + + ACE_DEBUG ((LM_DEBUG, "********************\n")); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "bytes_to_write", + result.bytes_to_write ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "handle", result.handle ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "bytes_transfered", + result.bytes_transferred ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "act", (u_long) result.act ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "success", result.success ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "completion_key", (u_long) + result.completion_key ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "error", result.error ())); + ACE_DEBUG ((LM_DEBUG, "********************\n")); + ACE_DEBUG ((LM_DEBUG, "%s = %s\n", "message_block", + result.message_block ().rd_ptr ())); + + // Simplify just for Test + if (result.success () && result.bytes_transferred () != 0) + { + if ( duplex != 0 ) // full duplex, continue write + { + initiate_write_stream () ; + } + else // half-duplex read reply, after read we will start + // write + { + initiate_read_stream () ; + } + } + + { + ACE_Guard<MyMutex> locker (m_Mtx) ; + nIOCount-- ; + } +} + +void +Sender::handle_read_stream (const ACE_Asynch_Read_Stream::Result &result) +{ + ACE_DEBUG ((LM_DEBUG, + "handle_read_stream called\n")); + + // Reset pointers. + result.message_block ().rd_ptr ()[result.bytes_transferred ()] = + '\0'; + + ACE_DEBUG ((LM_DEBUG, "********************\n")); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "bytes_to_read", result.bytes_to_read + ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "handle", result.handle ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "bytes_transfered", + result.bytes_transferred ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "act", (u_long) result.act ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "success", result.success ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "completion_key", (u_long) + result.completion_key ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "error", result.error ())); + ACE_DEBUG ((LM_DEBUG, "********************\n")); + ACE_DEBUG ((LM_DEBUG, "%s = %s\n", "message_block", + result.message_block ().rd_ptr ())); + + result.message_block().release (); + + if ( result.success () && result.bytes_transferred () != 0) + { + // Successful read: write the data to the file asynchronously. + // Note how we reuse the <ACE_Message_Block> for the writing. + // Therefore, we do not delete this buffer because it is handled + // in <handle_write_stream>. + + if ( duplex != 0 ) // full duplex, continue read + { + initiate_read_stream () ; + } + else // half-duplex writey, after write we will start read + { + initiate_write_stream () ; + } + } + + { + ACE_Guard<MyMutex> locker (m_Mtx) ; + nIOCount-- ; + } +} + +//-------------------------------------------------------------------------- + +static int +parse_args (int argc, ACE_TCHAR *argv[]) +{ + ACE_Get_Opt get_opt (argc, argv, ACE_TEXT("n:p:d:h:")); + int c; + + while ((c = get_opt ()) != EOF) + switch (c) + { + case 'h': + host = get_opt.opt_arg (); + break; + case 'n': + nThreads = ACE_OS::atoi (get_opt.opt_arg ()) ; + break; + case 'p': + port = ACE_OS::atoi (get_opt.opt_arg ()); + break; + case 'd': + duplex = ACE_OS::atoi (get_opt.opt_arg ()); + break; + default: + ACE_ERROR ((LM_ERROR, "%p.\n", + "usage :\n" + "-h <host> for Sender mode\n" + "-d <duplex mode 1-on/0-off>\n" + "-p <port to listen/connect>\n" + "-n <number threads for Proactor pool>\n")); + return -1; + } + + return 0; +} + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + ACE_UNUSED_ARG (initial_read_size); + + if (parse_args (argc, argv) == -1) + return -1; + +#if defined (ACE_WIN32) && !defined (ACE_HAS_WINCE) + + ACE_WIN32_Proactor * pImpl = new ACE_WIN32_Proactor; + +#elif defined (ACE_HAS_AIO_CALLS) + + // ACE_POSIX_AIOCB_Proactor * pImpl = new ACE_POSIX_AIOCB_Proactor; + ACE_POSIX_SIG_Proactor * pImpl = new ACE_POSIX_SIG_Proactor; +#endif + + ACE_Proactor Proactor ( pImpl ,1 ); + + ACE_Proactor::instance( & Proactor ); + + + MyTask Task1 ; + + if (Task1.activate (THR_NEW_LWP, nThreads ) == -1) + { + ACE_ERROR_RETURN ((LM_ERROR, "%p.\n", "main"), -1); + } + + Sender sender; + ACE_Asynch_Acceptor<Receiver> acceptor; + + int Rc = -1 ; + + if ( host == NULL ) // Acceptor + { + // Simplify , initial read with zero size + Rc = acceptor.open (ACE_INET_Addr (port),0,1); + + } + else + { + Rc = sender.open (host, port); + } + + if ( Rc == 0 ) + { + char c ; + cout << "Press any key to stop and exit=>\n" << flush ; + cin.clear (); + cin >> c ; + } + + ACE_Proactor::end_event_loop () ; + + if ( host != NULL ) // we are sender + { + sender.close () ; // disconnect to get reciever error !!! + } + + + ACE_Thread_Manager * pTM = ACE_Thread_Manager::instance(); + + pTM->wait_task ( & Task1 ) ; + + ACE_Proactor::instance( ( ACE_Proactor* )NULL ); + + return 0; +} +//-------------------------------------------------------------------- +// +//-------------------------------------------------------------------- +int DisableSignal ( int SigNum ) +{ + +#ifndef ACE_WIN32 + sigset_t signal_set; + if ( sigemptyset (&signal_set) == - 1 ) + { + ACE_ERROR ((LM_ERROR, + "Error:(%P | %t):%p\n", + "sigemptyset failed")); + } + + sigaddset (&signal_set, SigNum); + + // Put the <signal_set>. + if (ACE_OS::pthread_sigmask (SIG_BLOCK, &signal_set, 0) != 0) + { + ACE_ERROR ((LM_ERROR, + "Error:(%P | %t):%p\n", + "pthread_sigmask failed")); + } +#else + ACE_UNUSED_ARG(SigNum); +#endif + + return 1; +} +//-------------------------------------------------------------------- +// Get the <signal_set> back from the OS. +//-------------------------------------------------------------------- + +int PrintSigMask () +{ +#ifndef ACE_WIN32 + + sigset_t mask ; + int member = 0; + + COUT ( "\n=============Signal Mask==========" ) + + if (ACE_OS::pthread_sigmask (SIG_SETMASK, 0, & mask ) != 0) + { + ACE_ERROR ((LM_ERROR, + "Error:(%P | %t):%p\n", + "ACE_OS::pthread_sigmask failed")); + } + else for (int i = 1 ; i < 1000; i++) + { + member = sigismember (&mask,i); + + COUT ( "\nSig " ) + COUT ( i ) + COUT ( " is " ) + COUT (member ) + + if (member == -1) + { + break ; + } + } +#endif + return 0; +} + +#endif /* ACE_WIN32 && !ACE_HAS_WINCE || ACE_HAS_AIO_CALLS*/ diff --git a/ACE/examples/Reactor/Proactor/test_proactor3.cpp b/ACE/examples/Reactor/Proactor/test_proactor3.cpp new file mode 100644 index 00000000000..c47468276c8 --- /dev/null +++ b/ACE/examples/Reactor/Proactor/test_proactor3.cpp @@ -0,0 +1,864 @@ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// examples +// +// = FILENAME +// test_proactor3.cpp +// +// = DESCRIPTION +// This program illustrates how the <ACE_Proactor> can be used to +// implement an application that does various asynchronous +// operations. +// +// = AUTHOR +// Irfan Pyarali <irfan@cs.wustl.edu> +// modified by Alexander Libman <alibman@baltimore.com> +// from original test_proactor.cpp +// ============================================================================ + +#include "ace/Signal.h" + +#include "ace/Service_Config.h" +#include "ace/Proactor.h" +#include "ace/Asynch_IO.h" +#include "ace/Asynch_IO_Impl.h" +#include "ace/Asynch_Acceptor.h" +#include "ace/INET_Addr.h" +#include "ace/SOCK_Connector.h" +#include "ace/SOCK_Acceptor.h" +#include "ace/SOCK_Stream.h" +#include "ace/Message_Block.h" +#include "ace/Get_Opt.h" + +// FUZZ: disable check_for_streams_include +#include "ace/streams.h" + +#include "ace/Task.h" + +ACE_RCSID(Proactor, test_proactor, "test_proactor.cpp,v 1.27 2000/03/07 17:15:56 schmidt Exp") + +#if ((defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)) || (defined (ACE_HAS_AIO_CALLS))) + // This only works on Win32 platforms and on Unix platforms + // supporting POSIX aio calls. + +#if defined (ACE_WIN32) && !defined (ACE_HAS_WINCE) + +# include "ace/WIN32_Proactor.h" + +#elif defined (ACE_HAS_AIO_CALLS) + +# include "ace/POSIX_Proactor.h" +# include "ace/SUN_Proactor.h" + +#endif /* defined (ACE_WIN32) && !defined (ACE_HAS_WINCE) */ + +// Some debug helper functions +static int disable_signal (int sigmin, int sigmax); +#if 0 +static int print_sigmask (void); +#endif + +#define COUT(X) cout << X; cout.flush (); + +// Proactor Type (UNIX only, Win32 ignored) 0-default, 1 -AIOCB, +// 2-SIG, 3-SUN +static int proactor_type = 0; + +// POSIX : > 0 max number aio operations proactor, +static int max_aio_operations = 0; + +// Host that we're connecting to. +static ACE_TCHAR *host = 0; + +// number of Senders instances +static int senders = 1; +static const int MaxSenders = 100; + +// duplex mode: ==0 half-duplex +// !=0 full duplex +static int duplex = 0; + +// number threads in the Proactor thread pool +static int threads = 1; + +// Port that we're receiving connections on. +static u_short port = ACE_DEFAULT_SERVER_PORT; + +class MyTask: public ACE_Task<ACE_MT_SYNCH> +{ + // = TITLE + // MyTask plays role for Proactor threads pool +public: + MyTask (void) : threads_ (0), proactor_ (0) {} + + int svc (void); + void waitready (void) { event_.wait (); } + +private: + ACE_Recursive_Thread_Mutex mutex_; + int threads_; + ACE_Proactor *proactor_; + ACE_Manual_Event event_; + + void create_proactor (void); + void delete_proactor (void); +}; + +void +MyTask::create_proactor (void) +{ + ACE_Guard<ACE_Recursive_Thread_Mutex> locker (mutex_); + + if (threads_ == 0) + { +#if defined (ACE_WIN32) && !defined (ACE_HAS_WINCE) + ACE_WIN32_Proactor *proactor = new ACE_WIN32_Proactor; + ACE_DEBUG ((LM_DEBUG,"(%t) Create Proactor Type=WIN32")); + +#elif defined (ACE_HAS_AIO_CALLS) + + ACE_POSIX_Proactor *proactor = 0; + + switch (proactor_type) + { + case 1: proactor = new ACE_POSIX_AIOCB_Proactor (max_aio_operations); + ACE_DEBUG ((LM_DEBUG,"(%t) Create Proactor Type=AIOCB\n")); + break; + case 2: proactor = new ACE_POSIX_SIG_Proactor; + ACE_DEBUG ((LM_DEBUG,"(%t) Create Proactor Type=SIG\n")); + break; +# if defined (sun) + case 3: proactor = new ACE_SUN_Proactor (max_aio_operations); + ACE_DEBUG ((LM_DEBUG,"(%t) Create Proactor Type=SUN\n")); + break; +# endif /* sun */ + default:proactor = new ACE_POSIX_SIG_Proactor; + ACE_DEBUG ((LM_DEBUG,"(%t) Create Proactor Type=SIG\n")); + break; + } +#endif + + proactor_ = new ACE_Proactor (proactor, 1); + + ACE_Proactor::instance(proactor_); + event_.signal (); + } + + threads_++; +} + +void +MyTask::delete_proactor (void) +{ + ACE_Guard<ACE_Recursive_Thread_Mutex> locker (mutex_); + if (--threads_ == 0) + { + ACE_DEBUG ((LM_DEBUG, "(%t) Delete Proactor\n")); + ACE_Proactor::instance ((ACE_Proactor *) 0); + delete proactor_; + proactor_ = 0; + } +} + +int +MyTask::svc (void) +{ + ACE_DEBUG ((LM_DEBUG, "(%t) MyTask started\n")); + + create_proactor (); + disable_signal (ACE_SIGRTMIN, ACE_SIGRTMAX); + + while (ACE_Proactor::event_loop_done () == 0) + ACE_Proactor::run_event_loop (); + + delete_proactor (); + + ACE_DEBUG ((LM_DEBUG, "(%t) MyTask finished\n")); + return 0; +} + +class Receiver : public ACE_Service_Handler +{ +public: + + Receiver (void); + ~Receiver (void); + + virtual void open (ACE_HANDLE handle, + ACE_Message_Block &message_block); + // This is called after the new connection has been accepted. + + static long get_number_sessions (void) { return sessions_; } + +protected: + // These methods are called by the framework + + virtual void handle_read_stream (const ACE_Asynch_Read_Stream::Result &result); + // This is called when asynchronous <read> operation from the socket + // complete. + + virtual void handle_write_stream (const ACE_Asynch_Write_Stream::Result &result); + // This is called when an asynchronous <write> to the file + // completes. + +private: + int initiate_read_stream (void); + int initiate_write_stream (ACE_Message_Block & mb, int nBytes); + int check_destroy (void); + + ACE_Asynch_Read_Stream rs_; + ACE_Asynch_Write_Stream ws_; + ACE_HANDLE handle_; + ACE_Recursive_Thread_Mutex mutex_; + long io_count_; + static long sessions_; +}; + +long Receiver::sessions_ = 0; + +Receiver::Receiver (void) + : handle_ (ACE_INVALID_HANDLE), + io_count_ (0) +{ + ACE_Guard<ACE_Recursive_Thread_Mutex> locker (mutex_); + sessions_++; + ACE_DEBUG ((LM_DEBUG, "Receiver Ctor sessions_=%d\n", sessions_)); +} + +Receiver::~Receiver (void) +{ + ACE_Guard<ACE_Recursive_Thread_Mutex> locker (mutex_); + sessions_--; + ACE_OS::closesocket (this->handle_); + ACE_DEBUG ((LM_DEBUG, "~Receiver Dtor sessions_=%d\n", sessions_)); +} + +// return true if we alive, false we commited suicide +int +Receiver::check_destroy (void) +{ + { + ACE_Guard<ACE_Recursive_Thread_Mutex> locker (mutex_); + + if (io_count_ > 0) + return 1; + } + + delete this; + return 0; +} + +void +Receiver::open (ACE_HANDLE handle, + ACE_Message_Block &) +{ + ACE_DEBUG ((LM_DEBUG, + "%N:%l:Receiver::open called\n")); + + this->handle_ = handle; + + if (this->ws_.open (*this, this->handle_) == -1) + ACE_ERROR ((LM_ERROR, + "%p\n", + "ACE_Asynch_Write_Stream::open")); + else if (this->rs_.open (*this, this->handle_) == -1) + ACE_ERROR ((LM_ERROR, + "%p\n", + "ACE_Asynch_Read_Stream::open")); + else + initiate_read_stream (); + + check_destroy (); +} + +int +Receiver::initiate_read_stream (void) +{ + ACE_Guard<ACE_Recursive_Thread_Mutex> locker (mutex_); + + ACE_Message_Block *mb = 0; + ACE_NEW_RETURN (mb, + ACE_Message_Block (BUFSIZ + 1), + -1); + + // Inititiate read + if (this->rs_.read (*mb, mb->size ()- 1) == -1) + { + mb->release (); + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "ACE_Asynch_Read_Stream::read"), + -1); + } + + io_count_++; + return 0; +} + +int +Receiver::initiate_write_stream (ACE_Message_Block &mb, int nbytes) +{ + ACE_Guard<ACE_Recursive_Thread_Mutex> locker (mutex_); + if (nbytes <= 0) + { + mb.release (); + ACE_ERROR_RETURN((LM_ERROR, + "ACE_Asynch_Write_Stream::write nbytes <0 "), + -1); + } + + if (this->ws_.write (mb, nbytes) == -1) + { + mb.release (); + ACE_ERROR_RETURN((LM_ERROR, + "%p\n", + "ACE_Asynch_Write_Stream::write"), + -1); + } + + io_count_++; + return 0; +} + +void +Receiver::handle_read_stream (const ACE_Asynch_Read_Stream::Result &result) +{ + // Reset pointers. + result.message_block ().rd_ptr ()[result.bytes_transferred ()] = '\0'; + + if (result.bytes_transferred () == 0 || result.error () != 0) + { + ACE_DEBUG ((LM_DEBUG, "handle_read_stream called\n")); + ACE_DEBUG ((LM_DEBUG, "********************\n")); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "bytes_to_read", result.bytes_to_read ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "handle", result.handle ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "bytes_transfered", result.bytes_transferred ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "act", (u_long) result.act ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "success", result.success ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "completion_key", (u_long) result.completion_key ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "error", result.error ())); + ACE_DEBUG ((LM_DEBUG, "********************\n")); + ACE_DEBUG ((LM_DEBUG, "%s = %s\n", "message_block", result.message_block ().rd_ptr ())); + } + + if (result.success () && result.bytes_transferred () != 0) + { + // Successful read: write the data to the file asynchronously. + // Note how we reuse the <ACE_Message_Block> for the writing. + // Therefore, we do not delete this buffer because it is handled + // in <handle_write_stream>. + + if(this->initiate_write_stream (result.message_block (), + result.bytes_transferred ()) == 0) + { + if (duplex != 0) + { + // Initiate new read from the stream. + this->initiate_read_stream (); + } + } + } + else + { + result.message_block ().release (); + ACE_DEBUG ((LM_DEBUG, "Receiver completed\n")); + } + + { + ACE_Guard<ACE_Recursive_Thread_Mutex> locker (mutex_); + io_count_--; + } + check_destroy (); +} + +void +Receiver::handle_write_stream (const ACE_Asynch_Write_Stream::Result &result) +{ + if (result.bytes_transferred () == 0 || result.error () != 0) + { + ACE_DEBUG ((LM_DEBUG, "handle_write_stream called\n")); + + ACE_DEBUG ((LM_DEBUG, "********************\n")); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "bytes_to_write", result.bytes_to_write ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "handle", result.handle ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "bytes_transfered", result.bytes_transferred ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "act", (u_long) result.act ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "success", result.success ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "completion_key", (u_long) result.completion_key ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "error", result.error ())); + ACE_DEBUG ((LM_DEBUG, "********************\n")); + } + + result.message_block ().release (); + + if (result.success () && result.bytes_transferred () != 0) + { + // This code is not robust enough to deal with short file writes + // (which hardly ever happen);-) + // ACE_ASSERT (result.bytes_to_write () == result.bytes_transferred ()); + + if (duplex == 0) + initiate_read_stream (); + } + + { + ACE_Guard<ACE_Recursive_Thread_Mutex> locker (mutex_); + io_count_--; + } + check_destroy (); +} + +class Sender : public ACE_Handler +{ + // = TITLE + // Sends welcome messages receives them back. +public: + Sender (void); + ~Sender (void); + int open (const ACE_TCHAR *host, u_short port); + void close (void); + ACE_HANDLE handle (void) const; + +protected: + // These methods are called by the freamwork + + virtual void handle_read_stream (const ACE_Asynch_Read_Stream::Result &result); + // This is called when asynchronous reads from the socket complete + + virtual void handle_write_stream (const ACE_Asynch_Write_Stream::Result &result); + // This is called when asynchronous writes from the socket complete + +private: + + int initiate_read_stream (void); + int initiate_write_stream (void); + + ACE_SOCK_Stream stream_; + // Network I/O handle + + ACE_Asynch_Write_Stream ws_; + // ws (write stream): for writing to the socket + + ACE_Asynch_Read_Stream rs_; + // rs (read file): for reading from the socket + + ACE_Message_Block welcome_message_; + // Welcome message + + ACE_Recursive_Thread_Mutex mutex_; + long io_count_; +}; + +static char *data = "Welcome to Irfan World! Irfan RULES here !!\n"; + +Sender::Sender (void) + : io_count_ (0) +{ + // Moment of inspiration... :-) + this->welcome_message_.init (data, ACE_OS::strlen (data)); +} + +Sender::~Sender (void) +{ + close (); +} + +void Sender::close (void) +{ + this->stream_.close (); +} + +ACE_HANDLE Sender::handle (void) const +{ + return this->stream_.get_handle (); +} + +int Sender::open (const ACE_TCHAR *host, u_short port) +{ + // Initialize stuff + // Connect to remote host + ACE_INET_Addr address (port, host); + ACE_SOCK_Connector connector; + + if (connector.connect (this->stream_, + address) == -1) + { + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "ACE_SOCK_Connector::connect"), + -1); + } + + // Open ACE_Asynch_Write_Stream + if (this->ws_.open (*this) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "ACE_Asynch_Write_Stream::open"), + -1); + + // Open ACE_Asynch_Read_Stream + if (this->rs_.open (*this) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "ACE_Asynch_Read_Stream::open"), + -1); + + // Start an asynchronous transmit file + if (this->initiate_write_stream () == -1) + return -1; + + if (duplex != 0) + // Start an asynchronous read file + if (this->initiate_read_stream () == -1) + return -1; + + return 0; +} + +int +Sender::initiate_write_stream (void) +{ + ACE_Guard<ACE_Recursive_Thread_Mutex> locker (mutex_); + + welcome_message_.rd_ptr(welcome_message_.base ()); + welcome_message_.wr_ptr(welcome_message_.base ()); + welcome_message_.wr_ptr (ACE_OS::strlen (data)); + + if (this->ws_.write (welcome_message_, + welcome_message_.length ()) == -1) + ACE_ERROR_RETURN((LM_ERROR, + "%p\n", + "ACE_Asynch_Write_Stream::write"), + -1); + io_count_++; + return 0; +} + +int +Sender::initiate_read_stream (void) +{ + ACE_Guard<ACE_Recursive_Thread_Mutex> locker (mutex_); + + // Create a new <Message_Block>. Note that this message block will + // be used both to <read> data asynchronously from the socket and to + // <write> data asynchronously to the file. + ACE_DEBUG ((LM_DEBUG, + "initiate_read_stream called\n")); + + ACE_Message_Block *mb = 0; + ACE_NEW_RETURN (mb, + ACE_Message_Block (BUFSIZ + 1), + -1); + + // Inititiate read + if (this->rs_.read (*mb, mb->size ()- 1) == -1) + { + mb->release (); + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "ACE_Asynch_Read_Stream::read"), + -1); + } + + io_count_++; + return 0; +} + +void +Sender::handle_write_stream (const ACE_Asynch_Write_Stream::Result &result) +{ + if (result.bytes_transferred () == 0 || result.error () != 0) + { + ACE_DEBUG ((LM_DEBUG, "handle_write_stream called\n")); + + // Reset pointers. + result.message_block ().rd_ptr (result.message_block ().rd_ptr () - result.bytes_transferred ()); + + ACE_DEBUG ((LM_DEBUG, "********************\n")); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "bytes_to_write", result.bytes_to_write ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "handle", result.handle ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "bytes_transfered", result.bytes_transferred ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "act", (u_long) result.act ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "success", result.success ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "completion_key", (u_long) result.completion_key ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "error", result.error ())); + ACE_DEBUG ((LM_DEBUG, "********************\n")); + ACE_DEBUG ((LM_DEBUG, "%s = %s\n", "message_block", result.message_block ().rd_ptr ())); + } + + // Simplify just for Test + if (result.success () && result.bytes_transferred () != 0) + { + if (duplex != 0) // full duplex, continue write + initiate_write_stream (); + else // half-duplex read reply, after read we will start write + initiate_read_stream (); + } + + { + ACE_Guard<ACE_Recursive_Thread_Mutex> locker (mutex_); + io_count_--; + } +} + +void +Sender::handle_read_stream (const ACE_Asynch_Read_Stream::Result &result) +{ + if (result.bytes_transferred () == 0 || result.error () != 0) + { + ACE_DEBUG ((LM_DEBUG, + "handle_read_stream called\n")); + + // Reset pointers. + result.message_block ().rd_ptr ()[result.bytes_transferred ()] = '\0'; + + ACE_DEBUG ((LM_DEBUG, "********************\n")); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "bytes_to_read", result.bytes_to_read ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "handle", result.handle ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "bytes_transfered", result.bytes_transferred ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "act", (u_long) result.act ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "success", result.success ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "completion_key", (u_long) result.completion_key ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "error", result.error ())); + ACE_DEBUG ((LM_DEBUG, "********************\n")); + ACE_DEBUG ((LM_DEBUG, "%s = %s\n", "message_block", result.message_block ().rd_ptr ())); + } + + result.message_block().release (); + + if (result.success () && result.bytes_transferred () != 0) + { + // Successful read: write the data to the file asynchronously. + // Note how we reuse the <ACE_Message_Block> for the writing. + // Therefore, we do not delete this buffer because it is handled + // in <handle_write_stream>. + + if (duplex != 0) // full duplex, continue read + initiate_read_stream (); + else // half-duplex writey, after write we will start read + initiate_write_stream (); + } + + { + ACE_Guard<ACE_Recursive_Thread_Mutex> locker (mutex_); + io_count_--; + } +} + +static int +set_proactor_type (const char *ptype) +{ + if (!ptype) + return false; + + switch (toupper (*ptype)) + { + case 'D' : proactor_type = 0; return true; + case 'A' : proactor_type = 1; return true; + case 'I' : proactor_type = 2; return true; +#if defined (sun) + case 'S' : proactor_type = 3; return true; +#endif /* sun */ + } + return false; +} + +static int +parse_args (int argc, ACE_TCHAR *argv[]) +{ + ACE_Get_Opt get_opt (argc, argv, ACE_TEXT("t:o:n:p:d:h:s:u")); + int c; + + while ((c = get_opt ()) != EOF) + switch (c) + { + case 'd': // duplex + duplex = ACE_OS::atoi (get_opt.opt_arg ()); + break; + case 'h': // host for sender + host = get_opt.opt_arg (); + break; + case 'p': // port number + port = ACE_OS::atoi (get_opt.opt_arg ()); + break; + case 'n': // thread pool size + threads = ACE_OS::atoi (get_opt.opt_arg ()); + break; + case 's': // number of senders + senders = ACE_OS::atoi (get_opt.opt_arg ()); + if (senders > MaxSenders) + senders = MaxSenders; + break; + case 'o': // max number of aio for proactor + max_aio_operations = ACE_OS::atoi (get_opt.opt_arg ()); + break; + case 't': // Proactor Type + if (set_proactor_type (get_opt.opt_arg ())) + break; + case 'u': + default: + ACE_ERROR ((LM_ERROR, "%p.", + "\nusage:" + "\n-o <max number of started aio operations for Proactor>" + "\n-t <Proactor type> UNIX-only, Win32-default always:" + "\n a AIOCB" + "\n i SIG" + "\n s SUN" + "\n d default" + "\n-d <duplex mode 1-on/0-off>" + "\n-h <host> for Sender mode" + "\n-n <number threads for Proactor pool>" + "\n-p <port to listen/connect>" + "\n-s <number of sender's instances>" + "\n-u show this message" + "\n")); + + return -1; + } + + return 0; +} + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ +#if defined (sun) + ACE_DEBUG ((LM_DEBUG, "\nSUN defined!\n")); +#endif + if (parse_args (argc, argv) == -1) + return -1; + + disable_signal (ACE_SIGRTMIN, ACE_SIGRTMAX); + + MyTask task1; + + if (task1.activate (THR_NEW_LWP, threads) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p.\n", + "main"), + -1); + + // wait for creation of Proactor + task1.waitready (); + + Sender * send_list[MaxSenders]; + + ACE_Asynch_Acceptor<Receiver> acceptor; + + int rc = -1; + int i; + char c; + + if (host == 0) // Acceptor + { + // Simplify, initial read with zero size + if (acceptor.open (ACE_INET_Addr (port),0,1) == 0) + rc = 1; + } + else + { + for (i = 0; i < senders; ++i) + send_list[i] = new Sender; + + for (i = 0; i < senders; ++i) + if (send_list[i]->open (host, port) == 0) + rc++; + } + + if (rc > 0) + { + cout << "Press any key to stop=>" << flush; + cin.clear (); + cin >> c; + } + + ACE_Proactor::end_event_loop (); + + if (host != 0) // we are sender + { + for (i = 0; i < senders; ++i) + send_list[i]->close (); + } + + + ACE_Thread_Manager *tm = + ACE_Thread_Manager::instance(); + + tm->wait_task (&task1); + + cout << "\nNumber of Receivers objects=" + << Receiver::get_number_sessions () + << flush; + + for (i = 0; i < senders; ++i) + { + delete (send_list[i]); + send_list[i] = 0; + } + + return 0; +} + +static int +disable_signal (int sigmin, int sigmax) +{ +#ifndef ACE_WIN32 + + sigset_t signal_set; + if (sigemptyset (&signal_set) == - 1) + ACE_ERROR ((LM_ERROR, + "Error:(%P | %t):%p\n", + "sigemptyset failed")); + + for (int i = sigmin; i <= sigmax; i++) + sigaddset (&signal_set, i); + + // Put the <signal_set>. + if (ACE_OS::pthread_sigmask (SIG_BLOCK, &signal_set, 0) != 0) + ACE_ERROR ((LM_ERROR, + "Error:(%P | %t):%p\n", + "pthread_sigmask failed")); +#endif /* ACE_WIN32 */ + + return 1; +} + +// Get the <signal_set> back from the OS. + +#if 0 +static int +print_sigmask (void) +{ +#ifndef ACE_WIN32 + sigset_t mask; + int member = 0; + + COUT ("\n=============Signal Mask==========") + + if (ACE_OS::pthread_sigmask (SIG_SETMASK, 0, & mask) != 0) + ACE_ERROR ((LM_ERROR, + "Error:(%P | %t):%p\n", + "ACE_OS::pthread_sigmask failed")); + else + for (int i = 1; i < 1000; i++) + { + member = sigismember (&mask,i); + + COUT ("\nSig ") + COUT (i) + COUT (" is ") + COUT (member) + + if (member == -1) + break; + } + +#endif /* ACE_WIN32 */ + return 0; +} +#endif /* 0 */ + +#endif /* ACE_WIN32 && !ACE_HAS_WINCE || ACE_HAS_AIO_CALLS*/ diff --git a/ACE/examples/Reactor/Proactor/test_timeout.cpp b/ACE/examples/Reactor/Proactor/test_timeout.cpp new file mode 100644 index 00000000000..39351717db9 --- /dev/null +++ b/ACE/examples/Reactor/Proactor/test_timeout.cpp @@ -0,0 +1,130 @@ +// $Id: test_timeout.cpp + +// ============================================================================ +// +// = LIBRARY +// examples +// +// = FILENAME +// test_timeout.cpp +// +// = DESCRIPTION +// +// This example application shows how to write event loops that +// handle events for some fixed amount of time. Note that any +// thread in the Proactor thread pool can call back the handler. On +// POSIX4 systems, this test works only with POSIX_SIG_Proactor, +// which can work with multiple threads. +// +// = AUTHOR +// Irfan Pyarali and Alexander Babu Arulanthu +// +// ============================================================================ + +#include "ace/Proactor.h" +#include "ace/Task.h" +#include "ace/Atomic_Op.h" +#include "ace/OS_NS_sys_time.h" +#include "ace/OS_NS_unistd.h" +#include "ace/OS_main.h" + +ACE_RCSID(Proactor, test_timeout, "$Id$") + +#if ((defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)) || \ + (defined (ACE_HAS_AIO_CALLS)) && !defined (ACE_POSIX_AIOCB_PROACTOR)) + // This only works on Win32 platforms and on Unix platforms supporting + // POSIX aio calls. + +class Timeout_Handler : public ACE_Handler +{ + // = TITLE + // Generic timeout handler. +public: + Timeout_Handler (void) + : start_time_ (ACE_OS::gettimeofday ()) + { + } + + virtual void handle_time_out (const ACE_Time_Value &tv, + const void *arg) + { + // Print out when timeouts occur. + ACE_DEBUG ((LM_DEBUG, "(%t) %d timeout occurred for %s @ %d.\n", + ++count_, + (char *) arg, + (tv - this->start_time_).sec ())); + + // Sleep for a while + ACE_OS::sleep (4); + } + +private: + ACE_Atomic_Op <ACE_SYNCH_MUTEX, int> count_; + // Number of the timer event. + + ACE_Time_Value start_time_; + // Starting time of the test. +}; + +class Worker : public ACE_Task <ACE_NULL_SYNCH> +{ +public: + int svc (void) + { + // Handle events for 13 seconds. + ACE_Time_Value run_time (13); + + ACE_DEBUG ((LM_DEBUG, "(%t):Starting svc routine\n")); + + if (ACE_Proactor::run_event_loop(run_time) == -1) + ACE_ERROR_RETURN ((LM_ERROR, "(%t):%p.\n", "Worker::svc"), -1); + + ACE_DEBUG ((LM_DEBUG, "(%t) work complete\n")); + + return 0; + } +}; + +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + Timeout_Handler handler; + + // Register a 2 second timer. + ACE_Time_Value foo_tv (2); + if (ACE_Proactor::instance ()->schedule_timer (handler, + (void *) "Foo", + ACE_Time_Value::zero, + foo_tv) == -1) + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "schedule_timer"), -1); + + // Register a 3 second timer. + ACE_Time_Value bar_tv (3); + if (ACE_Proactor::instance ()->schedule_timer (handler, + (void *) "Bar", + ACE_Time_Value::zero, + bar_tv) == -1) + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "schedule_timer"), -1); + + Worker worker; + + if (worker.activate (THR_NEW_LWP, 10) == -1) + ACE_ERROR_RETURN ((LM_ERROR, "%p.\n", "main"), -1); + + ACE_Thread_Manager::instance ()->wait (); + + return 0; +} + +#else /* ACE_WIN32 && !ACE_HAS_WINCE || ACE_HAS_AIO_CALLS && !ACE_POSIX_AIOCB_PROACTOR*/ + +int +main (int, char *[]) +{ + ACE_DEBUG ((LM_DEBUG, + "This example is multithreaded version of test_timeout_st.cpp\n" + "This doesnt work on this platform !!!\n")); + return 1; +} + +#endif /* ACE_WIN32 && !ACE_HAS_WINCE || ACE_HAS_AIO_CALLS && !ACE_POSIX_AIOCB_PROACTOR*/ diff --git a/ACE/examples/Reactor/Proactor/test_timeout_st.cpp b/ACE/examples/Reactor/Proactor/test_timeout_st.cpp new file mode 100644 index 00000000000..ae44c2ba1f4 --- /dev/null +++ b/ACE/examples/Reactor/Proactor/test_timeout_st.cpp @@ -0,0 +1,99 @@ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// examples +// +// = FILENAME +// test_timeout_st.cpp +// +// = DESCRIPTION +// +// This example application shows how to write event loops that +// handle events for some fixed amount of time. This is the single +// threaded version of the test_timeout.cpp application. +// +// = AUTHOR +// Irfan Pyarali and Alexander Babu Arulanthu +// +// ============================================================================ + +#include "ace/Proactor.h" +#include "ace/OS_main.h" + +ACE_RCSID(Proactor, test_timeout, "$Id$") + +#if ((defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)) || (defined (ACE_HAS_AIO_CALLS))) +// This only works on Win32 platforms and on Unix platforms supporting +// POSIX aio calls. + +class Timeout_Handler : public ACE_Handler +{ + // = TITLE + // Generic timeout handler. + +public: + Timeout_Handler (void) + : count_ (0), + start_time_ (ACE_OS::gettimeofday ()) + { + } + + virtual void handle_time_out (const ACE_Time_Value &tv, + const void *arg) + { + // Print out when timeouts occur. + ACE_DEBUG ((LM_DEBUG, "(%t) %d timeout occurred for %s @ %d.\n", + ++count_, + (char *) arg, + (tv - this->start_time_).sec ())); + } + +private: + int count_; + // Sequence number for the timeouts. + + ACE_Time_Value start_time_; + // Starting time of the test. +}; + + +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + Timeout_Handler handler; + + // Register a 2 second timer. + ACE_Time_Value foo_tv (2); + if (ACE_Proactor::instance ()->schedule_timer (handler, + (void *) "Foo", + ACE_Time_Value::zero, + foo_tv) == -1) + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "schedule_timer"), -1); + + // Register a 3 second timer. + ACE_Time_Value bar_tv (3); + if (ACE_Proactor::instance ()->schedule_timer (handler, + (void *) "Bar", + ACE_Time_Value::zero, + bar_tv) == -1) + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "schedule_timer"), -1); + + // Handle events for 13 seconds. + ACE_Time_Value run_time (13); + + ACE_DEBUG ((LM_DEBUG, "Starting event loop\n")); + + // Run the event loop. + if (ACE_Proactor::run_event_loop(run_time) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "(%t):%p.\n", "Worker::svc"), + 1); + + ACE_DEBUG ((LM_DEBUG, "Ending event loop\n")); + + return 0; +} + +#endif /* ACE_WIN32 && !ACE_HAS_WINCE || ACE_HAS_AIO_CALLS*/ diff --git a/ACE/examples/Reactor/Proactor/test_udp_proactor.cpp b/ACE/examples/Reactor/Proactor/test_udp_proactor.cpp new file mode 100644 index 00000000000..49d834a2884 --- /dev/null +++ b/ACE/examples/Reactor/Proactor/test_udp_proactor.cpp @@ -0,0 +1,432 @@ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// examples +// +// = FILENAME +// test_udp_proactor.cpp +// +// = DESCRIPTION +// This program illustrates how the <ACE_Proactor> can be used to +// implement an application that does asynchronous operations using +// datagrams. +// +// = AUTHOR +// Irfan Pyarali <irfan@cs.wustl.edu> and +// Roger Tragin <r.tragin@computer.org> +// +// ============================================================================ + +#include "ace/OS_NS_string.h" +#include "ace/OS_main.h" +#include "ace/Proactor.h" +#include "ace/Asynch_IO.h" +#include "ace/INET_Addr.h" +#include "ace/SOCK_Dgram.h" +#include "ace/Message_Block.h" +#include "ace/Get_Opt.h" +#include "ace/Log_Msg.h" + +ACE_RCSID(Proactor, test_udp_proactor, "test_proactor.cpp,v 1.29 2001/02/02 23:41:16 shuston Exp") + +#if defined (ACE_WIN32) && !defined (ACE_HAS_WINCE) || defined (ACE_HAS_AIO_CALLS) + // This only works on Win32 platforms. + +// Host that we're connecting to. +static ACE_TCHAR *host = 0; + +// Port that we're receiving connections on. +static u_short port = ACE_DEFAULT_SERVER_PORT; + +// Keep track of when we're done. +static int done = 0; + +class Receiver : public ACE_Service_Handler +{ + // = TITLE + // This class will receive data from + // the network connection and dump it to a file. +public: + // = Initialization and termination. + Receiver (void); + ~Receiver (void); + + int open_addr (const ACE_INET_Addr &localAddr); + +protected: + // These methods are called by the framework + + /// This method will be called when an asynchronous read completes on + /// a UDP socket. + virtual void handle_read_dgram (const ACE_Asynch_Read_Dgram::Result &result); + +private: + ACE_SOCK_Dgram sock_dgram_; + + ACE_Asynch_Read_Dgram rd_; + // rd (read dgram): for reading from a UDP socket. + const char* completion_key_; + const char* act_; +}; + +Receiver::Receiver (void) + : completion_key_ ("Receiver Completion Key"), + act_ ("Receiver ACT") +{ +} + +Receiver::~Receiver (void) +{ + sock_dgram_.close (); +} + +int +Receiver::open_addr (const ACE_INET_Addr &localAddr) +{ + ACE_DEBUG ((LM_DEBUG, + "%N:%l:Receiver::open_addr called\n")); + + // Create a local UDP socket to receive datagrams. + if (this->sock_dgram_.open (localAddr) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "ACE_SOCK_Dgram::open"), -1); + + // Initialize the asynchronous read. + if (this->rd_.open (*this, + this->sock_dgram_.get_handle (), + this->completion_key_, + ACE_Proactor::instance ()) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "ACE_Asynch_Read_Dgram::open"), -1); + + // Create a buffer to read into. We are using scatter/gather to + // read the message header and message body into 2 buffers + + // create a message block to read the message header + ACE_Message_Block* msg = 0; + ACE_NEW_RETURN (msg, ACE_Message_Block (1024), -1); + + // the next line sets the size of the header, even though we + // allocated a the message block of 1k, by setting the size to 20 + // bytes then the first 20 bytes of the reveived datagram will be + // put into this message block. + msg->size (20); // size of header to read is 20 bytes + + // create a message block to read the message body + ACE_Message_Block* body = 0; + ACE_NEW_RETURN (body, ACE_Message_Block (1024), -1); + // The message body will not exceed 1024 bytes, at least not in this test. + + // set body as the cont of msg. This associates the 2 message + // blocks so that a read will fill the first block (which is the + // header) up to size (), and use the cont () block for the rest of + // the data. You can chain up to IOV_MAX message block using this + // method. + msg->cont (body); + + // ok lets do the asynch read + size_t number_of_bytes_recvd = 0; + + int res = rd_.recv (msg, + number_of_bytes_recvd, + 0, + PF_INET, + this->act_); + switch (res) + { + case 0: + // this is a good error. The proactor will call our handler when the + // read has completed. + break; + case 1: + // actually read something, we will handle it in the handler callback + ACE_DEBUG ((LM_DEBUG, "********************\n")); + ACE_DEBUG ((LM_DEBUG, + "%s = %d\n", + "bytes recieved immediately", + number_of_bytes_recvd)); + ACE_DEBUG ((LM_DEBUG, "********************\n")); + res = 0; + break; + case -1: + // Something else went wrong. + ACE_ERROR ((LM_ERROR, + "%p\n", + "ACE_Asynch_Read_Dgram::recv")); + // the handler will not get called in this case so lets clean up our msg + msg->release (); + break; + default: + // Something undocumented really went wrong. + ACE_ERROR ((LM_ERROR, + "%p\n", + "ACE_Asynch_Read_Dgram::recv")); + msg->release (); + break; + } + + return res; +} + +void +Receiver::handle_read_dgram (const ACE_Asynch_Read_Dgram::Result &result) +{ + ACE_DEBUG ((LM_DEBUG, + "handle_read_dgram called\n")); + + ACE_DEBUG ((LM_DEBUG, "********************\n")); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "bytes_to_read", result.bytes_to_read ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "handle", result.handle ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "bytes_transfered", result.bytes_transferred ())); + ACE_INET_Addr peerAddr; + result.remote_address (peerAddr); + ACE_DEBUG ((LM_DEBUG, "%s = %s:%d\n", "peer_address", peerAddr.get_host_addr (), peerAddr.get_port_number ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "flags", result.flags ())); + ACE_DEBUG ((LM_DEBUG, "%s = %s\n", "act", result.act ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "success", result.success ())); + ACE_DEBUG ((LM_DEBUG, "%s = %s\n", "completion_key", result.completion_key ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "error", result.error ())); + ACE_DEBUG ((LM_DEBUG, "********************\n")); + + if (result.success () && result.bytes_transferred () != 0) + { + // loop through our message block and print out the contents + for (const ACE_Message_Block* msg = result.message_block (); msg != 0; msg = msg->cont ()) + { // use msg->length () to get the number of bytes written to the message + // block. + ACE_DEBUG ((LM_DEBUG, "Buf=[size=<%d>", msg->length ())); + for (u_long i = 0; i < msg->length (); ++i) + ACE_DEBUG ((LM_DEBUG, + "%c", (msg->rd_ptr ())[i])); + ACE_DEBUG ((LM_DEBUG, "]\n")); + } + } + + ACE_DEBUG ((LM_DEBUG, + "Receiver completed\n")); + + // No need for this message block anymore. + result.message_block ()->release (); + + // Note that we are done with the test. + done++; +} + +class Sender : public ACE_Handler +{ + // = TITLE + // The class will be created by <main>. +public: + Sender (void); + ~Sender (void); + int open (const ACE_TCHAR *host, u_short port); + +protected: + // These methods are called by the freamwork + + virtual void handle_write_dgram (const ACE_Asynch_Write_Dgram::Result &result); + // This is called when asynchronous writes from the dgram socket + // complete + +private: + + ACE_SOCK_Dgram sock_dgram_; + // Network I/O handle + + ACE_Asynch_Write_Dgram wd_; + // wd (write dgram): for writing to the socket + + const char* completion_key_; + const char* act_; +}; + +Sender::Sender (void) + : completion_key_ ("Sender completion key"), + act_ ("Sender ACT") +{ +} + +Sender::~Sender (void) +{ + this->sock_dgram_.close (); +} + +int +Sender::open (const ACE_TCHAR *host, + u_short port) +{ + // Initialize stuff + + if (this->sock_dgram_.open (ACE_INET_Addr::sap_any) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "ACE_SOCK_Dgram::open"), -1); + + // Initialize the asynchronous read. + if (this->wd_.open (*this, + this->sock_dgram_.get_handle (), + this->completion_key_, + ACE_Proactor::instance ()) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "ACE_Asynch_Write_Dgram::open"), -1); + + // We are using scatter/gather to send the message header and + // message body using 2 buffers + + // create a message block for the message header + ACE_Message_Block* msg = 0; + ACE_NEW_RETURN (msg, ACE_Message_Block (100), -1); + const char raw_msg [] = "To be or not to be."; + // Copy buf into the Message_Block and update the wr_ptr (). + msg->copy (raw_msg, ACE_OS::strlen (raw_msg) + 1); + + // create a message block for the message body + ACE_Message_Block* body = 0; + ACE_NEW_RETURN (body, ACE_Message_Block (100), -1); + ACE_OS::memset (body->wr_ptr (), 'X', 100); + body->wr_ptr (100); // always remember to update the wr_ptr () + + // set body as the cont of msg. This associates the 2 message blocks so + // that a send will send the first block (which is the header) up to + // length (), and use the cont () to get the next block to send. You can + // chain up to IOV_MAX message block using this method. + msg->cont (body); + + // do the asynch send + size_t number_of_bytes_sent = 0; + ACE_INET_Addr serverAddr (port, host); + int res = this->wd_.send (msg, number_of_bytes_sent, 0, serverAddr, this->act_); + + switch (res) + { + case 0: + // this is a good error. The proactor will call our handler when the + // send has completed. + break; + case 1: + // actually sent something, we will handle it in the handler callback + ACE_DEBUG ((LM_DEBUG, "********************\n")); + ACE_DEBUG ((LM_DEBUG, + "%s = %d\n", + "bytes sent immediately", + number_of_bytes_sent)); + ACE_DEBUG ((LM_DEBUG, "********************\n")); + res = 0; + break; + case -1: + // Something else went wrong. + ACE_ERROR ((LM_ERROR, + "%p\n", + "ACE_Asynch_Write_Dgram::recv")); + // the handler will not get called in this case so lets clean up our msg + msg->release (); + break; + default: + // Something undocumented really went wrong. + ACE_ERROR ((LM_ERROR, + "%p\n", + "ACE_Asynch_Write_Dgram::recv")); + msg->release (); + break; + } + return res; +} + +void +Sender::handle_write_dgram (const ACE_Asynch_Write_Dgram::Result &result) +{ + ACE_DEBUG ((LM_DEBUG, + "handle_write_dgram called\n")); + + ACE_DEBUG ((LM_DEBUG, "********************\n")); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "bytes_to_write", result.bytes_to_write ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "handle", result.handle ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "bytes_transfered", result.bytes_transferred ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "flags", result.flags ())); + ACE_DEBUG ((LM_DEBUG, "%s = %s\n", "act", result.act ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "success", result.success ())); + ACE_DEBUG ((LM_DEBUG, "%s = %s\n", "completion_key", result.completion_key ())); + ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "error", result.error ())); + ACE_DEBUG ((LM_DEBUG, "********************\n")); + + + ACE_DEBUG ((LM_DEBUG, + "Sender completed\n")); + + // No need for this message block anymore. + result.message_block ()->release (); + + // Note that we are done with the test. + done++; +} + +static int +parse_args (int argc, ACE_TCHAR *argv[]) +{ + ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("h:p:")); + int c; + + while ((c = get_opt ()) != EOF) + switch (c) + { + case 'h': + host = get_opt.opt_arg (); + break; + case 'p': + port = ACE_OS::atoi (get_opt.opt_arg ()); + break; + default: + ACE_ERROR_RETURN ((LM_ERROR, "%p.\n", + "usage :\n" + "-h <host>\n"), -1); + } + + return 0; +} + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + if (parse_args (argc, argv) == -1) + return -1; + + Sender sender; + + Receiver receiver; + + // If passive side + if (host == 0) + { + if (receiver.open_addr (ACE_INET_Addr (port)) == -1) + return -1; + } + // If active side + else if (sender.open (host, port) == -1) + return -1; + + for (int success = 1; + success > 0 && !done; + ) + // Dispatch events via Proactor singleton. + success = ACE_Proactor::instance ()->handle_events (); + + return 0; +} + +#else /* ACE_WIN32 && !ACE_HAS_WINCE || ACE_HAS_AIO_CALLS*/ + +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_DEBUG ((LM_DEBUG, + "This example does not work on this platform.\n")); + return 1; +} + +#endif /* ACE_WIN32 && !ACE_HAS_WINCE || ACE_HAS_AIO_CALLS*/ + diff --git a/ACE/examples/Reactor/README b/ACE/examples/Reactor/README new file mode 100644 index 00000000000..fefaeeaf317 --- /dev/null +++ b/ACE/examples/Reactor/README @@ -0,0 +1,20 @@ +This directory contains subdirectories that test the ACE Reactor and Proactor + + . Dgram + Tests the CODgram and Dgram classes with the Reactor. + + . Misc + Various miscellaneous tests of Reactor functionality + (e.g., signals, timers, notification, etc.). + + . Multicast + Tests out the ACE multicast capabilities in conjunction + with the Reactor. + + . Ntalker + A program that implements a multicast "chat" program. + + + . Proactor + A program that illustrates the "Proactive" version of + the Reactor diff --git a/ACE/examples/Reactor/TP_Reactor/AcceptHandler.cpp b/ACE/examples/Reactor/TP_Reactor/AcceptHandler.cpp new file mode 100644 index 00000000000..7ae34d2b2b4 --- /dev/null +++ b/ACE/examples/Reactor/TP_Reactor/AcceptHandler.cpp @@ -0,0 +1,106 @@ +/* + * $Id$ + * + * ACE reactor demonstration + * + * Date: 26-Jan-2006 + */ + +#include <ace/Auto_Ptr.h> +#include <ace/INET_Addr.h> + +#include "common.h" +#include "AcceptHandler.h" +#include "ReadHandler.h" + +AcceptHandler:: AcceptHandler(ACE_Reactor *reactor) : + ACE_Event_Handler(), + mReactor(reactor == 0 ? ACE_Reactor::instance() : reactor), + mAcceptor() { + ACE_TRACE("AcceptHandler:: AcceptHandler(ACE_Reactor *)"); +} + +AcceptHandler::~AcceptHandler() { + ACE_TRACE("AcceptHandler::~AcceptHandler()"); +} + +int AcceptHandler::open(void) { + ACE_TRACE("AcceptHandler::open(void)"); + + // create the local address used for the service (PORT is from common.h) + ACE_INET_Addr addr(PORT); + + // open a port using the acceptor; reuse the address later + if (mAcceptor.open(addr, 1) == -1) + ACE_ERROR_RETURN((LM_ERROR, ACE_TEXT("%N:%l: Failed to open ") + ACE_TEXT ("listening socket. (errno = %i: %m)\n"), errno), -1); + + // register the handler with the reactor + if (mReactor->register_handler(this, + ACE_Event_Handler::ACCEPT_MASK) == -1) { + ACE_ERROR((LM_ERROR, ACE_TEXT("%N:%l: Failed to register accept ") + ACE_TEXT ("handler. (errno = %i: %m)\n"), errno)); + + // don't leave the acceptor open + if (mAcceptor.close() == -1) + ACE_ERROR((LM_ERROR, ACE_TEXT("%N:%l: Failed to close the socket ") + ACE_TEXT ("after previous error. (errno = %i: %m)\n"), + errno)); + return -1; + } + + return 0; +} + +ACE_HANDLE AcceptHandler::get_handle(void) const { + ACE_TRACE("AcceptHandler::get_handle(void)"); + return mAcceptor.get_handle(); +} + +int AcceptHandler::handle_input(ACE_HANDLE) { + ACE_TRACE("AcceptHandler::handle_input(ACE_HANDLE)"); + + ACE_INET_Addr clientAddr; + + // create a new ReadHandler + ReadHandler *reader = 0; + ACE_NEW_NORETURN (reader, ReadHandler()); + if (reader == 0) + ACE_ERROR_RETURN((LM_ERROR, ACE_TEXT("%N:%l: Failed to allocate ") + ACE_TEXT ("reader. (errno = %i: %m)\n"), errno), -1); + + // put reader in an auto pointer so we can use ACE_ERROR_RETURN safely + auto_ptr<ReadHandler> pReader(reader); + + // accept the connection using the reader's stream + if (mAcceptor.accept(reader->getStream(), &clientAddr) == -1) + ACE_ERROR_RETURN((LM_ERROR, ACE_TEXT("%N:%l: Failed to accept ") + ACE_TEXT ("client connection. (errno = %i: %m)\n"), errno), -1); + + // register the reader with the reactor + if (mReactor->register_handler(reader, + ACE_Event_Handler::READ_MASK) == -1) + ACE_ERROR_RETURN((LM_ERROR, ACE_TEXT("%N:%l: Failed to register ") + ACE_TEXT ("read handler. (errno = %i: %m)\n"), errno), -1); + + // from now on the read handler takes care of itself + pReader.release(); + + return 0; // keep going +} + +int AcceptHandler::handle_close(ACE_HANDLE, ACE_Reactor_Mask) { + ACE_TRACE("AcceptHandler::handle_close(ACE_HANDLE, ACE_Reactor_Mask)"); + + // close the listening socket + if (mAcceptor.close() == -1) + ACE_ERROR((LM_ERROR, ACE_TEXT("%N:%l: Failed to close the ") + ACE_TEXT ("socket. (errno = %i: %m)\n"), errno)); + + // no need to distinguish between error during close and normal close + // since ACE does not evaluate the return value of handle_close() + + delete this; + return 0; +} + diff --git a/ACE/examples/Reactor/TP_Reactor/AcceptHandler.h b/ACE/examples/Reactor/TP_Reactor/AcceptHandler.h new file mode 100644 index 00000000000..036f7a36f5a --- /dev/null +++ b/ACE/examples/Reactor/TP_Reactor/AcceptHandler.h @@ -0,0 +1,75 @@ +/* + * ACE reactor demonstration + * + * $Id$ + * Date: 26-Jan-2006 + */ + +#ifndef __ACCEPTHANDLER_H__ +#define __ACCEPTHANDLER_H__ + +#include <ace/Event_Handler.h> +#include <ace/Reactor.h> +#include <ace/SOCK_Acceptor.h> + +/** + * This accept handler is based on the provided solution from the ACE course. + */ +class AcceptHandler : public ACE_Event_Handler { + + private: + + /** + * The reactor to which the accept handler belongs. + */ + ACE_Reactor *mReactor; + + /** + * The socket used for incoming conections. + */ + ACE_SOCK_Acceptor mAcceptor; + + public: + + /** + * @param reactor The reactor which will use this accept handler. + */ + AcceptHandler(ACE_Reactor *reactor = 0); + + /** + * The destructor exists for tracing purposes. + */ + virtual ~AcceptHandler(); + + /** + * Open the listening socket and register the handler with the reactor. + * + * @return 0 on success, -1 on failure + */ + int open(void); + + /** + * @name Overridden methods from the ACE_Event_Handler + */ + // @{ + + /** + * Provides the handle of mAcceptor. + */ + virtual ACE_HANDLE get_handle(void) const; + + /** + * Create a read handler for the new connection and register that + * handler with the reactor. + */ + virtual int handle_input(ACE_HANDLE = ACE_INVALID_HANDLE); + + /** + * Close the listening socket. + */ + virtual int handle_close(ACE_HANDLE, ACE_Reactor_Mask); + // @} +}; + +#endif /* __ACCEPTHANDLER_H__ */ + diff --git a/ACE/examples/Reactor/TP_Reactor/Makefile.am b/ACE/examples/Reactor/TP_Reactor/Makefile.am new file mode 100644 index 00000000000..5407cbb10e1 --- /dev/null +++ b/ACE/examples/Reactor/TP_Reactor/Makefile.am @@ -0,0 +1,53 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +ACE_BUILDDIR = $(top_builddir) +ACE_ROOT = $(top_srcdir) + +## Makefile.TP_Reactor_Client.am +noinst_PROGRAMS = client + +client_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +client_SOURCES = \ + client.cpp \ + AcceptHandler.h \ + ReadHandler.h \ + common.h + +client_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.TP_Reactor_Server.am +noinst_PROGRAMS += server + +server_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +server_SOURCES = \ + AcceptHandler.cpp \ + ReadHandler.cpp \ + server.cpp \ + AcceptHandler.h \ + ReadHandler.h + +server_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Clean up template repositories, etc. +clean-local: + -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.* + -rm -f gcctemp.c gcctemp so_locations *.ics + -rm -rf cxx_repository ptrepository ti_files + -rm -rf templateregistry ir.out + -rm -rf ptrepository SunWS_cache Templates.DB diff --git a/ACE/examples/Reactor/TP_Reactor/README b/ACE/examples/Reactor/TP_Reactor/README new file mode 100644 index 00000000000..32fbc15aca9 --- /dev/null +++ b/ACE/examples/Reactor/TP_Reactor/README @@ -0,0 +1,86 @@ +ACE reactor demonstration +========================= + +Martin Kolleck +Tino Riethmuller + + + +1. Introduction + +This program demonstrates what we think is a bug in the ACE library. The +affected component is the ACE_TP_Reactor. According to the documentation, the +reactor ensures that only one of the handle_*() methods of an event handler is +called at a time. Tino found this to be not true and I wrote this example +program showing the behavior. I do not exclude the possibility that we are +using the ACE library in an unintended/wrong way. So comments on the code as +well as any other remarks are welcome. + + + +2. The program + +The program consists of a client and a server. The general implementation is +taken from the example solution to exercise 4c of the ACE course. The client +will send a request to the server. This request is interpreted to be the size +of the following data. The server allocates the memory required to hold the +client's data and then sends a confirmation to the client, that it may +proceed. The the client sends the large data chunk and the server again +confirms it. + +The client runs in a loop which can be configured to run indefinitely or a +previously set amount of times. The configuration i done from the command +line. To invoke the client type: + + $ ./client size [count] + +<size> sets the size (in MiB) of the buffer sent to the server. Depending on +the systems, values between 60 and 100 have been used for testing. <count> +determines how often the buffer is sent. If left out, the clients send the +buffer until interrupted. + +The server is started without arguments. Both programs will print a dot for +each successful connection. I found this an easy and unintrusive way of showing +progress whithout flooding the console too fast. This also makes it easier to +see when an error has occurred. + + + +3. Building the program + +This example was created on a Linux box. You will need the environment +variable ACE_ROOT set up to the location where ACE is installed. It might be +possible, that the path where the ACE libraries are found, needs to be adjusted +in the Makefile. + +To compile simply type 'make' on the command prompt. + + $ make + +This will create two executable files. One for the server and one for the +client. (named respectively) + + + +4. Running the program + +The error seems to be of statistical nature. Occurring only under certain +conditions (which I am not sure of, what they are). I successfully produced +the error on the four machines given below (architecture, ACE and compiler +version). I tested the program with localhost connections, as well as over +a real network connection and could always reproduce the error. + +To detect the error I introduced a member variable to the read event handler. +This counter is initialized to zero in the constructor. When handle_input() of +the event handler is called, the counter is increased and decreased, when +handle_input() returns. Before increasing the counter, It is compared to zero +(which it should alway be, if only one invocation to handle_input() is made +at a time) and an error message is printed if it is not zero. + +To test for the error, I ran one instance of the server program and TWO +instances of the client program. The sizes of the buffers were between 60 and +100 MiB and no count was given (running until stopped) The three Linux boxes +showed the error within one minute of starting both clients. For the Windows +box I decreased the buffer size to 15 and 20 MiB (Windows does not seem to have +very performant localhost connectivity) and it took about half an +hour until the error occurred the first time. diff --git a/ACE/examples/Reactor/TP_Reactor/ReadHandler.cpp b/ACE/examples/Reactor/TP_Reactor/ReadHandler.cpp new file mode 100644 index 00000000000..06c6c953046 --- /dev/null +++ b/ACE/examples/Reactor/TP_Reactor/ReadHandler.cpp @@ -0,0 +1,151 @@ +/* + * ACE reactor demonstration + * + * $Id$ + * Date: 26-Jan-2006 + */ + +#include <ace/streams.h> +#include <ace/Time_Value.h> + +#include "common.h" +#include "ReadHandler.h" + +/** + * This macro is used to increase the invocation counter by one when entering + * handle_input(). It also checks wether the counter is greater than zero + * indicating, that handle_input() has been called before. + */ +#define INVOCATION_ENTER() do { if (mInvocationCounter > 0) \ + ACE_ERROR((LM_ERROR, ACE_TEXT("Multiple invocations detected.\n"))); \ + mInvocationCounter++; } while (0) + +/** + * THis macro is the counter part to INVOCATION_ENTER(). It decreases the + * invocation counter and then returns the given value. This macro is + * here for convenience to decrease the invocation counter also when returning + * due to errors. + */ +#define INVOCATION_RETURN(retval) do { mInvocationCounter--; \ + return retval; } while(0) + +ReadHandler::ReadHandler() : ACE_Event_Handler(), mStream(), mDataSize(0), + mData(0), mCallCounter(0), mInvocationCounter(0) { + ACE_TRACE(ACE_TEXT("ReadHandler::ReadHandler()")); +} + +ReadHandler::~ReadHandler() { + ACE_TRACE(ACE_TEXT("ReadHandler::~ReadHandler()")); + + if (mStream.close() == -1) + ACE_ERROR((LM_ERROR, ACE_TEXT("%N:%l: Failed to close socket. ") + ACE_TEXT ("(errno = %i: %m)\n"), errno)); + + delete[] mData; +} + +ACE_SOCK_Stream &ReadHandler::getStream(void) { + ACE_TRACE(ACE_TEXT("ReadHandler::getStream(void)")); + return mStream; +} + +ACE_HANDLE ReadHandler::get_handle(void) const { + ACE_TRACE(ACE_TEXT("ReadHandler::get_handle(void)")); + return mStream.get_handle(); +} + +int ReadHandler::handle_input(ACE_HANDLE) { + ACE_TRACE(ACE_TEXT("ReadHandler::handle_input(ACE_HANDLE)")); + + INVOCATION_ENTER(); + + // the response sent to the client + char response = 0; + + if (mCallCounter == 0) { + + /* + * This is the first request from the client. + */ + + // increase the call counter so the next client request goes to else-if + mCallCounter++; + + // get the desired size from the client + // Note: only use the sizeof and pointer to int on compatible + // platforms (i.e. little-endian/big-endian, data type size) + if (mStream.recv_n(&mDataSize, sizeof(mDataSize), + &connTimeout) != sizeof(mDataSize)) { + ACE_ERROR((LM_ERROR, ACE_TEXT("%N:%l: Failed to receive ") + ACE_TEXT ("request. (errno = %i: %m)\n"), errno)); + INVOCATION_RETURN(-1); + } + + // The verbose debug output is replaced with some unintrusive dots. + // This increases visibility of the desired effect. + // ACE_DEBUG((LM_DEBUG, ACE_TEXT("%@: Data size: %i\n"), this, mDataSize)); + ACE_DEBUG((LM_DEBUG, ACE_TEXT("."))); + + // check mDataSize for plausability then allocate memory + if (mDataSize > 0) { + mData = new (std::nothrow) char[mDataSize]; + if (mData == 0) + ACE_DEBUG((LM_DEBUG, ACE_TEXT("%N:%l: Failed to allocate ") + ACE_TEXT ("data buffer.\n"))); + else + response = 'K'; + } + + // send the response to the client (which is still 0, if the + // allocation did not succeed) + if (mStream.send_n(&response, sizeof(response), &connTimeout) != 1) { + ACE_ERROR((LM_ERROR, ACE_TEXT("%N:%l: Failed to send ") + ACE_TEXT ("response. (errno = %i: %m)\n"), errno)); + INVOCATION_RETURN(-1); + } + + if (response == 'K') + INVOCATION_RETURN(0); // get another request from the same client + else + INVOCATION_RETURN(-1); // the client will not send data if response != 'K' + + } else if (mCallCounter == 1) { + + /* + * This is the second request from the client. + */ + + // increase the call counter, this read handler should not be called + // again + mCallCounter++; + + // receive the data from the client + if (mStream.recv_n(mData, mDataSize, &connTimeout) != mDataSize) { + ACE_ERROR((LM_ERROR, ACE_TEXT("%N:%l: Failed to receive data.") + ACE_TEXT ("(errno = %i: %m)\n"), errno)); + INVOCATION_RETURN(-1); + } + + response = 'K'; + + if (mStream.send_n(&response, 1, &connTimeout) != 1) { + ACE_ERROR((LM_ERROR, ACE_TEXT("%N:%l: Failed to send ") + ACE_TEXT ("confirmation. (errno = %i: %m)\n"), errno)); + INVOCATION_RETURN(-1); + } + + INVOCATION_RETURN(-1); // ask for removal, since client does not send any more data + } + + // this is to find strange actions with the call counter + ACE_ERROR((LM_ERROR, ACE_TEXT("%N:%l: We should not get here."))); + INVOCATION_RETURN(-1); +} + +int ReadHandler::handle_close(ACE_HANDLE, ACE_Reactor_Mask) { + ACE_TRACE("ReadHandler::handle_close(ACE_HANDLE, ACE_Reactor_Mask)"); + + delete this; + return 0; +} + diff --git a/ACE/examples/Reactor/TP_Reactor/ReadHandler.h b/ACE/examples/Reactor/TP_Reactor/ReadHandler.h new file mode 100644 index 00000000000..41d58b6008a --- /dev/null +++ b/ACE/examples/Reactor/TP_Reactor/ReadHandler.h @@ -0,0 +1,92 @@ +/* + * ACE reactor demonstration + * + * $Id$ + * Date: 26-Jan-2006 + */ + +#ifndef __READHANDLER_H__ +#define __READHANDLER_H__ + +#include <ace/Event_Handler.h> +#include <ace/SOCK_Stream.h> + +/** + * This read handler is created by the accept handler and handles all the data + * exchange between client and server. The client makes two requests to the + * server. The first asks the server to create a buffer which will hold the + * data sent in the second call. + */ +class ReadHandler : public ACE_Event_Handler { + + private: + + /** + * The stream socket used for data exchange. + */ + ACE_SOCK_Stream mStream; + + /** + * The size of the data array. + */ + int mDataSize; + + /** + * The array containing the client's data. + */ + char *mData; + + /** + * The call counter to distinguish between first and second call. + */ + int mCallCounter; + + /** + * Count the numer of invocations of handle_*(). According to the + * docs, there should be only one invocation at any given time. + */ + int mInvocationCounter; + + public: + + /** + * Initialization. + */ + ReadHandler(void); + + /** + * Clean up data. + */ + virtual ~ReadHandler(); + + /** + * Provide access to the internal stream socket. + */ + ACE_SOCK_Stream &getStream(void); + + /** + * @name Overridden methods from the ACE_Event_Handler + */ + // @{ + + /** + * Provides the handle of mStream; + */ + virtual ACE_HANDLE get_handle(void) const; + + /** + * Handles the data excahnge between client and server. On the first + * invocation, mData is allocated to the requested size and on the + * second invocation, that buffer is filled with the client's data. + */ + virtual int handle_input(ACE_HANDLE = ACE_INVALID_HANDLE); + + /** + * Deletes this instance of the read handler. + */ + virtual int handle_close(ACE_HANDLE, ACE_Reactor_Mask); + // @} +}; + +#endif /* __READHANDLER_H__ */ + diff --git a/ACE/examples/Reactor/TP_Reactor/TP_Reactor.mpc b/ACE/examples/Reactor/TP_Reactor/TP_Reactor.mpc new file mode 100644 index 00000000000..03d8de2e7aa --- /dev/null +++ b/ACE/examples/Reactor/TP_Reactor/TP_Reactor.mpc @@ -0,0 +1,18 @@ +// -*- MPC -*- +// $Id$ + +project (*client) : aceexe { + exename = client + Source_Files { + client.cpp + } +} + +project (*server) : aceexe { + exename = server + Source_Files { + server.cpp + AcceptHandler.cpp + ReadHandler.cpp + } +} diff --git a/ACE/examples/Reactor/TP_Reactor/client.cpp b/ACE/examples/Reactor/TP_Reactor/client.cpp new file mode 100644 index 00000000000..509f2e9c457 --- /dev/null +++ b/ACE/examples/Reactor/TP_Reactor/client.cpp @@ -0,0 +1,141 @@ +/* + * ACE reactor demonstration + * + * $Id$ + * Date: 26-Jan-2006 + */ + +#include <ace/Auto_Ptr.h> +#include <ace/INET_Addr.h> +#include <ace/Log_Msg.h> +#include <ace/OS.h> +#include <ace/SOCK_Acceptor.h> +#include <ace/SOCK_Connector.h> +#include <ace/SOCK_Stream.h> +#include <ace/streams.h> + +#include "common.h" + +/** + * Print usage information for the client. + * + * @param arg The progams name (argv[0]). + */ +int printUsage(ACE_TCHAR *arg) { + cerr << "Usage: " << arg << " size [count]" << endl; + cerr << "\tSends <size> MiB to the server and optionally repeats that " + << "<count> times." << endl; + cerr << "\tAll arguments must be positive numbers. If no <count> is " + << "given, the\n\tclient runs until interrupted." << endl; + return -1; +} + +int ACE_TMAIN(int argc, ACE_TCHAR **argv) { + + // size and count for transmissions + int size = 0, count = -1; + + // the server's answer is a single byte + char answer; + + // parse the <size> argument + if ((argc < 2) || (((size = ACE_OS::strtol(argv[1], 0, 10)) < 1) || + (errno == EINVAL))) + return printUsage(argv[0]); + + // take size as the number of MiB and create appropriate buffer + size *= BASE; + char *someData = new (std::nothrow) char[size]; + + if (someData == 0) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%N:%l: Failed to allocate ") + ACE_TEXT ("data buffer.\n")), -1); + + // put someData in an auto_ptr so it gets deleted automatically + auto_ptr<char> pSomeData(someData); + + // parse the <count> argument if available + if ((argc == 3) && (((count = ACE_OS::strtol(argv[2], 0, 10)) < 1) || + (errno == EINVAL))) + return printUsage(argv[0]); + + // the server listens on localhost on default port (from common.h) + ACE_INET_Addr serverAddr(PORT, "localhost"); + + ACE_SOCK_Stream stream; + ACE_SOCK_Connector connector; + + // -1 is running indefinitely + while ((count == -1) || (count-- != 0)) { + + // some output, that we know something is happening + //ACE_DEBUG((LM_DEBUG, ACE_TEXT("%N:%l: Passes left: %i\n"), count)); + ACE_DEBUG((LM_DEBUG, ACE_TEXT("."))); + + // connect to the server and get the stream + if (connector.connect(stream, serverAddr) == -1) { + ACE_ERROR((LM_ERROR, + ACE_TEXT("%N:%l: Failed to connect to ") + ACE_TEXT ("server. (errno = %i: %m)\n"), errno)); + break; + } + + try { + + // send the request to the server (number of MiB in the next call) + // Note: only use the sizeof and pointer to int on compatible + // platforms (i.e. little-endian/big-endian, data type size) + if (stream.send_n(&size, sizeof(size), &connTimeout) != sizeof(size)) { + ACE_ERROR((LM_ERROR, ACE_TEXT("%N:%l: Failed to send ") + ACE_TEXT ("request. (errno = %i: %m)\n"), errno)); + throw(1); + } + + // receive the answer + if (stream.recv_n(&answer, sizeof(answer), &connTimeout) != 1) { + ACE_ERROR((LM_ERROR, ACE_TEXT("%N: %l: Failed to receive ") + ACE_TEXT ("1st response. (errno = %i: %m)\n"), errno)); + throw(1); + } + + // server answer, 'K" indicates a positive answer + if (answer == 'K') { + + // send a huge message to the server + if (stream.send_n(someData, size, &connTimeout) != size) { + ACE_ERROR((LM_ERROR, ACE_TEXT("%N:%l: Failed to send ") + ACE_TEXT ("someData. (errno = %i: %m)\n"), errno)); + throw(1); + } + + // get an answer + if (stream.recv_n(&answer, sizeof(answer), &connTimeout) != 1) { + ACE_ERROR((LM_ERROR, ACE_TEXT("%N: %l: Failed to receive ") + ACE_TEXT ("2nd response. (errno = %i: %m)\n"), errno)); + throw(1); + } + + // check the answer + if (answer != 'K') { + cout << "The server was unable to process the data." + << endl; + } + } + } catch (...) { + // ok we know an error occurred, we need to close the socket. + // The we'll try again. + } + + // close the current stream + if (stream.close() == -1) { + ACE_ERROR((LM_ERROR, ACE_TEXT("%N:%l: Failed to close ") + ACE_TEXT ("socket. (errno = %i: %m)\n"), errno)); + break; + } + } // while + + cout << "Bye. Bye" << endl; + return 0; +} + diff --git a/ACE/examples/Reactor/TP_Reactor/common.h b/ACE/examples/Reactor/TP_Reactor/common.h new file mode 100644 index 00000000000..c9661027923 --- /dev/null +++ b/ACE/examples/Reactor/TP_Reactor/common.h @@ -0,0 +1,29 @@ +/* + * ACE reactor demonstration + * + * $Id$ + * Date: 26-Jan-2006 + */ + +#ifndef __COMMON_H__ +#define __COMMON_H__ + +#include <ace/Time_Value.h> + +/** + * The port number used by client and server. + */ +static const int PORT = 4711; + +/** + * The base size. 0x100000 = 1 MiB + */ +static const int BASE = 0x100000; + +/** + * The timeout value for connections. (30 seconds) + */ +static const ACE_Time_Value connTimeout(30); + +#endif /* __COMMON_H__ */ + diff --git a/ACE/examples/Reactor/TP_Reactor/run_test.pl b/ACE/examples/Reactor/TP_Reactor/run_test.pl new file mode 100644 index 00000000000..ac07295a735 --- /dev/null +++ b/ACE/examples/Reactor/TP_Reactor/run_test.pl @@ -0,0 +1,41 @@ +eval '(exit $?0)' && eval 'exec perl -S $0 ${1+"$@"}' + & eval 'exec perl -S $0 $argv:q' + if 0; + +# $Id$ +# -*- perl -*- + +use lib '../../../bin'; +use PerlACE::Run_Test; + +$status = 0; + +$SV = new PerlACE::Process ("server", ""); +$CL1 = new PerlACE::Process ("client", "80 100"); +$CL2 = new PerlACE::Process ("client", "80 100"); +$SV->Spawn (); + +sleep (1); + +$client1 = $CL1->Spawn (); + +if ($client1 != 0) { + print STDERR "ERROR: client 1 returned $client1\n"; + $status = 1; +} + +$client2 = $CL2->Spawn (); + +if ($client2 != 0) { + print STDERR "ERROR: client 2 returned $client2\n"; + $status = 1; +} + +$server = $SV->WaitKill (1000); + +if ($server != 0) { + print STDERR "ERROR: server returned $server\n"; + $status = 1; +} + +exit $status; diff --git a/ACE/examples/Reactor/TP_Reactor/server.cpp b/ACE/examples/Reactor/TP_Reactor/server.cpp new file mode 100644 index 00000000000..0c147818424 --- /dev/null +++ b/ACE/examples/Reactor/TP_Reactor/server.cpp @@ -0,0 +1,66 @@ +/* + * ACE reactor demonstration + * + * $Id$ + * Date: 26-Jan-2006 + */ + +#include <ace/Event_Handler.h> +#include <ace/Log_Msg.h> +#include <ace/OS.h> +#include <ace/Reactor.h> +#include <ace/Signal.h> +#include <ace/streams.h> +#include <ace/Thread_Manager.h> +#include <ace/TP_Reactor.h> + +#include "AcceptHandler.h" + +/** + * This is the function run by all threads in the thread pool. + * + * @param arg is expected to be of type (ACE_Reactor *) + */ +ACE_THR_FUNC_RETURN threadFunc(void *arg) { + ACE_TRACE("threadFunc(void *)"); + + ACE_Reactor *reactor = (ACE_Reactor *) arg; + reactor->run_reactor_event_loop(); + + return 0; +} + +/** + * The main function sets up the TP reactor. The code is basically taken from + * the solution to exercise 4c of the ACE course. + */ +int ACE_TMAIN(int, ACE_TCHAR **) { + + // create a reactor from a TP reactor + ACE_TP_Reactor tpReactor; + ACE_Reactor reactor(&tpReactor); + + // create a new accept handler using that reactor + AcceptHandler *acceptHandler = 0; + ACE_NEW_NORETURN (acceptHandler, AcceptHandler(&reactor)); + if (acceptHandler == 0) + ACE_ERROR_RETURN((LM_ERROR, ACE_TEXT("%N:%l: Failed to allocate ") + ACE_TEXT ("accept handler. (errno = %i: %m)\n"), errno), -1); + + // open the accept handler + if (acceptHandler->open() == -1) { + delete acceptHandler; + ACE_ERROR_RETURN((LM_ERROR, ACE_TEXT("%N:%l: Failed to open accept ") + ACE_TEXT ("handler. Exiting.\n")), -1); + } + + // spawn some threads which run the reactor event loop(s) + ACE_Thread_Manager::instance()->spawn_n(9, threadFunc, &reactor); + + // let the thread manager wait for all threads + ACE_Thread_Manager::instance()->wait(); + + ACE_DEBUG((LM_DEBUG, ACE_TEXT("Bye. Bye.\n"))); + return 0; +} + diff --git a/ACE/examples/Reactor/WFMO_Reactor/APC.cpp b/ACE/examples/Reactor/WFMO_Reactor/APC.cpp new file mode 100644 index 00000000000..bf42fd1edfa --- /dev/null +++ b/ACE/examples/Reactor/WFMO_Reactor/APC.cpp @@ -0,0 +1,124 @@ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// examples +// +// = FILENAME +// APC.cpp +// +// = DESCRIPTION +// +// Tests the WFMO_Reactor's ability to handle regular APC +// notifications. +// +// = AUTHOR +// +// Irfan Pyarali <irfan@cs.wustl.edu> +// +// ============================================================================ + +#include "ace/OS_main.h" + +#if defined (ACE_WIN32) + +#include "ace/Reactor.h" +#include "ace/Auto_Event.h" + +ACE_RCSID(WFMO_Reactor, APC, "$Id$") + +class Event_Handler : public ACE_Event_Handler +{ +public: + int handle_signal (int signum, + siginfo_t * = 0, + ucontext_t * = 0); + + int handle_timeout (const ACE_Time_Value &tv, + const void *arg = 0); + + ACE_Auto_Event handle_; + int iterations_; +}; + +static Event_Handler *global_event_handler; + +static void WINAPI +apc_callback (DWORD) +{ + ACE_DEBUG ((LM_DEBUG, + "(%t) apc occured @ %T\n")); + + global_event_handler->handle_.signal (); +} + +void +queue_apc (void) +{ + DWORD result = ::QueueUserAPC (reinterpret_cast<PAPCFUNC> (&apc_callback), + // pointer to APC function + ::GetCurrentThread (), // handle to the thread + 0); // argument for the APC function + if (result == FALSE) + ACE_OS::exit (-1); +} + +int +Event_Handler::handle_signal (int, + siginfo_t *, + ucontext_t *) +{ + --this->iterations_; + + if (this->iterations_ == 0) + { + ACE_Reactor::instance ()->remove_handler (this->handle_.handle (), + ACE_Event_Handler::DONT_CALL); + ACE_Reactor::end_event_loop (); + } + + return 0; +} + +int +Event_Handler::handle_timeout (const ACE_Time_Value &, + const void *) +{ + ACE_DEBUG ((LM_DEBUG, + "(%t) timeout occured @ %T\n")); + queue_apc (); + return 0; +} + +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + Event_Handler event_handler; + event_handler.iterations_ = 5; + global_event_handler = &event_handler; + + int result = ACE_Reactor::instance ()->register_handler (&event_handler, + event_handler.handle_.handle ()); + ACE_ASSERT (result == 0); + + ACE_Time_Value timeout (2); + result = ACE_Reactor::instance ()->schedule_timer (&event_handler, + 0, + timeout, + timeout); + ACE_ASSERT (result != -1); + + ACE_Reactor::run_alertable_event_loop (); + + ACE_Reactor::instance ()->cancel_timer(&event_handler); + + return 0; +} +#else /* !ACE_WIN32 */ +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + return 0; +} +#endif /* ACE_WIN32 */ diff --git a/ACE/examples/Reactor/WFMO_Reactor/Abandoned.cpp b/ACE/examples/Reactor/WFMO_Reactor/Abandoned.cpp new file mode 100644 index 00000000000..c860fc2810c --- /dev/null +++ b/ACE/examples/Reactor/WFMO_Reactor/Abandoned.cpp @@ -0,0 +1,141 @@ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// examples +// +// = FILENAME +// Abandoned.cpp +// +// = DESCRIPTION +// +// Tests the WFMO_Reactor's ability to handle abandoned mutexes. +// +// = AUTHOR +// +// Irfan Pyarali <irfan@cs.wustl.edu> +// +// ============================================================================ + +#include "ace/OS_main.h" + +#if defined (ACE_WIN32) + +#include "ace/Reactor.h" +#include "ace/Thread_Manager.h" +#include "ace/Process_Mutex.h" +#include "ace/Auto_Event.h" + +ACE_RCSID(WFMO_Reactor, Abandoned, "$Id$") + +class Event_Handler : public ACE_Event_Handler +{ +public: + int handle_signal (int signum, + siginfo_t * = 0, + ucontext_t * = 0); + + int handle_timeout (const ACE_Time_Value &tv, + const void *arg = 0); + + ACE_Auto_Event handle_; + ACE_Process_Mutex *mutex_; + int iterations_; +}; + +static int abandon = 1; + +static ACE_THR_FUNC_RETURN +worker (void *data) +{ + Event_Handler *handler = (Event_Handler *) data; + + handler->handle_.signal (); + handler->mutex_->acquire (); + + if (!abandon) + handler->mutex_->release (); + + return 0; +} + +int +Event_Handler::handle_signal (int, + siginfo_t *s, + ucontext_t *) +{ + ACE_HANDLE handle = s->si_handle_; + if (handle == this->handle_.handle ()) + ACE_Reactor::instance ()->register_handler (this, + this->mutex_->lock ().proc_mutex_); + else + { + ACE_Reactor::instance ()->remove_handler (this->mutex_->lock ().proc_mutex_, + ACE_Event_Handler::DONT_CALL); + delete this->mutex_; + } + + return 0; +} + +int +Event_Handler::handle_timeout (const ACE_Time_Value &, + const void *) +{ + --this->iterations_; + ACE_DEBUG ((LM_DEBUG, + "(%t) timeout occured @ %T, iterations left %d\n", + this->iterations_)); + + if (this->iterations_ == 0) + { + ACE_Reactor::instance ()->remove_handler (this->handle_.handle (), + ACE_Event_Handler::DONT_CALL); + + ACE_Reactor::instance ()->cancel_timer (this); + + ACE_Reactor::end_event_loop (); + } + else + { + ACE_NEW_RETURN (this->mutex_, + ACE_Process_Mutex, + -1); + int result = ACE_Thread_Manager::instance ()->spawn (&worker, this); + ACE_ASSERT (result != -1); + ACE_UNUSED_ARG (result); + } + + return 0; +} + +int +ACE_TMAIN (int , ACE_TCHAR *[]) +{ + Event_Handler event_handler; + + event_handler.iterations_ = 5; + int result = ACE_Reactor::instance ()->register_handler + (&event_handler, + event_handler.handle_.handle ()); + ACE_ASSERT (result == 0); + + ACE_Time_Value timeout (2); + result = ACE_Reactor::instance ()->schedule_timer (&event_handler, + 0, + timeout, + timeout); + ACE_ASSERT (result != -1); + + ACE_Reactor::run_event_loop (); + + return 0; +} +#else /* !ACE_WIN32 */ +int +ACE_TMAIN (int , ACE_TCHAR *[]) +{ + return 0; +} +#endif /* ACE_WIN32 */ diff --git a/ACE/examples/Reactor/WFMO_Reactor/Console_Input.cpp b/ACE/examples/Reactor/WFMO_Reactor/Console_Input.cpp new file mode 100644 index 00000000000..363a6a8ead8 --- /dev/null +++ b/ACE/examples/Reactor/WFMO_Reactor/Console_Input.cpp @@ -0,0 +1,87 @@ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// examples +// +// = FILENAME +// Console_Input.cpp +// +// = DESCRIPTION +// +// This application tests the working of WFMO_Reactor when users +// are interested in console input. +// +// = AUTHOR +// Irfan Pyarali <irfan@cs.wustl.edu> +// +// ============================================================================ + +#include "ace/Reactor.h" +#include "ace/OS_NS_unistd.h" +#include "ace/OS_NS_string.h" +#include "ace/OS_main.h" + +ACE_RCSID(WFMO_Reactor, Console_Input, "$Id$") + +class Event_Handler : public ACE_Event_Handler +{ +public: + Event_Handler (ACE_Reactor &reactor); + int handle_signal (int signum, siginfo_t * = 0, ucontext_t * = 0); + int handle_close (ACE_HANDLE handle, + ACE_Reactor_Mask close_mask); +}; + +Event_Handler::Event_Handler (ACE_Reactor &reactor) +{ + this->reactor (&reactor); + + if (this->reactor ()->register_handler (this, + ACE_STDIN) != 0) + ACE_ERROR ((LM_ERROR, + "Registration with Reactor could not be done\n")); +} + +int +Event_Handler::handle_signal (int, siginfo_t *, ucontext_t *) +{ + ACE_TCHAR buffer[BUFSIZ]; + int result = ACE_OS::read (ACE_STDIN, buffer, sizeof buffer); + buffer[result] = '\0'; + + if (result <= 0) + { + this->reactor ()->close (); + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "ACE_OS::read"), -1); + } + + if (ACE_OS::strcmp (ACE_TEXT("quit\r\n"), buffer) == 0) + this->reactor ()->close (); + + ACE_DEBUG ((LM_DEBUG, "User input: %s", buffer)); + + return 0; +} + +int +Event_Handler::handle_close (ACE_HANDLE, + ACE_Reactor_Mask) +{ + ACE_DEBUG ((LM_DEBUG, "Event_Handler removed from Reactor\n")); + return 0; +} + +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_Reactor reactor; + Event_Handler handler (reactor); + + int result = 0; + while (result != -1) + result = reactor.handle_events (); + + return 0; +} diff --git a/ACE/examples/Reactor/WFMO_Reactor/Directory_Changes.cpp b/ACE/examples/Reactor/WFMO_Reactor/Directory_Changes.cpp new file mode 100644 index 00000000000..7f5126c6cba --- /dev/null +++ b/ACE/examples/Reactor/WFMO_Reactor/Directory_Changes.cpp @@ -0,0 +1,128 @@ +// $Id$ +// +// ============================================================================ +// +// = LIBRARY +// examples +// +// = FILENAME +// Directory_Changes.cpp +// +// = DESCRIPTION +// +// This application tests the working of WFMO_Reactor when users +// are interested in monitoring changes in the filesystem. +// +// = AUTHOR +// Irfan Pyarali +// +// ============================================================================ + +#include "ace/OS_main.h" + +#if defined (ACE_WIN32) + +#include "ace/Reactor.h" +#include "ace/OS_NS_unistd.h" +#include "ace/OS_NS_fcntl.h" + +ACE_RCSID(WFMO_Reactor, Directory_Changes, "$Id$") + +static int stop_test = 0; +static const ACE_TCHAR *directory = ACE_TEXT ("."); +static const ACE_TCHAR *temp_file = ACE_TEXT ("foo"); + +class Event_Handler : public ACE_Event_Handler +{ +public: + Event_Handler (ACE_Reactor &reactor); + ~Event_Handler (void); + int handle_signal (int signum, siginfo_t * = 0, ucontext_t * = 0); + int handle_close (ACE_HANDLE handle, + ACE_Reactor_Mask close_mask); + +private: + ACE_HANDLE handle_; +}; + +Event_Handler::Event_Handler (ACE_Reactor &reactor) + : handle_ (ACE_INVALID_HANDLE) +{ + this->reactor (&reactor); + + int change_notification_flags = FILE_NOTIFY_CHANGE_FILE_NAME; + + this->handle_ = ACE_TEXT_FindFirstChangeNotification (directory, // pointer to name of directory to watch + FALSE, // flag for monitoring directory or directory tree + change_notification_flags // filter conditions to watch for + ); + if (this->handle_ == ACE_INVALID_HANDLE) + ACE_ERROR ((LM_ERROR, "FindFirstChangeNotification could not be setup\n")); + + if (this->reactor ()->register_handler (this, + this->handle_) != 0) + ACE_ERROR ((LM_ERROR, "Registration with Reactor could not be done\n")); +} + +Event_Handler::~Event_Handler (void) +{ +} + +int +Event_Handler::handle_signal (int, siginfo_t *, ucontext_t *) +{ + ::FindNextChangeNotification (this->handle_); + if (stop_test) + this->reactor ()->close (); + return 0; +} + +int +Event_Handler::handle_close (ACE_HANDLE, + ACE_Reactor_Mask) +{ + ACE_DEBUG ((LM_DEBUG, "Event_Handler removed from Reactor\n")); + ::FindCloseChangeNotification (this->handle_); + return 0; +} + +void +worker (void) +{ + ACE_DEBUG ((LM_DEBUG, "(%t) Thread creation\n")); + ACE_DEBUG ((LM_DEBUG, "(%t) Thread creating temporary file\n")); + ACE_HANDLE file = ACE_OS::open (temp_file, _O_CREAT | _O_EXCL); + if (file == ACE_INVALID_HANDLE) + ACE_ERROR ((LM_ERROR, "Error in creating %s: %p\n", temp_file, "ACE_OS::open")); + else + { + ACE_OS::close (file); + ACE_DEBUG ((LM_DEBUG, "(%t) Thread sleeping\n")); + ACE_OS::sleep (3); + ACE_DEBUG ((LM_DEBUG, "(%t) Thread removing temporary file\n")); + stop_test = 1; + ACE_OS::unlink (temp_file); + } +} + +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_Reactor reactor; + Event_Handler handler (reactor); + + int result = ACE_OS::thr_create ((ACE_THR_FUNC) worker, 0, 0, 0); + ACE_ASSERT (result == 0); + + for (result = 0; result != -1; result = reactor.handle_events ()) + continue; + + return 0; +} +#else /* !ACE_WIN32 */ +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + return 0; +} +#endif /* ACE_WIN32 */ diff --git a/ACE/examples/Reactor/WFMO_Reactor/Exceptions.cpp b/ACE/examples/Reactor/WFMO_Reactor/Exceptions.cpp new file mode 100644 index 00000000000..5bbf0b4e4f3 --- /dev/null +++ b/ACE/examples/Reactor/WFMO_Reactor/Exceptions.cpp @@ -0,0 +1,109 @@ +// $Id$ +// +// ============================================================================ +// +// = LIBRARY +// examples +// +// = FILENAME +// Exceptions.cpp +// +// = DESCRIPTION +// +// This test application tests the state of WFMO_Reactor when +// exceptions occurs when executing user callbacks. +// +// The thread count in WFMO_Reactor is used to ensure that state of +// WFMO_Reactor is not fouled up when exceptions occur in user code. +// This example also shows how to write event loops that survive +// user exceptions +// +// = AUTHOR +// Irfan Pyarali +// +// ============================================================================ + +#include "ace/OS_main.h" + +#if defined (ACE_WIN32) + +#include "ace/WFMO_Reactor.h" + +ACE_RCSID(WFMO_Reactor, Exceptions, "$Id$") + +class Event_Handler : public ACE_Event_Handler +{ +public: + Event_Handler (void) + : event_ (1) + { + ACE_DEBUG ((LM_DEBUG, + "Event_Handler created\n")); + } + + ~Event_Handler (void) + { + ACE_DEBUG ((LM_DEBUG, + "Event_Handler destroyed\n")); + } + + int handle_signal (int, siginfo_t * = 0, ucontext_t * = 0) + { + char *cause_exception = 0; + char a = *cause_exception; + ACE_UNUSED_ARG(a); + return 0; + } + + ACE_HANDLE get_handle (void) const + { + return this->event_.handle (); + } +private: + ACE_Manual_Event event_; +}; + +class ACE_WFMO_Reactor_Test +{ +public: + static void doit (ACE_WFMO_Reactor &wfmo_reactor) + { + for (int i = 1; i <= 10; i++) + { + ACE_DEBUG ((LM_DEBUG, + "Active threads in WFMO_Reactor (before handle_events) = %d\n", + wfmo_reactor.active_threads_)); + ACE_SEH_TRY + { + wfmo_reactor.handle_events (); + } + ACE_SEH_EXCEPT (EXCEPTION_EXECUTE_HANDLER) + { + ACE_DEBUG ((LM_DEBUG, + "Exception occurred\n")); + } + ACE_DEBUG ((LM_DEBUG, + "Active threads in WFMO_Reactor (after handle_events) = %d\n", + wfmo_reactor.active_threads_)); + } + } +}; + +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + Event_Handler handler; + ACE_WFMO_Reactor wfmo_reactor; + wfmo_reactor.register_handler (&handler); + + ACE_WFMO_Reactor_Test::doit (wfmo_reactor); + + return 0; +} +#else /* !ACE_WIN32 */ +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + return 0; +} +#endif /* ACE_WIN32 */ diff --git a/ACE/examples/Reactor/WFMO_Reactor/Handle_Close.cpp b/ACE/examples/Reactor/WFMO_Reactor/Handle_Close.cpp new file mode 100644 index 00000000000..9eb6d7c727a --- /dev/null +++ b/ACE/examples/Reactor/WFMO_Reactor/Handle_Close.cpp @@ -0,0 +1,333 @@ +// $Id$ +// +// ============================================================================ +// +// = LIBRARY +// examples +// +// = FILENAME +// Handle_Close.cpp +// +// = DESCRIPTION +// +// This application tests whether handle_close gets called and if +// the correct masks are passed along. The handler should get +// handle_close called for all three masks (READ, WRITE, and +// EXCEPT). +// +// = AUTHOR +// Irfan Pyarali +// +// ============================================================================ + +#include "ace/Get_Opt.h" +#include "ace/Reactor.h" +#include "ace/WFMO_Reactor.h" +#include "ace/Select_Reactor.h" +#include "ace/Auto_Ptr.h" +#include "ace/Pipe.h" +#include "ace/OS_main.h" + +ACE_RCSID(WFMO_Reactor, Handle_Close, "$Id: ") + +// Use the WFMO_Reactor +static int opt_wfmo_reactor = 0; + +// Use the Select_Reactor +static int opt_select_reactor = 0; + +// Make pipe readable in main() +static int write_to_pipe_in_main = 0; + +// Cancel reads +static int cancel_reads = 0; + +// Write some data to the pipe. This will cause handle_input to get +// called. +void +write_to_pipe (ACE_Pipe &pipe) +{ + char *data = "hello"; + size_t len = ACE_OS::strlen (data); + + ssize_t result = ACE::send (pipe.write_handle (), + data, + len); + ACE_ASSERT ((size_t)result == len); + ACE_UNUSED_ARG (result); +} + +// Simple handler class +class Handler : public ACE_Event_Handler +{ +public: + Handler (ACE_Pipe &pipe) + : pipe_ (pipe) + { + } + + ~Handler (void) + { + this->reactor (0); + } + + ACE_HANDLE get_handle (void) const + { + return this->pipe_.read_handle (); + } + + int handle_close (ACE_HANDLE handle, + ACE_Reactor_Mask close_mask) + { + ACE_UNUSED_ARG (handle); + ACE_DEBUG ((LM_DEBUG, + "Handler::handle_close called with mask = %d\n", + close_mask)); + return 0; + } + + int handle_input (ACE_HANDLE handle) + { + ACE_UNUSED_ARG (handle); + ACE_DEBUG ((LM_DEBUG, "Handler::handle_input\n")); + + // Remove for reading + return -1; + } + + int handle_output (ACE_HANDLE handle) + { + ACE_UNUSED_ARG (handle); + ACE_DEBUG ((LM_DEBUG, "Handler::handle_output\n")); + + // Optionally cancel reads + if (cancel_reads) + { + int result = this->reactor ()->cancel_wakeup (this, + ACE_Event_Handler::READ_MASK); + ACE_ASSERT (result != -1); + ACE_UNUSED_ARG (result); + } + + // Write to the pipe; this causes handle_input to get called. + if (!write_to_pipe_in_main) + write_to_pipe (this->pipe_); + + // Remove for writing + return -1; + } + +protected: + ACE_Pipe &pipe_; +}; + +class Different_Handler : public ACE_Event_Handler +{ +public: + + Different_Handler (ACE_Pipe &pipe) + : pipe_ (pipe) + { + } + + ~Different_Handler (void) + { + this->reactor (0); + } + + ACE_HANDLE get_handle (void) const + { + return this->pipe_.read_handle (); + } + + int handle_close (ACE_HANDLE handle, + ACE_Reactor_Mask close_mask) + { + ACE_UNUSED_ARG (handle); + ACE_DEBUG ((LM_DEBUG, + "Different_Handler::handle_close called with mask = %d\n", + close_mask)); + return 0; + } + + int handle_input (ACE_HANDLE handle) + { + ACE_UNUSED_ARG (handle); + ACE_DEBUG ((LM_DEBUG, "Different_Handler::handle_input\n")); + + // Remove for reading + int result = this->reactor ()->remove_handler (this, + ACE_Event_Handler::READ_MASK); + ACE_ASSERT (result == 0); + ACE_UNUSED_ARG (result); + + return 0; + } + + int handle_output (ACE_HANDLE handle) + { + ACE_UNUSED_ARG (handle); + ACE_DEBUG ((LM_DEBUG, "Different_Handler::handle_output\n")); + + // Add for reading + int result = this->reactor ()->mask_ops (this, + ACE_Event_Handler::READ_MASK, + ACE_Reactor::ADD_MASK); + ACE_ASSERT (result != -1); + + ACE_Reactor_Mask old_masks = + ACE_Event_Handler::WRITE_MASK | + ACE_Event_Handler::EXCEPT_MASK; + + ACE_ASSERT (old_masks == + static_cast<ACE_Reactor_Mask> (result)); + ACE_UNUSED_ARG (old_masks); + + // Get new masks + result = this->reactor ()->mask_ops (this, + ACE_Event_Handler::NULL_MASK, + ACE_Reactor::GET_MASK); + ACE_ASSERT (result != -1); + + ACE_Reactor_Mask current_masks = + ACE_Event_Handler::READ_MASK | + ACE_Event_Handler::WRITE_MASK | + ACE_Event_Handler::EXCEPT_MASK; + + ACE_ASSERT (current_masks == + static_cast<ACE_Reactor_Mask> (result)); + ACE_UNUSED_ARG (current_masks); + + // Remove for writing + ACE_Reactor_Mask mask = ACE_Event_Handler::WRITE_MASK | ACE_Event_Handler::DONT_CALL; + result = this->reactor ()->remove_handler (this, + mask); + ACE_ASSERT (result == 0); + + // Write to the pipe; this causes handle_input to get called. + if (!write_to_pipe_in_main) + write_to_pipe (this->pipe_); + + return 0; + } + +protected: + ACE_Pipe &pipe_; +}; + + +// +// Selection of which reactor should get created +// +ACE_Reactor * +create_reactor (void) +{ + ACE_Reactor_Impl *impl = 0; + + if (opt_wfmo_reactor) + { +#if defined (ACE_WIN32) && !defined (ACE_HAS_WINCE) + ACE_NEW_RETURN (impl, + ACE_WFMO_Reactor, + 0); +#endif /* ACE_WIN32 */ + } + else if (opt_select_reactor) + { + ACE_NEW_RETURN (impl, + ACE_Select_Reactor, + 0); + } + else + { + ACE_Reactor *singleton_reactor = + ACE_Reactor::instance (); + ACE_Reactor::instance (0); + return singleton_reactor; + } + + ACE_Reactor *reactor = 0; + ACE_NEW_RETURN (reactor, + ACE_Reactor (impl, + 1), + 0); + + return reactor; +} + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + int result = 0; + + // Parse args + ACE_Get_Opt getopt (argc, argv, ACE_TEXT ("swmc"), 1); + for (int c; (c = getopt ()) != -1; ) + switch (c) + { + case 's': + opt_select_reactor = 1; + break; + case 'w': + opt_wfmo_reactor = 1; + break; + case 'm': + write_to_pipe_in_main = 1; + break; + case 'c': + cancel_reads = 1; + break; + } + + // Create pipes + ACE_Pipe pipe1, pipe2; + + result = pipe1.open (); + ACE_ASSERT (result == 0); + + result = pipe2.open (); + ACE_ASSERT (result == 0); + + // Create handlers + Handler handler (pipe1); + Different_Handler different_handler (pipe2); + + // Manage memory automagically. + auto_ptr<ACE_Reactor> reactor (create_reactor ()); + + // Register handlers + ACE_Reactor_Mask handler_mask = + ACE_Event_Handler::READ_MASK | + ACE_Event_Handler::WRITE_MASK | + ACE_Event_Handler::EXCEPT_MASK; + + ACE_Reactor_Mask different_handler_mask = + ACE_Event_Handler::WRITE_MASK | + ACE_Event_Handler::EXCEPT_MASK; + + result = reactor->register_handler (&handler, + handler_mask); + ACE_ASSERT (result == 0); + + result = reactor->register_handler (&different_handler, + different_handler_mask); + ACE_ASSERT (result == 0); + + // Write to the pipe; this causes handle_input to get called. + if (write_to_pipe_in_main) + { + write_to_pipe (pipe1); + write_to_pipe (pipe2); + } + + // Note that handle_output will get called automatically since the + // pipe is writable! + + // Run for three seconds + ACE_Time_Value time (3); + reactor->run_reactor_event_loop (time); + + ACE_DEBUG ((LM_DEBUG, "\nClosing down the application\n\n")); + + return 0; +} diff --git a/ACE/examples/Reactor/WFMO_Reactor/Makefile.am b/ACE/examples/Reactor/WFMO_Reactor/Makefile.am new file mode 100644 index 00000000000..cfa1c687b6c --- /dev/null +++ b/ACE/examples/Reactor/WFMO_Reactor/Makefile.am @@ -0,0 +1,308 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +ACE_BUILDDIR = $(top_builddir) +ACE_ROOT = $(top_srcdir) + +noinst_PROGRAMS = + +## Makefile.WFMO_Reactor_APC.am + +if BUILD_WFMO +if !BUILD_WINCE +noinst_PROGRAMS += apc + +apc_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +apc_SOURCES = \ + APC.cpp + +apc_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_WINCE +endif BUILD_WFMO + +## Makefile.WFMO_Reactor_Abandoned.am + +if BUILD_WFMO +noinst_PROGRAMS += abandoned + +abandoned_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +abandoned_SOURCES = \ + Abandoned.cpp + +abandoned_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif BUILD_WFMO + +## Makefile.WFMO_Reactor_Console_Input.am + +if BUILD_WFMO +noinst_PROGRAMS += console_input + +console_input_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +console_input_SOURCES = \ + Console_Input.cpp + +console_input_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif BUILD_WFMO + +## Makefile.WFMO_Reactor_Directory_Changes.am + +if BUILD_WFMO +noinst_PROGRAMS += directory_changes + +directory_changes_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +directory_changes_SOURCES = \ + Directory_Changes.cpp + +directory_changes_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif BUILD_WFMO + +## Makefile.WFMO_Reactor_Exceptions.am + +if BUILD_WFMO +noinst_PROGRAMS += exceptions + +exceptions_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +exceptions_SOURCES = \ + Exceptions.cpp + +exceptions_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif BUILD_WFMO + +## Makefile.WFMO_Reactor_Handle_Close.am + +if BUILD_WFMO +noinst_PROGRAMS += handle_close + +handle_close_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +handle_close_SOURCES = \ + Handle_Close.cpp + +handle_close_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif BUILD_WFMO + +## Makefile.WFMO_Reactor_Multithreading.am + +if BUILD_WFMO +noinst_PROGRAMS += multithreading + +multithreading_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +multithreading_SOURCES = \ + Multithreading.cpp + +multithreading_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif BUILD_WFMO + +## Makefile.WFMO_Reactor_Network_Events.am + +if BUILD_WFMO +noinst_PROGRAMS += network_events + +network_events_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +network_events_SOURCES = \ + Network_Events.cpp + +network_events_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif BUILD_WFMO + +## Makefile.WFMO_Reactor_Prerun_State_Changes.am + +if BUILD_WFMO +noinst_PROGRAMS += prerun_state_changes + +prerun_state_changes_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +prerun_state_changes_SOURCES = \ + Prerun_State_Changes.cpp + +prerun_state_changes_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif BUILD_WFMO + +## Makefile.WFMO_Reactor_Registration.am + +if BUILD_WFMO +noinst_PROGRAMS += registration + +registration_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +registration_SOURCES = \ + Registration.cpp + +registration_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif BUILD_WFMO + +## Makefile.WFMO_Reactor_Registry_Changes.am + +if BUILD_WFMO +if !BUILD_ACE_FOR_TAO +if !BUILD_WINCE +noinst_PROGRAMS += registry_changes + +registry_changes_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +registry_changes_SOURCES = \ + Registry_Changes.cpp + +registry_changes_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_WINCE +endif !BUILD_ACE_FOR_TAO +endif BUILD_WFMO + +## Makefile.WFMO_Reactor_Removals.am + +if BUILD_WFMO +noinst_PROGRAMS += removals + +removals_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +removals_SOURCES = \ + Removals.cpp + +removals_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif BUILD_WFMO + +## Makefile.WFMO_Reactor_Suspended_Removals.am + +if BUILD_WFMO +noinst_PROGRAMS += suspended_removals + +suspended_removals_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +suspended_removals_SOURCES = \ + Suspended_Removals.cpp + +suspended_removals_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif BUILD_WFMO + +## Makefile.WFMO_Reactor_Talker.am + +if BUILD_WFMO +if !BUILD_ACE_FOR_TAO +if !BUILD_WINCE +noinst_PROGRAMS += talker + +talker_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +talker_SOURCES = \ + Talker.cpp + +talker_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_WINCE +endif !BUILD_ACE_FOR_TAO +endif BUILD_WFMO + +## Makefile.WFMO_Reactor_Timeouts.am + +if BUILD_WFMO +noinst_PROGRAMS += timeouts + +timeouts_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +timeouts_SOURCES = \ + Timeouts.cpp + +timeouts_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif BUILD_WFMO + +## Makefile.WFMO_Reactor_Window_Messages.am + +if BUILD_WFMO +if !BUILD_ACE_FOR_TAO +if !BUILD_WINCE +noinst_PROGRAMS += window_messages + +window_messages_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +window_messages_SOURCES = \ + Window_Messages.cpp + +window_messages_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_WINCE +endif !BUILD_ACE_FOR_TAO +endif BUILD_WFMO + +## Clean up template repositories, etc. +clean-local: + -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.* + -rm -f gcctemp.c gcctemp so_locations *.ics + -rm -rf cxx_repository ptrepository ti_files + -rm -rf templateregistry ir.out + -rm -rf ptrepository SunWS_cache Templates.DB diff --git a/ACE/examples/Reactor/WFMO_Reactor/Multithreading.cpp b/ACE/examples/Reactor/WFMO_Reactor/Multithreading.cpp new file mode 100644 index 00000000000..0778f375251 --- /dev/null +++ b/ACE/examples/Reactor/WFMO_Reactor/Multithreading.cpp @@ -0,0 +1,262 @@ +// $Id$ +// +// ============================================================================ +// +// = LIBRARY +// examples +// +// = FILENAME +// Multithreading.cpp +// +// = DESCRIPTION +// +// This application tests multiple threads simultaneously calling +// Reactor::handle_events(). It also shows how different threads +// can update the state of Reactor by registering and removing +// Event_Handlers. +// +// Note that this test will only work with WFMO_Reactor +// +// = AUTHOR +// Irfan Pyarali +// +// ============================================================================ + +#include "ace/OS_main.h" + +#if defined (ACE_WIN32) + +#include "ace/Task.h" +#include "ace/Reactor.h" +#include "ace/WFMO_Reactor.h" +#include "ace/Get_Opt.h" +#include "ace/OS_NS_time.h" + +ACE_RCSID(WFMO_Reactor, Multithreading, "$Id$") + +static int concurrent_threads = 1; +static int number_of_handles = static_cast<int> (ACE_Reactor::instance ()->size ()); +static int number_of_handles_to_signal = 1; +static int interval = 2; +static int iterations = 10; + +// Explain usage and exit. +static void +print_usage_and_die (void) +{ + ACE_DEBUG ((LM_DEBUG, + "usage: \n\t" + "[-t (# of threads - default 1)] \n\t" + "[-h (# of handlers) - default 62] \n\t" + "[-i (# time interval between signals) - default 2] \n\t" + "[-s (# of handles to signal) - default 1] \n\t" + "[-e (# of iterations) - default 10] \n\t")); + ACE_OS::exit (1); +} + +// Parse the command-line arguments and set options. +static void +parse_args (int argc, ACE_TCHAR **argv) +{ + ACE_Get_Opt get_opt (argc, argv, ACE_TEXT("t:h:s:i:e:")); + int c; + + while ((c = get_opt ()) != -1) + switch (c) + { + case 't': + concurrent_threads = ACE_OS::atoi (get_opt.opt_arg ()); + break; + case 'e': + iterations = ACE_OS::atoi (get_opt.opt_arg ()); + break; + case 'h': + number_of_handles = ACE_OS::atoi (get_opt.opt_arg ()); + break; + case 'i': + interval = ACE_OS::atoi (get_opt.opt_arg ()); + break; + case 's': + number_of_handles_to_signal = ACE_OS::atoi (get_opt.opt_arg ()); + break; + default: + print_usage_and_die (); + break; + } +} + +class Task_Handler : public ACE_Task<ACE_NULL_SYNCH> +{ +public: + Task_Handler (size_t number_of_handles, + size_t concurrent_threads); + // Constructor. + + ~Task_Handler (void); + // Destructor. + + virtual int handle_close (ACE_HANDLE handle, + ACE_Reactor_Mask close_mask); + // Called when object is removed from the ACE_Reactor + + int handle_signal (int signum, siginfo_t * = 0, ucontext_t * = 0); + // Handle events being signaled by the main thread. + + virtual int handle_timeout (const ACE_Time_Value &tv, + const void *arg = 0); + // Called when timer expires. + + int svc (void); + // Task event loop. + + int signal (size_t index); + // Signal an event. + +private: + ACE_Auto_Event *events_; +}; + +// All threads do reactor->handle_events () +int +Task_Handler::svc (void) +{ + // Try to become the owner + ACE_Reactor::instance ()->owner (ACE_Thread::self ()); + // Run the event loop. + return ACE_Reactor::run_event_loop (); +} + +Task_Handler::Task_Handler (size_t number_of_handles, + size_t concurrent_threads) +{ + ACE_NEW (this->events_, ACE_Auto_Event [number_of_handles]); + + for (size_t i = 0; i < number_of_handles; ++i) + if (ACE_Reactor::instance ()->register_handler (this, + this->events_[i].handle ()) == -1) + ACE_ERROR ((LM_ERROR, + "%p\t cannot register handle %d with Reactor\n", + "Task_Handler::Task_Handler", + i)); + + // Make us an active object. + if (this->activate (THR_NEW_LWP, + static_cast<int> (concurrent_threads)) == -1) + ACE_ERROR ((LM_ERROR, "%p\t cannot activate task\n", + "activate")); +} + +Task_Handler::~Task_Handler (void) +{ + this->reactor (0); + delete [] this->events_; +} + + +int +Task_Handler::handle_signal (int, siginfo_t *siginfo, ucontext_t *) +{ + // When signaled, print message, remove self, and add self + // This will force Reactor to update its internal handle tables + + ACE_DEBUG ((LM_DEBUG, + "(%t) calls handle_signal for handle %d\n", + siginfo->si_handle_)); + + if (ACE_Reactor::instance ()->remove_handler (siginfo->si_handle_, + ACE_Event_Handler::DONT_CALL) == -1) + return -1; + // ACE_ERROR_RETURN ((LM_ERROR, + // "(%t) %p\tTask cannot be unregistered from Reactor: handle value = %d\n", + // "Task_Handler::handle_signal", + // siginfo->si_handle_), -1); + + if (ACE_Reactor::instance ()->register_handler (this, + siginfo->si_handle_) == -1) + return -1; + // ACE_ERROR_RETURN ((LM_ERROR, + // "(%t) %p\tTask cannot be registered with Reactor: handle value = %d\n", + // "Task_Handler::handle_signal", + // siginfo->si_handle_), -1); + return 0; +} + +int +Task_Handler::handle_close (ACE_HANDLE handle, + ACE_Reactor_Mask) +{ + ACE_DEBUG ((LM_DEBUG, "(%t) handle_close() called: handle value = %d\n", + handle)); + return 0; +} + +int +Task_Handler::handle_timeout (const ACE_Time_Value &, + const void *arg) +{ + ACE_DEBUG ((LM_DEBUG, "(%t) handle_timeout() called: iteration value = %d\n", + size_t (arg))); + return 0; +} + +int +Task_Handler::signal (size_t index) +{ + return this->events_[index].signal (); +} + +int +ACE_TMAIN (int argc, ACE_TCHAR **argv) +{ + parse_args (argc, argv); + Task_Handler task (number_of_handles, + concurrent_threads); + + ACE_OS::srand (ACE_OS::time (0L)); + + for (int i = 1; i <= iterations; i++) + { + // Sleep for a while + ACE_OS::sleep (interval); + + // Randomly generate events + ACE_DEBUG ((LM_DEBUG, "********************************************************\n")); + ACE_DEBUG ((LM_DEBUG, "(%t -- main thread) signaling %d events : iteration = %d\n", + number_of_handles_to_signal, + i)); + ACE_DEBUG ((LM_DEBUG, "********************************************************\n")); + + // Setup a timer for the task + if (ACE_Reactor::instance ()->schedule_timer (&task, + (void *)((size_t)i), + ACE_Time_Value::zero) == -1) + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "schedule_timer"), -1); + + for (int i = 0; i < number_of_handles_to_signal; i++) + // Randomly select a handle to signal. + task.signal (ACE_OS::rand() % number_of_handles); + } + + // Sleep for a while + ACE_OS::sleep (interval); + + // End the Reactor event loop + ACE_Reactor::end_event_loop (); + + // Wait for all threads to exit + ACE_Thread_Manager::instance ()->wait (); + + // Close the Reactor singleton before exiting this function. + // If we wait for the Object Manager to do this, it will be too + // late since Task_Handler instance would have disappeared. + ACE_Reactor::close_singleton (); + + return 0; +} +#else /* !ACE_WIN32 */ +int +ACE_TMAIN (int, ACE_TCHAR **) +{ + return 0; +} +#endif /* ACE_WIN32 */ diff --git a/ACE/examples/Reactor/WFMO_Reactor/Network_Events.cpp b/ACE/examples/Reactor/WFMO_Reactor/Network_Events.cpp new file mode 100644 index 00000000000..9935679a60f --- /dev/null +++ b/ACE/examples/Reactor/WFMO_Reactor/Network_Events.cpp @@ -0,0 +1,211 @@ +// $Id$ +// +// ============================================================================ +// +// = LIBRARY +// examples +// +// = FILENAME +// Network_Events.cpp +// +// = DESCRIPTION +// +// This application tests Reactor to make sure that it responds +// correctly to different kinds of network events. +// +// The test starts off by creating a Network_Listener, that listens +// for connections at ACE_DEFAULT_SERVER_PORT. When a client +// connects, a Network_Handler is created. Network_Handler reads +// messages off the socket and prints them out. This is done until +// the remote side shuts down. Multiple clients can connect at the +// same time. +// +// Events tested in this example includes ACCEPT, READ, and CLOSE masks. +// +// To run this example, start an instance of this example and +// connect to it using telnet (to port +// ACE_DEFAULT_SERVER_PORT(20002)). +// +// = AUTHOR +// Irfan Pyarali +// +// ============================================================================ + +#include "ace/Reactor.h" +#include "ace/WFMO_Reactor.h" +#include "ace/INET_Addr.h" +#include "ace/SOCK_Stream.h" +#include "ace/SOCK_Acceptor.h" +#include "ace/OS_main.h" + +ACE_RCSID(WFMO_Reactor, Network_Events, "$Id$") + +class Network_Handler : public ACE_Event_Handler +{ +public: + Network_Handler (ACE_SOCK_Stream &s); + // Default constructor + + virtual int handle_input (ACE_HANDLE handle); + virtual int handle_close (ACE_HANDLE handle, + ACE_Reactor_Mask close_mask); + virtual ACE_HANDLE get_handle (void) const; + + ACE_SOCK_Stream stream_; + +}; + +Network_Handler::Network_Handler (ACE_SOCK_Stream &s) + : stream_ (s) +{ + this->reactor (ACE_Reactor::instance ()); + + int result = this->reactor ()->register_handler (this, READ_MASK); + ACE_ASSERT (result == 0); + ACE_UNUSED_ARG (result); +} + +ACE_HANDLE +Network_Handler::get_handle (void) const +{ + return this->stream_.get_handle (); +} + +int +Network_Handler::handle_input (ACE_HANDLE handle) +{ + ACE_DEBUG ((LM_DEBUG, "Network_Handler::handle_input handle = %d\n", handle)); + + while (1) + { + char message[BUFSIZ]; + int result = this->stream_.recv (message, sizeof message); + if (result > 0) + { + message[result] = 0; + ACE_DEBUG ((LM_DEBUG, "Remote message: %s\n", message)); + } + else if (result == 0) + { + ACE_DEBUG ((LM_DEBUG, "Connection closed\n")); + return -1; + } + else if (errno == EWOULDBLOCK) + { + return 0; + } + else + { + ACE_DEBUG ((LM_DEBUG, "Problems in receiving data, result = %d", result)); + return -1; + } + } +} + +int +Network_Handler::handle_close (ACE_HANDLE handle, + ACE_Reactor_Mask) +{ + ACE_DEBUG ((LM_DEBUG, "Network_Handler::handle_close handle = %d\n", handle)); + + this->stream_.close (); + delete this; + + ACE_Reactor::end_event_loop (); + + return 0; +} + +class Network_Listener : public ACE_Event_Handler +{ +public: + Network_Listener (void); + // Default constructor + ~Network_Listener (void); + // Default constructor + + virtual int handle_input (ACE_HANDLE handle); + virtual int handle_close (ACE_HANDLE handle, + ACE_Reactor_Mask close_mask); + ACE_HANDLE get_handle (void) const; + + ACE_INET_Addr local_address_; + ACE_SOCK_Acceptor acceptor_; +}; + +Network_Listener::Network_Listener (void) + : local_address_ (ACE_DEFAULT_SERVER_PORT), + acceptor_ (local_address_, 1) +{ + this->reactor (ACE_Reactor::instance ()); + int result = this->reactor ()->register_handler (this, + ACE_Event_Handler::ACCEPT_MASK); + ACE_ASSERT (result == 0); + ACE_UNUSED_ARG (result); +} + +Network_Listener::~Network_Listener (void) +{ +} + +ACE_HANDLE +Network_Listener::get_handle (void) const +{ + return this->acceptor_.get_handle (); +} + +int +Network_Listener::handle_input (ACE_HANDLE handle) +{ + ACE_DEBUG ((LM_DEBUG, "Network_Listener::handle_input handle = %d\n", handle)); + + ACE_INET_Addr remote_address; + ACE_SOCK_Stream stream; + + // Try to find out if the implementation of the reactor that we are + // using requires us to reset the event association for the newly + // created handle. This is because the newly created handle will + // inherit the properties of the listen handle, including its event + // associations. + int reset_new_handle = this->reactor ()->uses_event_associations (); + + int result = this->acceptor_.accept (stream, // stream + &remote_address, // remote address + 0, // timeout + 1, // restart + reset_new_handle); // reset new handler + ACE_ASSERT (result == 0); + ACE_UNUSED_ARG (result); + + ACE_DEBUG ((LM_DEBUG, "Remote connection from: ")); + remote_address.dump (); + + Network_Handler *handler; + ACE_NEW_RETURN (handler, Network_Handler (stream), -1); + + return 0; +} + +int +Network_Listener::handle_close (ACE_HANDLE handle, + ACE_Reactor_Mask) +{ + ACE_DEBUG ((LM_DEBUG, "Network_Listener::handle_close handle = %d\n", handle)); + + this->acceptor_.close (); + + delete this; + + return 0; +} + +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + Network_Listener *listener = 0; + listener = new Network_Listener; + + ACE_Reactor::run_event_loop (); + + return 0; +}; diff --git a/ACE/examples/Reactor/WFMO_Reactor/Prerun_State_Changes.cpp b/ACE/examples/Reactor/WFMO_Reactor/Prerun_State_Changes.cpp new file mode 100644 index 00000000000..e276fd7d3f8 --- /dev/null +++ b/ACE/examples/Reactor/WFMO_Reactor/Prerun_State_Changes.cpp @@ -0,0 +1,66 @@ +// $Id$ +// +// ============================================================================ +// +// = LIBRARY +// examples +// +// = FILENAME +// Prerun_State_Changes.cpp +// +// = DESCRIPTION +// +// Tests the Reactor's ability to handle state changes before +// getting a chance to run. +// +// = AUTHOR +// +// Irfan Pyarali +// +// ============================================================================ + +#include "ace/Reactor.h" +#include "ace/OS_main.h" + +ACE_RCSID(WFMO_Reactor, Prerun_State_Changes, "$Id$") + +class Event_Handler : public ACE_Event_Handler +// = TITLE +// Generic Event Handler. +// +{ +public: + virtual int handle_close (ACE_HANDLE handle, ACE_Reactor_Mask mask) + { + ACE_UNUSED_ARG(mask); + ACE_DEBUG ((LM_DEBUG, + "event handler %d closed.\n", + (size_t) handle)); + delete this; + return 0; + } +}; + +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_HANDLE handle = (ACE_HANDLE) ::socket (PF_INET, SOCK_STREAM, 0); + + Event_Handler *event_handler = new Event_Handler; + + int result = ACE_Reactor::instance ()->register_handler (handle, + event_handler, + ACE_Event_Handler::READ_MASK); + ACE_ASSERT (result == 0); + + result = ACE_Reactor::instance ()->register_handler (handle, + event_handler, + ACE_Event_Handler::WRITE_MASK | ACE_Event_Handler::QOS_MASK); + ACE_ASSERT (result == 0); + + result = ACE_Reactor::instance ()->remove_handler (handle, + ACE_Event_Handler::READ_MASK | ACE_Event_Handler::DONT_CALL); + ACE_ASSERT (result == 0); + + return 0; +} diff --git a/ACE/examples/Reactor/WFMO_Reactor/Registration.cpp b/ACE/examples/Reactor/WFMO_Reactor/Registration.cpp new file mode 100644 index 00000000000..a9429bdd433 --- /dev/null +++ b/ACE/examples/Reactor/WFMO_Reactor/Registration.cpp @@ -0,0 +1,169 @@ +// $Id$ +// +// ============================================================================ +// +// = LIBRARY +// examples +// +// = FILENAME +// Registration.cpp +// +// = DESCRIPTION +// +// This test application tests a wide range of registration, +// suspension, resumption, and removal of events from Reactor. +// +// The application initially registers two events with Reactor. A +// auxiliary thread is created to do the signaling on the +// events. When the first event is signaled, the event is suspended +// from Reactor. The event is then signaled again, but is "lost" +// since the handler has been suspended. When the second event is +// signal, the first event is resumed and the second is +// suspended. When the first event is signaled again, both events +// are removed from Reactor. +// +// This test shows off the following features of Reactor: +// - Registration +// - Suspension +// - Resumption +// - Removal (while active and while suspended) +// +// = AUTHOR +// Irfan Pyarali +// +// ============================================================================ + +#include "ace/OS_main.h" + +#if defined (ACE_WIN32) + +#include "ace/Reactor.h" +#include "ace/Auto_Event.h" +#include "ace/OS_NS_unistd.h" + +ACE_RCSID(WFMO_Reactor, Registration, "$Id$") + +// Globals for this test +int stop_test = 0; +ACE_Reactor reactor; + + +class Simple_Handler : public ACE_Event_Handler +{ +public: + Simple_Handler (void); + // Default constructor + + virtual int handle_signal (int signum, siginfo_t * = 0, ucontext_t * = 0); + virtual int handle_close (ACE_HANDLE handle, + ACE_Reactor_Mask close_mask); + + ACE_Auto_Event event1_; + ACE_Auto_Event event2_; + int handle_signal_count_; + int handle_close_count_; +}; + +Simple_Handler::Simple_Handler (void) + : handle_signal_count_ (0), + handle_close_count_ (0) +{ +} + +int +Simple_Handler::handle_signal (int, siginfo_t *s, ucontext_t *) +{ + ACE_HANDLE handle = s->si_handle_; + ACE_UNUSED_ARG (handle); + + this->handle_signal_count_++; + + if (this->handle_signal_count_ == 1) + this->reactor ()->suspend_handler (event1_.handle ()); + else if (this->handle_signal_count_ == 2) + { + this->reactor ()->resume_handler (event1_.handle ()); + this->reactor ()->suspend_handler (event2_.handle ()); + } + else if (this->handle_signal_count_ == 3) + { + this->reactor ()->remove_handler (event1_.handle (), + ACE_Event_Handler::NULL_MASK); + this->reactor ()->remove_handler (event2_.handle (), + ACE_Event_Handler::NULL_MASK); + } + return 0; +} + +int +Simple_Handler::handle_close (ACE_HANDLE handle, + ACE_Reactor_Mask) +{ + ACE_DEBUG ((LM_DEBUG, "Simple_Handler::handle_close handle = %d\n", handle)); + this->handle_close_count_++; + + if (this->handle_close_count_ == 1) + stop_test = 0; + else if (this->handle_close_count_ == 2) + stop_test = 1; + + return 0; +} + +// Globals for this test +Simple_Handler simple_handler; + +void +worker (void) +{ + ACE_DEBUG ((LM_DEBUG, "(%t) Thread creation\n")); + ACE_DEBUG ((LM_DEBUG, "(%t) Thread sleeping\n")); + ACE_OS::sleep (1); + ACE_DEBUG ((LM_DEBUG, "(%t) Thread signaling %d\n", simple_handler.event1_.handle())); + simple_handler.event1_.signal (); + ACE_DEBUG ((LM_DEBUG, "(%t) Thread sleeping\n")); + ACE_OS::sleep (1); + ACE_DEBUG ((LM_DEBUG, "(%t) Thread signaling %d\n", simple_handler.event1_.handle())); + ACE_DEBUG ((LM_DEBUG, "Note: This signal should be \"lost\" because of the suspended handler\n")); + simple_handler.event1_.signal (); + ACE_DEBUG ((LM_DEBUG, "(%t) Thread sleeping\n")); + ACE_OS::sleep (1); + ACE_DEBUG ((LM_DEBUG, "(%t) Thread resetting %d\n", simple_handler.event1_.handle())); + simple_handler.event1_.reset (); + ACE_DEBUG ((LM_DEBUG, "(%t) Thread signaling %d\n", simple_handler.event2_.handle())); + simple_handler.event2_.signal (); + ACE_DEBUG ((LM_DEBUG, "(%t) Thread sleeping\n")); + ACE_OS::sleep (1); + ACE_DEBUG ((LM_DEBUG, "(%t) Thread signaling %d\n", simple_handler.event1_.handle())); + simple_handler.event1_.signal (); + ACE_DEBUG ((LM_DEBUG, "(%t) Thread death\n")); +} + +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + int result = reactor.register_handler (&simple_handler, + simple_handler.event1_.handle ()); + ACE_ASSERT (result == 0); + + result = reactor.register_handler (&simple_handler, + simple_handler.event2_.handle ()); + ACE_ASSERT (result == 0); + + result = ACE_OS::thr_create ((ACE_THR_FUNC) worker, 0, 0, 0); + ACE_ASSERT (result == 0); + + result = 0; + while (!stop_test && result != -1) + { + result = reactor.handle_events (); + } + return 0; +}; +#else /* !ACE_WIN32 */ +int +ACE_TMAIN (int, ACE_TCHAR **) +{ + return 0; +} +#endif /* ACE_WIN32 */ diff --git a/ACE/examples/Reactor/WFMO_Reactor/Registry_Changes.cpp b/ACE/examples/Reactor/WFMO_Reactor/Registry_Changes.cpp new file mode 100644 index 00000000000..be787293e65 --- /dev/null +++ b/ACE/examples/Reactor/WFMO_Reactor/Registry_Changes.cpp @@ -0,0 +1,146 @@ +// $Id$ +// +// ============================================================================ +// +// = LIBRARY +// examples +// +// = FILENAME +// Registry_Changes.cpp +// +// = DESCRIPTION +// +// This application tests the working of Reactor when users are +// interested in monitoring changes in the registry. +// +// = AUTHOR +// Irfan Pyarali +// +// ============================================================================ + +#include "ace/OS_main.h" + +#if defined (ACE_WIN32) + +#include "ace/Reactor.h" +#include "ace/Registry.h" +#include "ace/Auto_Event.h" +#include "ace/OS_NS_unistd.h" + +ACE_RCSID(WFMO_Reactor, Registry_Changes, "$Id$") + +static int stop_test = 0; +static HKEY context_to_monitor = HKEY_CURRENT_USER; +static const ACE_TCHAR *temp_context_name = ACE_TEXT ("ACE temporary context"); + +class Event_Handler : public ACE_Event_Handler +{ +public: + Event_Handler (ACE_Reactor &reactor); + ~Event_Handler (void); + int handle_signal (int signum, siginfo_t * = 0, ucontext_t * = 0); + int handle_close (ACE_HANDLE handle, + ACE_Reactor_Mask close_mask); + ACE_Registry::Naming_Context &context (void); + +private: + ACE_Auto_Event event_; + ACE_Registry::Naming_Context context_; +}; + +Event_Handler::Event_Handler (ACE_Reactor &reactor) + : context_ (context_to_monitor) +{ + this->reactor (&reactor); + + if (::RegNotifyChangeKeyValue (this->context_.key (), // handle of key to watch + FALSE, // flag for subkey notification + REG_NOTIFY_CHANGE_NAME, // changes to be reported + this->event_.handle (), // handle of signaled event + TRUE // flag for asynchronous reporting + ) != ERROR_SUCCESS) + ACE_ERROR ((LM_ERROR, "RegNotifyChangeKeyValue could not be setup\n")); + + if (this->reactor ()->register_handler (this, + this->event_.handle ()) != 0) + ACE_ERROR ((LM_ERROR, "Registration with Reactor could not be done\n")); +} + +Event_Handler::~Event_Handler (void) +{ +} + +int +Event_Handler::handle_signal (int, siginfo_t *, ucontext_t *) +{ + if (stop_test) + this->reactor ()->close (); + else if (::RegNotifyChangeKeyValue (this->context_.key (), // handle of key to watch + FALSE, // flag for subkey notification + REG_NOTIFY_CHANGE_NAME, // changes to be reported + this->event_.handle (), // handle of signaled event + TRUE // flag for asynchronous reporting + ) != ERROR_SUCCESS) + ACE_ERROR ((LM_ERROR, + "RegNotifyChangeKeyValue could not be setup\n")); + return 0; +} + +int +Event_Handler::handle_close (ACE_HANDLE, + ACE_Reactor_Mask) +{ + ACE_DEBUG ((LM_DEBUG, "Event_Handler removed from Reactor\n")); + return 0; +} + +ACE_Registry::Naming_Context & +Event_Handler::context (void) +{ + return this->context_; +} + +void +worker (Event_Handler *event_handler) +{ + ACE_DEBUG ((LM_DEBUG, "(%t) Thread creation\n")); + ACE_DEBUG ((LM_DEBUG, "(%t) Thread creating temporary registry entry\n")); + + ACE_Registry::Naming_Context temp_context; + int result = event_handler->context ().bind_new_context (temp_context_name, + temp_context); + + if (result == -1) + ACE_ERROR ((LM_ERROR, "Error in creating %s: %p\n", temp_context_name, "bind_new_context")); + else + { + ACE_DEBUG ((LM_DEBUG, "(%t) Thread sleeping\n")); + ACE_OS::sleep (3); + + ACE_DEBUG ((LM_DEBUG, "(%t) Thread removing registry entry\n")); + stop_test = 1; + event_handler->context ().unbind_context (temp_context_name); + } +} + +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_Reactor reactor; + Event_Handler handler (reactor); + + int result = ACE_OS::thr_create ((ACE_THR_FUNC) worker, &handler, 0, 0); + ACE_ASSERT (result == 0); + + for (result = 0; result != -1; result = reactor.handle_events ()) + continue; + + return 0; +} +#else /* !ACE_WIN32 */ +int +ACE_TMAIN (int, ACE_TCHAR **) +{ + return 0; +} +#endif /* ACE_WIN32 */ diff --git a/ACE/examples/Reactor/WFMO_Reactor/Removals.cpp b/ACE/examples/Reactor/WFMO_Reactor/Removals.cpp new file mode 100644 index 00000000000..260b9e897ee --- /dev/null +++ b/ACE/examples/Reactor/WFMO_Reactor/Removals.cpp @@ -0,0 +1,114 @@ +// $Id$ +// +// ============================================================================ +// +// = LIBRARY +// examples +// +// = FILENAME +// Removals.cpp +// +// = DESCRIPTION +// +// Tests the Reactor's ability to handle simultaneous events. If +// you pass anything on the command-line, then each handler +// requests to be removed from the Reactor after each event. +// +// = AUTHOR +// Tim Harrison +// Irfan Pyarali +// +// ============================================================================ + +#include "ace/OS_main.h" + +#if defined (ACE_WIN32) + +#include "ace/Reactor.h" +#include "ace/Service_Config.h" +#include "ace/Event.h" + +ACE_RCSID(WFMO_Reactor, Removals, "$Id$") + +class Event_Handler : public ACE_Event_Handler +// = TITLE +// Generic Event Handler. +// +// = DESCRIPTION +// +// Creates event. Registers with Reactor. Signals event. If +// created with -close_down- it returns -1 from handle signal. +{ +public: + Event_Handler (int event_number, + int close_down) + : event_number_ (event_number), + close_down_ (close_down) + { + if (ACE_Reactor::instance ()->register_handler (this, + this->event_.handle ()) == -1) + ACE_ERROR ((LM_ERROR, "%p\tevent handler %d cannot be added to Reactor\n", "", event_number_)); + this->event_.signal (); + } + + virtual int handle_signal (int, siginfo_t *, ucontext_t *) + { + if (this->close_down_) + return -1; + else + return 0; + } + + virtual int handle_close (ACE_HANDLE, ACE_Reactor_Mask) + { + ACE_DEBUG ((LM_DEBUG, "event handler %d closed.\n", event_number_)); + delete this; + return 0; + } + + virtual ACE_HANDLE get_handle (void) const + { + return event_.handle (); + } + +private: + int event_number_; + // Our event number. + + int close_down_; + // Shall we close down or not. + + ACE_Event event_; + // Signaled to shut down the handler. +}; + +int +ACE_TMAIN (int argc, ACE_TCHAR *[]) +{ + int close_down = argc > 1 ? 1 : 0; + + for (size_t i = 1; i <= ACE_Reactor::instance ()->size (); i++) + new Event_Handler (static_cast<int> (i), close_down); + + int result = 0; + ACE_Time_Value time (1); + while (1) + { + result = ACE_Reactor::instance ()->handle_events (time); + if (result == 0 && errno == ETIME) + { + ACE_DEBUG ((LM_DEBUG, "No more work left: timing out\n")); + break; + } + if (result == -1) + ACE_ERROR_RETURN ((LM_ERROR, "%p.\n", "main"), -1); + } + return 0; +} +#else /* !ACE_WIN32 */ +int +ACE_TMAIN (int , ACE_TCHAR *[]) +{ + return 0; +} +#endif /* ACE_WIN32 */ diff --git a/ACE/examples/Reactor/WFMO_Reactor/Suspended_Removals.cpp b/ACE/examples/Reactor/WFMO_Reactor/Suspended_Removals.cpp new file mode 100644 index 00000000000..ead467146a5 --- /dev/null +++ b/ACE/examples/Reactor/WFMO_Reactor/Suspended_Removals.cpp @@ -0,0 +1,173 @@ +// $Id$ +// +// ============================================================================ +// +// = LIBRARY +// examples +// +// = FILENAME +// Suspended_Removals.cpp +// +// = DESCRIPTION +// +// Tests the Reactor's ability to handle removal of suspended +// handles. +// +// = AUTHOR +// Irfan Pyarali +// +// ============================================================================ + +#include "ace/OS_main.h" + +#if defined (ACE_WIN32) + +#include "ace/Reactor.h" +#include "ace/WFMO_Reactor.h" + +ACE_RCSID(WFMO_Reactor, Suspended_Removals, "$Id$") + +class Event_Handler : public ACE_Event_Handler +{ +public: + + ACE_HANDLE get_handle (void) const + { + return this->event_.handle (); + } + + ACE_Event event_; +}; + +class ACE_WFMO_Reactor_Test +{ +public: + static void check_for_valid_state (ACE_WFMO_Reactor &wfmo_reactor, + size_t handles_to_be_added, + size_t handles_to_be_suspended, + size_t handles_to_be_resumed, + size_t handles_to_be_deleted) + { + ACE_ASSERT (wfmo_reactor.handler_rep_.handles_to_be_added_ == handles_to_be_added); + ACE_ASSERT (wfmo_reactor.handler_rep_.handles_to_be_suspended_ == handles_to_be_suspended); + ACE_ASSERT (wfmo_reactor.handler_rep_.handles_to_be_resumed_ == handles_to_be_resumed); + ACE_ASSERT (wfmo_reactor.handler_rep_.handles_to_be_deleted_ == handles_to_be_deleted); + } +}; + +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + Event_Handler handler; + ACE_WFMO_Reactor reactor; + ACE_Reactor base_reactor (&reactor); + ACE_Time_Value time (1); + + int result = + reactor.register_handler (&handler); + ACE_ASSERT (result == 0); + + ACE_WFMO_Reactor_Test::check_for_valid_state (reactor, + 1, 0, 0, 0); + + result = + reactor.remove_handler (&handler, + ACE_Event_Handler::DONT_CALL | + ACE_Event_Handler::ALL_EVENTS_MASK); + ACE_ASSERT (result == 0); + + ACE_WFMO_Reactor_Test::check_for_valid_state (reactor, + 1, 0, 0, 1); + + result = base_reactor.run_reactor_event_loop (time); + ACE_ASSERT (result != -1); + + ACE_WFMO_Reactor_Test::check_for_valid_state (reactor, + 0, 0, 0, 0); + + result = + reactor.register_handler (&handler); + ACE_ASSERT (result == 0); + + ACE_WFMO_Reactor_Test::check_for_valid_state (reactor, + 1, 0, 0, 0); + + result = base_reactor.run_reactor_event_loop (time); + ACE_ASSERT (result != -1); + + ACE_WFMO_Reactor_Test::check_for_valid_state (reactor, + 0, 0, 0, 0); + + result = + reactor.suspend_handler (&handler); + ACE_ASSERT (result == 0); + + ACE_WFMO_Reactor_Test::check_for_valid_state (reactor, + 0, 1, 0, 0); + + result = + reactor.remove_handler (&handler, + ACE_Event_Handler::DONT_CALL | + ACE_Event_Handler::ALL_EVENTS_MASK); + ACE_ASSERT (result == 0); + + ACE_WFMO_Reactor_Test::check_for_valid_state (reactor, + 0, 0, 0, 1); + + result = base_reactor.run_reactor_event_loop (time); + ACE_ASSERT (result != -1); + + ACE_WFMO_Reactor_Test::check_for_valid_state (reactor, + 0, 0, 0, 0); + + result = + reactor.register_handler (&handler); + ACE_ASSERT (result == 0); + + ACE_WFMO_Reactor_Test::check_for_valid_state (reactor, + 1, 0, 0, 0); + + result = + reactor.suspend_handler (&handler); + ACE_ASSERT (result == 0); + + ACE_WFMO_Reactor_Test::check_for_valid_state (reactor, + 1, 1, 0, 0); + + result = base_reactor.run_reactor_event_loop (time); + ACE_ASSERT (result != -1); + + ACE_WFMO_Reactor_Test::check_for_valid_state (reactor, + 0, 0, 0, 0); + + result = + reactor.resume_handler (&handler); + ACE_ASSERT (result == 0); + + ACE_WFMO_Reactor_Test::check_for_valid_state (reactor, + 0, 0, 1, 0); + + result = + reactor.remove_handler (&handler, + ACE_Event_Handler::DONT_CALL | + ACE_Event_Handler::ALL_EVENTS_MASK); + ACE_ASSERT (result == 0); + + ACE_WFMO_Reactor_Test::check_for_valid_state (reactor, + 0, 0, 0, 1); + + result = base_reactor.run_reactor_event_loop (time); + ACE_ASSERT (result != -1); + + ACE_WFMO_Reactor_Test::check_for_valid_state (reactor, + 0, 0, 0, 0); + + return 0; +} +#else /* !ACE_WIN32 */ +int +ACE_TMAIN (int , ACE_TCHAR *[]) +{ + return 0; +} +#endif /* ACE_WIN32 */ diff --git a/ACE/examples/Reactor/WFMO_Reactor/Talker.cpp b/ACE/examples/Reactor/WFMO_Reactor/Talker.cpp new file mode 100644 index 00000000000..32438088614 --- /dev/null +++ b/ACE/examples/Reactor/WFMO_Reactor/Talker.cpp @@ -0,0 +1,594 @@ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// examples +// +// = FILENAME +// Talker.cpp +// +// = DESCRIPTION +// +// This test application tests a wide range of events that can be +// demultiplexed using various ACE utilities. Events used include +// ^C events, reading from STDIN, vanilla Win32 events, thread +// exits, Reactor notifications, proactive reads, and proactive +// writes. +// +// The proactive I/O events are demultiplexed by the ACE_Proactor. +// The thread exits, notications, and vanilla Win32 events are +// demultiplexed by the ACE_Reactor. To enable a single thread +// to run all these events, the Proactor is integrated with the +// Reactor. +// +// The test application prototypes a simple talk program. Two +// instances of the application connect. Input from either console +// is displayed on the others console also. Because of the evils +// of Win32 STDIN, a separate thread is used to read from STDIN. +// To test the Proactor and Reactor, I/O between the remote +// processes is performed proactively and interactions between the +// STDIN thread and the main thread are performed reactively. +// +// The following description of the test application is in two +// parts. The participants section explains the main components +// involved in the application. The collaboration section +// describes how the partipants interact in response to the +// multiple event types which occur. +// +// The Reactor test application has the following participants: +// +// . Reactor -- The Reactor demultiplexes Win32 "waitable" +// events using WaitForMultipleObjects. +// +// . Proactor -- The proactor initiates and demultiplexes +// overlapped I/O operations. The Proactor registers with the +// Reactor so that a single-thread can demultiplex all +// application events. +// +// . STDIN_Handler -- STDIN_Handler is an Active Object which reads +// from STDIN and forwards the input to the Peer_Handler. This +// runs in a separate thread to make the test more interesting. +// However, STDIN is "waitable", so in general it can be waited on +// by the ACE Reactor, thanks MicroSlush! +// +// . Peer_Handler -- The Peer_Handler connects to another instance +// of test_reactor. It Proactively reads and writes data to the +// peer. When the STDIN_Handler gives it messages, it fowards them +// to the remote peer. When it receives messages from the remote +// peer, it prints the output to the console. +// +// The collaborations of the participants are as follows: +// +// . Initialization +// +// Peer_Handler -- connects to the remote peer. It then begins +// proactively reading from the remote connection. Note that it +// will be notified by the Proactor when a read completes. It +// also registers a notification strategy with message queue so +// that it is notified when the STDIN_Handler posts a message +// onto the queue. +// +// STDIN_Handler -- STDIN_Handler registers a signal handler for +// SIGINT. This just captures the exception so that the kernel +// doesn't kill our process; We want to exit gracefully. It also +// creates an Exit_Hook object which registers the +// STDIN_Handler's thread handle with the Reactor. The +// Exit_Hook will get called back when the STDIN_Handler thread +// exits. After registering these, it blocks reading from STDIN. +// +// Proactor -- is registered with the Reactor. +// +// The main thread of control waits in the Reactor. +// +// . STDIN events -- When the STDIN_Handler thread reads from +// STDIN, it puts the message on Peer_Handler's message queue. It +// then returns to reading from STDIN. +// +// . Message enqueue -- The Reactor thread wakes up and calls +// Peer_Handler::handle_output. The Peer_Handler then tries to +// dequeue a message from its message queue. If it can, the +// message is Proactively sent to the remote peer. Note that the +// Peer_Handler will be notified with this operation is complete. +// The Peer_Handler then falls back into the Reactor event loop. +// +// . Send complete event -- When a proactive send is complete, the +// Proactor is notified by the Reactor. The Proactor, in turn, +// notifies the Peer_Handler. The Peer_Handler then checks for +// more messages from the message queue. If there are any, it +// tries to send them. If there are not, it returns to the +// Reactor event loop. +// +// . Read complete event -- When a proactive read is complete (the +// Peer_Handler initiated a proactive read when it connected to the +// remote peer), the Proactor is notified by the Reactor. The +// Proactor, in turn notifies the Peer_Handler. If the read was +// successful the Peer_Handler just displays the received msg to +// the console and reinvokes a proactive read from the network +// connection. If the read failed (i.e. the remote peer exited), +// the Peer_Handler sets a flag to end the event loop and returns. +// This will cause the application to exit. +// +// . ^C events -- When the user types ^C at the console, the +// STDIN_Handler's signal handler will be called. It does nothing, +// but as a result of the signal, the STDIN_Handler thread will +// exit. +// +// . STDIN_Handler thread exits -- The Exit_Hook will get called +// back from the Reactor. Exit_Hook::handle_signal sets a flag +// to end the event loop and returns. This will cause the +// application to exit. +// +// +// To run example, start an instance of the test with an optional +// local port argument (as the acceptor). Start the other instance +// with -h <hostname> and -p <server port>. Type in either the +// client or server windows and your message should show up in the +// other window. Control C to exit. +// +// = AUTHOR +// Tim Harrison +// Irfan Pyarali +// +// ============================================================================ + +#include "ace/OS_main.h" + +#if defined (ACE_WIN32) + +#include "ace/Reactor.h" +#include "ace/Reactor_Notification_Strategy.h" +#include "ace/WIN32_Proactor.h" +#include "ace/Proactor.h" +#include "ace/SOCK_Connector.h" +#include "ace/SOCK_Acceptor.h" +#include "ace/Get_Opt.h" +#include "ace/Service_Config.h" +#include "ace/Task.h" +#include "ace/OS_NS_unistd.h" + +ACE_RCSID(WFMO_Reactor, Talker, "$Id$") + +typedef ACE_Task<ACE_MT_SYNCH> MT_TASK; + +class Peer_Handler : public MT_TASK, public ACE_Handler +// = TITLE +// Connect to a server. Receive messages from STDIN_Handler +// and forward them to the server using proactive I/O. +{ +public: + // = Initialization methods. + Peer_Handler (int argc, ACE_TCHAR *argv[]); + ~Peer_Handler (void); + + int open (void * =0); + // This method creates the network connection to the remote peer. + // It does blocking connects and accepts depending on whether a + // hostname was specified from the command line. + + virtual void handle_read_stream (const ACE_Asynch_Read_Stream::Result &result); + // This method will be called when an asynchronous read completes on a stream. + // The remote peer has sent us something. If it succeeded, print + // out the message and reinitiate a read. Otherwise, fail. In both + // cases, delete the message sent. + + virtual void handle_write_stream (const ACE_Asynch_Write_Stream::Result &result); + // This method will be called when an asynchronous write completes on a strea_m. + // One of our asynchronous writes to the remote peer has completed. + // Make sure it succeeded and then delete the message. + + virtual ACE_HANDLE handle (void) const; + // Get the I/O handle used by this <handler>. This method will be + // called by the ACE_Asynch_* classes when an ACE_INVALID_HANDLE is + // passed to <open>. + + void handle (ACE_HANDLE); + // Set the ACE_HANDLE value for this Handler. + + virtual int handle_close (ACE_HANDLE, ACE_Reactor_Mask); + // We've been removed from the Reactor. + + virtual int handle_output (ACE_HANDLE fd); + // Called when output events should start. Note that this is + // automatically invoked by the + // <ACE_Reactor_Notificiation_Strategy>. + +private: + ACE_SOCK_Stream stream_; + // Socket that we have connected to the server. + + ACE_Reactor_Notification_Strategy strategy_; + // The strategy object that the reactor uses to notify us when + // something is added to the queue. + + // = Remote peer info. + ACE_TCHAR *host_; + // Name of remote host. + + u_short port_; + // Port number for remote host. + + ACE_Asynch_Read_Stream rd_stream_; + // Read stream + + ACE_Asynch_Write_Stream wr_stream_; + // Write stream + + ACE_Message_Block mb_; + // Message Block for reading from the network +}; + +class STDIN_Handler : public ACE_Task<ACE_NULL_SYNCH> +// = TITLE +// Active Object. Reads from STDIN and passes message blocks to +// the peer handler. +{ +public: + STDIN_Handler (MT_TASK &ph); + // Initialization. + + virtual int open (void * = 0); + // Activate object. + + virtual int close (u_long = 0); + // Shut down. + + int svc (void); + // Thread runs here as an active object. + + int handle_close (ACE_HANDLE, + ACE_Reactor_Mask); + +private: + static void handler (int signum); + // Handle a ^C. (Do nothing, this just illustrates how we can catch + // signals along with the other things). + + void register_thread_exit_hook (void); + // Helper function to register with the Reactor for thread exit. + + virtual int handle_signal (int index, siginfo_t *, ucontext_t *); + // The STDIN thread has exited. This means the user hit ^C. We can + // end the event loop. + + MT_TASK &ph_; + // Send all input to ph_. + + ACE_HANDLE thr_handle_; + // Handle of our thread. +}; + +Peer_Handler::Peer_Handler (int argc, ACE_TCHAR *argv[]) + : strategy_ (ACE_Reactor::instance (), + this, + ACE_Event_Handler::WRITE_MASK), + host_ (0), + port_ (ACE_DEFAULT_SERVER_PORT), + mb_ (BUFSIZ) +{ + // This code sets up the message to notify us when a new message is + // added to the queue. Actually, the queue notifies Reactor which + // then notifies us. + this->msg_queue ()->notification_strategy (&this->strategy_); + + ACE_Get_Opt get_opt (argc, argv, ACE_TEXT("h:p:")); + int c; + + while ((c = get_opt ()) != EOF) + { + switch (c) + { + case 'h': + host_ = get_opt.opt_arg (); + break; + case 'p': + port_ = ACE_OS::atoi (get_opt.opt_arg ()); + break; + } + } +} + +Peer_Handler::~Peer_Handler (void) +{ +} + +// This method creates the network connection to the remote peer. It +// does blocking connects and accepts depending on whether a hostname +// was specified from the command line. + +int +Peer_Handler::open (void *) +{ + if (host_ != 0) // Connector + { + ACE_INET_Addr addr (port_, host_); + ACE_SOCK_Connector connector; + + // Establish connection with server. + if (connector.connect (stream_, addr) == -1) + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "connect"), -1); + + ACE_DEBUG ((LM_DEBUG, "(%t) connected.\n")); + } + else // Acceptor + { + ACE_SOCK_Acceptor acceptor; + ACE_INET_Addr local_addr (port_); + + if ((acceptor.open (local_addr) == -1) || + (acceptor.accept (this->stream_) == -1)) + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "accept failed"), -1); + + ACE_DEBUG ((LM_DEBUG, "(%t) accepted.\n")); + } + + int result = this->rd_stream_.open (*this); + if (result != 0) + return result; + + result = this->wr_stream_.open (*this); + if (result != 0) + return result; + + result = this->rd_stream_.read (this->mb_, + this->mb_.size ()); + return result; +} + +// One of our asynchronous writes to the remote peer has completed. +// Make sure it succeeded and then delete the message. + +void +Peer_Handler::handle_write_stream (const ACE_Asynch_Write_Stream::Result &result) +{ + if (result.bytes_transferred () <= 0) + ACE_DEBUG ((LM_DEBUG, "(%t) %p bytes = %d\n", "Message failed", + result.bytes_transferred ())); + + // This was allocated by the STDIN_Handler, queued, dequeued, passed + // to the proactor, and now passed back to us. + result.message_block ().release (); +} + +// The remote peer has sent us something. If it succeeded, print +// out the message and reinitiate a read. Otherwise, fail. In both +// cases, delete the message sent. + + +void +Peer_Handler::handle_read_stream (const ACE_Asynch_Read_Stream::Result &result) +{ + if (result.bytes_transferred () > 0 && + this->mb_.length () > 0) + { + this->mb_.rd_ptr ()[result.bytes_transferred ()] = '\0'; + // Print out the message received from the server. + ACE_DEBUG ((LM_DEBUG, "%s", this->mb_.rd_ptr ())); + } + else + { + // If a read failed, we will assume it's because the remote peer + // went away. We will end the event loop. Since we're in the + // main thread, we don't need to do a notify. + ACE_Reactor::end_event_loop(); + return; + } + + // Reset pointers + this->mb_.wr_ptr (this->mb_.wr_ptr () - result.bytes_transferred ()); + + // Start off another read + if (this->rd_stream_.read (this->mb_, + this->mb_.size ()) == -1) + ACE_ERROR ((LM_ERROR, "%p Read initiate.\n", "Peer_Handler")); +} + +// This is so the Proactor can get our handle. +ACE_HANDLE +Peer_Handler::handle (void) const +{ + return this->stream_.get_handle (); +} + +void +Peer_Handler::handle (ACE_HANDLE handle) +{ + this->stream_.set_handle (handle); +} + +// We've been removed from the Reactor. +int +Peer_Handler::handle_close (ACE_HANDLE, ACE_Reactor_Mask) +{ + ACE_DEBUG ((LM_DEBUG, "(%t) Peer_Handler closing down\n")); + return 0; +} + +// New stuff added to the message queue. Try to dequeue a message. +int +Peer_Handler::handle_output (ACE_HANDLE) +{ + ACE_Message_Block *mb; + + ACE_Time_Value tv (ACE_Time_Value::zero); + + // Forward the message to the remote peer receiver. + if (this->getq (mb, &tv) != -1) + { + if (this->wr_stream_.write (*mb, + mb->length ()) == -1) + ACE_ERROR_RETURN ((LM_ERROR, "%p Write initiate.\n", "Peer_Handler"), -1); + } + return 0; +} + +void +STDIN_Handler::handler (int signum) +{ + ACE_DEBUG ((LM_DEBUG, "(%t) signal = %S\n", signum)); +} + +STDIN_Handler::STDIN_Handler (MT_TASK &ph) + : ph_ (ph) +{ + // Register for ^C from the console. We just need to catch the + // exception so that the kernel doesn't kill our process. + // Registering this signal handler just tells the kernel that we + // know what we're doing; to leave us alone. + + ACE_OS::signal (SIGINT, (ACE_SignalHandler) STDIN_Handler::handler); +}; + +// Activate object. + +int +STDIN_Handler::open (void *) +{ + if (this->activate (THR_NEW_LWP | THR_DETACHED) == -1) + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "spawn"), -1); + + return 0; +} + +// Shut down. + +int +STDIN_Handler::close (u_long) +{ + ACE_DEBUG ((LM_DEBUG, "(%t) thread is exiting.\n")); + return 0; +} + +// Thread runs here. + +int +STDIN_Handler::svc (void) +{ + this->register_thread_exit_hook (); + + for (;;) + { + ACE_Message_Block *mb = new ACE_Message_Block (BUFSIZ); + + // Read from stdin into mb. + int read_result = ACE_OS::read (ACE_STDIN, + mb->rd_ptr (), + mb->size ()); + + // If read succeeds, put mb to peer handler, else end the loop. + if (read_result > 0) + { + mb->wr_ptr (read_result); + // Note that this call will first enqueue mb onto the peer + // handler's message queue, which will then turn around and + // notify the Reactor via the Notification_Strategy. This + // will subsequently signal the Peer_Handler, which will + // react by calling back to its handle_output() method, + // which dequeues the message and sends it to the peer + // across the network. + this->ph_.putq (mb); + } + else + { + mb->release (); + break; + } + } + + // handle_signal will get called on the main proactor thread since + // we just exited and the main thread is waiting on our thread exit. + return 0; +} + +// Register an exit hook with the reactor. + +void +STDIN_Handler::register_thread_exit_hook (void) +{ + // Get a real handle to our thread. + ACE_Thread_Manager::instance ()->thr_self (this->thr_handle_); + + // Register ourselves to get called back when our thread exits. + + if (ACE_Reactor::instance ()-> + register_handler (this, this->thr_handle_) == -1) + ACE_ERROR ((LM_ERROR, "Exit_Hook Register failed.\n")); +} + +// The STDIN thread has exited. This means the user hit ^C. We can +// end the event loop and delete ourself. + +int +STDIN_Handler::handle_signal (int, siginfo_t *si, ucontext_t *) +{ + if (si != 0) + { + ACE_ASSERT (this->thr_handle_ == si->si_handle_); + ACE_Reactor::end_event_loop (); + } + return 0; +} + +int +STDIN_Handler::handle_close (ACE_HANDLE, + ACE_Reactor_Mask) +{ + delete this; + return 0; +} + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + // Let the proactor know that it will be used with Reactor + // Create specific proactor + ACE_WIN32_Proactor win32_proactor (0, 1); + // Get the interface proactor + ACE_Proactor proactor (&win32_proactor); + // Put it as the instance. + ACE_Proactor::instance (&proactor); + + // Open handler for remote peer communications this will run from + // the main thread. + Peer_Handler peer_handler (argc, argv); + + if (peer_handler.open () == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p open failed, errno = %d.\n", + "peer_handler", errno), 0); + + // Open active object for reading from stdin. + STDIN_Handler *stdin_handler = + new STDIN_Handler (peer_handler); + + // Spawn thread. + if (stdin_handler->open () == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p open failed, errno = %d.\n", + "stdin_handler", errno), 0); + + // Register proactor with Reactor so that we can demultiplex + // "waitable" events and I/O operations from a single thread. + if (ACE_Reactor::instance ()->register_handler + (ACE_Proactor::instance ()->implementation ()) != 0) + ACE_ERROR_RETURN ((LM_ERROR, "%p failed to register Proactor.\n", + argv[0]), -1); + + // Run main event demultiplexor. + ACE_Reactor::run_event_loop (); + + // Remove proactor with Reactor. + if (ACE_Reactor::instance ()->remove_handler + (ACE_Proactor::instance ()->implementation (), ACE_Event_Handler::DONT_CALL) != 0) + ACE_ERROR_RETURN ((LM_ERROR, "%p failed to register Proactor.\n", + argv[0]), -1); + + return 0; +} +#else /* !ACE_WIN32 */ +int +ACE_TMAIN (int , ACE_TCHAR *[]) +{ + return 0; +} +#endif /* ACE_WIN32 */ diff --git a/ACE/examples/Reactor/WFMO_Reactor/Timeouts.cpp b/ACE/examples/Reactor/WFMO_Reactor/Timeouts.cpp new file mode 100644 index 00000000000..8cc37a940bc --- /dev/null +++ b/ACE/examples/Reactor/WFMO_Reactor/Timeouts.cpp @@ -0,0 +1,83 @@ +// $Id$ +// +// ============================================================================ +// +// = LIBRARY +// examples +// +// = FILENAME +// Timeouts.cpp +// +// = DESCRIPTION +// +// This example application shows how to write Reactor event +// loops that handle events for some fixed amount of time. +// +// Run this example (without arguments) to see the timers +// expire. The order should be: +// +// foo, bar, foo, bar, foo, foo, bar, foo, bar, foo +// +// = AUTHOR +// Tim Harrison +// Irfan Pyarali +// +// ============================================================================ + +#include "ace/Reactor.h" +#include "ace/Service_Config.h" +#include "ace/OS_main.h" + +ACE_RCSID(WFMO_Reactor, Timeouts, "$Id$") + +class Timeout_Handler : public ACE_Event_Handler +// = TITLE +// Generic timeout handler. +{ +public: + Timeout_Handler (void) + : count_ (0) {} + + virtual int handle_timeout (const ACE_Time_Value &tv, + const void *arg) + // Print out when timeouts occur. + { + ACE_UNUSED_ARG(tv); + ACE_DEBUG ((LM_DEBUG, + "%d timeout occurred for %s.\n", + ++count_, + (char *) arg)); + return 0; + } + +private: + int count_; +}; + +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + Timeout_Handler handler; + + // Register a 3 second timer. + ACE_Time_Value bar_tv (3); + ACE_Reactor::instance ()->schedule_timer (&handler, + (void *) "Bar", + bar_tv, + bar_tv); + + // Register a 2 second timer. + ACE_Time_Value foo_tv (2); + ACE_Reactor::instance ()->schedule_timer (&handler, + (void *) "Foo", + foo_tv, + foo_tv); + // Handle events for 12 seconds. + ACE_Time_Value run_time (12); + if (ACE_Reactor::run_event_loop(run_time) == -1) + ACE_ERROR_RETURN ((LM_ERROR, "%p.\n", "main"), -1); + + ACE_Reactor::instance ()->cancel_timer(&handler); + + return 0; +} diff --git a/ACE/examples/Reactor/WFMO_Reactor/WFMO_Reactor.mpc b/ACE/examples/Reactor/WFMO_Reactor/WFMO_Reactor.mpc new file mode 100644 index 00000000000..eec632ee696 --- /dev/null +++ b/ACE/examples/Reactor/WFMO_Reactor/WFMO_Reactor.mpc @@ -0,0 +1,118 @@ +// -*- MPC -*- +// $Id$ + +project(*Abandoned): aceexe, wfmo { + exename = abandoned + Source_Files { + Abandoned.cpp + } +} + +project(*APC): aceexe, wfmo { + avoids += wince + exename = apc + Source_Files { + APC.cpp + } +} + +project(*Console_Input): aceexe, wfmo { + exename = console_input + Source_Files { + Console_Input.cpp + } +} + +project(*Directory_Changes): aceexe, wfmo { + exename = directory_changes + Source_Files { + Directory_Changes.cpp + } +} + +project(*Exceptions): aceexe, wfmo { + exename = exceptions + Source_Files { + Exceptions.cpp + } +} + +project(*Handle_Close): aceexe, wfmo { + exename = handle_close + Source_Files { + Handle_Close.cpp + } +} + +project(*Multithreading): aceexe, wfmo { + exename = multithreading + Source_Files { + Multithreading.cpp + } +} + +project(*Network_Events): aceexe, wfmo { + exename = network_events + Source_Files { + Network_Events.cpp + } +} + +project(*Prerun_State_Changes): aceexe, wfmo { + exename = prerun_state_changes + Source_Files { + Prerun_State_Changes.cpp + } +} + +project(*Registration): aceexe, wfmo { + exename = registration + Source_Files { + Registration.cpp + } +} + +project(*Registry_Changes): aceexe, wfmo { + avoids += ace_for_tao wince + exename = registry_changes + Source_Files { + Registry_Changes.cpp + } +} + +project(*Removals): aceexe, wfmo { + exename = removals + Source_Files { + Removals.cpp + } +} + +project(*Suspended_Removals): aceexe, wfmo { + exename = suspended_removals + Source_Files { + Suspended_Removals.cpp + } +} + +project(*Talker): aceexe, wfmo { + avoids += ace_for_tao wince + exename = talker + Source_Files { + Talker.cpp + } +} + +project(*Timeouts): aceexe, wfmo { + exename = timeouts + Source_Files { + Timeouts.cpp + } +} + +project(*Window_Messages): aceexe, wfmo { + avoids += ace_for_tao wince + exename = window_messages + Source_Files { + Window_Messages.cpp + } +} diff --git a/ACE/examples/Reactor/WFMO_Reactor/Window_Messages.cpp b/ACE/examples/Reactor/WFMO_Reactor/Window_Messages.cpp new file mode 100644 index 00000000000..f5a1994168c --- /dev/null +++ b/ACE/examples/Reactor/WFMO_Reactor/Window_Messages.cpp @@ -0,0 +1,100 @@ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// examples +// +// = FILENAME +// Window_Messages.cpp +// +// = DESCRIPTION +// +// Tests the Msg_WFMO_Reactor's ability to handle regular events +// and window messages. +// +// = AUTHOR +// +// Irfan Pyarali <irfan@cs.wustl.edu> +// +// ============================================================================ + +#include "ace/OS_main.h" + +#if defined (ACE_WIN32) + +#include "ace/Msg_WFMO_Reactor.h" +#include "ace/Reactor.h" +#include "ace/Auto_Ptr.h" +#include "ace/Auto_Event.h" + +ACE_RCSID(WFMO_Reactor, Window_Messages, "$Id$") + +class Event_Handler : public ACE_Event_Handler +{ +public: + int handle_signal (int signum, siginfo_t * = 0, ucontext_t * = 0); + + ACE_Auto_Event handle_; + int iterations_; +}; + +int +Event_Handler::handle_signal (int, siginfo_t *, ucontext_t *) +{ + --this->iterations_; + + if (this->iterations_ == 0) + ACE_Reactor::end_event_loop (); + + return 0; +} + +static Event_Handler *global_event_handler; + +void WINAPI +timer_callback (HWND, + UINT, + UINT, + DWORD dwTime) +{ + ACE_DEBUG ((LM_DEBUG, "(%t) timeout occured @ %u\n", dwTime)); + + global_event_handler->handle_.signal (); +} + +int +ACE_TMAIN (int, ACE_TCHAR*[]) +{ + // Manage memory automagically. + ACE_Reactor_Impl *impl = new ACE_Msg_WFMO_Reactor; + auto_ptr<ACE_Reactor> reactor (new ACE_Reactor (impl, 1)); + ACE_Reactor::instance (reactor.get ()); + + Event_Handler event_handler; + global_event_handler = &event_handler; + + event_handler.iterations_ = 5; + int result = ACE_Reactor::instance ()->register_handler (&event_handler, + event_handler.handle_.handle ()); + ACE_ASSERT (result == 0); + + ACE_Time_Value timeout (1); + result = ::SetTimer (NULL, // handle of window for timer messages + 0, // timer identifier + timeout.msec (), // time-out value + (TIMERPROC) &timer_callback // address of timer procedure + ); + ACE_ASSERT (result != 0); + + ACE_Reactor::run_event_loop (); + + return 0; +} +#else /* !ACE_WIN32 */ +int +ACE_TMAIN (int , ACE_TCHAR *[]) +{ + return 0; +} +#endif /* ACE_WIN32 */ diff --git a/ACE/examples/Reactor/WFMO_Reactor/run_test.pl b/ACE/examples/Reactor/WFMO_Reactor/run_test.pl new file mode 100755 index 00000000000..cc445c64043 --- /dev/null +++ b/ACE/examples/Reactor/WFMO_Reactor/run_test.pl @@ -0,0 +1,68 @@ +eval '(exit $?0)' && eval 'exec perl -S $0 ${1+"$@"}' + & eval 'exec perl -S $0 $argv:q' + if 0; + +# $Id$ +# -*- perl -*- + +use lib '../../../bin'; +use PerlACE::Run_Test; + +# +# These tests only run on Win32 +# +if ($^O ne "MSWin32") +{ + exit; +} + +$test_timeout = 60; + +@tests = + ( + "Abandoned", + "APC", +# "Console_Input", # This test is interactive + "Directory_Changes", + "Exceptions", + "Handle_Close", + "Multithreading", +# "Network_Events", # This test is interactive + "Prerun_State_Changes", + "Registration", + "Registry_Changes", + "Removals", + "Suspended_Removals", +# "Talker", # This test is interactive + "Timeouts", + "Window_Messages", + ); + +for $test (@tests) +{ + print STDOUT "\n________________________________________\n"; + print STDOUT "\nStarting test \"$test\""; + print STDOUT "\n________________________________________\n\n"; + + $test_process = new PerlACE::Process ($test); + + if (! -x $test_process->Executable ()) { + print STDERR "Error: " . $test_process->Executable () . + " does not exist or is not runnable\n"; + } + else + { + $test_process->Spawn (); + $test_result = $test_process->WaitKill ($test_timeout); + + if ($test_result != 0) + { + print STDERR "\n________________________________________\n"; + print STDERR "\nERROR: \"$test\" returned $test_result"; + print STDERR "\n________________________________________\n"; + } + } + print STDOUT "\n________________________________________\n"; + print STDOUT "\n\"$test\" completed"; + print STDOUT "\n________________________________________\n"; +} diff --git a/ACE/examples/Registry/Makefile.am b/ACE/examples/Registry/Makefile.am new file mode 100644 index 00000000000..1e02e33abb2 --- /dev/null +++ b/ACE/examples/Registry/Makefile.am @@ -0,0 +1,60 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +ACE_BUILDDIR = $(top_builddir) +ACE_ROOT = $(top_srcdir) + +noinst_PROGRAMS = + +## Makefile.Registry_Iterator.am + +if BUILD_WINREGISTRY +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS += iterator + +iterator_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +iterator_SOURCES = \ + test_registry_iterator.cpp + +iterator_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO +endif BUILD_WINREGISTRY + +## Makefile.Registry_Update.am + +if BUILD_WINREGISTRY +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS += update + +update_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +update_SOURCES = \ + test_registry_update.cpp + +update_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO +endif BUILD_WINREGISTRY + +## Clean up template repositories, etc. +clean-local: + -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.* + -rm -f gcctemp.c gcctemp so_locations *.ics + -rm -rf cxx_repository ptrepository ti_files + -rm -rf templateregistry ir.out + -rm -rf ptrepository SunWS_cache Templates.DB diff --git a/ACE/examples/Registry/Registry.mpc b/ACE/examples/Registry/Registry.mpc new file mode 100644 index 00000000000..e2e048f02c0 --- /dev/null +++ b/ACE/examples/Registry/Registry.mpc @@ -0,0 +1,17 @@ +// -*- MPC -*- +// $Id$ + +project(*iterator) : aceexe, winregistry { + exename = iterator + + Source_Files { + test_registry_iterator.cpp + } +} +project(*update) : aceexe, winregistry { + exename = update + + Source_Files { + test_registry_update.cpp + } +} diff --git a/ACE/examples/Registry/test_registry_iterator.cpp b/ACE/examples/Registry/test_registry_iterator.cpp new file mode 100644 index 00000000000..e24a418ca07 --- /dev/null +++ b/ACE/examples/Registry/test_registry_iterator.cpp @@ -0,0 +1,146 @@ +// $Id$ + +// This example uses the ACE_Registry class to iterator through the +// entries in the predefined registries. The host of iteration can be +// varied through argv[1]. If no host is specified the local host is +// used. This is very similar to how regedt32 starts up. +// +// This examples points the cool iterators in ACE_Registry + +#include "ace/OS_main.h" + +#if defined (ACE_WIN32) + +#include "ace/Registry.h" + +// FUZZ: disable check_for_streams_include +#include "ace/streams.h" + +ACE_RCSID(Registry, test_registry_iterator, "$Id$") + +// Indentation while printing names +static const u_long INDENTATION_LEVEL = 3; + +// Prototypes +static int print_naming_context (ACE_Registry::Naming_Context &naming_context, + u_long indentation); +static void print_object (const ACE_TString &name, + u_long indentation); +static void print_context (ACE_Registry::Naming_Context &parent, + const ACE_TString &name, + u_long indentation); +static void indent (u_long indentation); + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + int result; + ACE_Registry::Naming_Context naming_context; + + // Connect to a predefined naming context + result = ACE_Predefined_Naming_Contexts::connect (naming_context, + HKEY_LOCAL_MACHINE, + // HKEY_CLASSES_ROOT, + // HKEY_USERS, + // HKEY_CURRENT_USER, + argc == 2 ? argv[1] : 0); + + if (result != 0) + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "ACE_Predefined_Naming_Contexts::connect failed"), -1); + + // Print contents of naming context + result = ::print_naming_context (naming_context, 0); + if (result != 0) + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "print_naming_context failed"), -1); + + return 0; +} + + +// Print contents of <naming_context> +static int +print_naming_context (ACE_Registry::Naming_Context &naming_context, + u_long indentation) +{ + ACE_Registry::Binding_List list; + + // Get the list of all entries + int result = naming_context.list (list); + if (result != 0) + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "ACE_Registry::Naming_Context::list"), -1); + + // Iterator through all entries + for (ACE_Registry::Binding_List::iterator i = list.begin (); + i != list.end (); + ++i) + { + // Yeeesss! STL rules! + ACE_Registry::Binding &binding = *i; + + if (binding.type () == ACE_Registry::OBJECT) + // If object + ::print_object (binding.name (), + indentation); + else + // If context + ::print_context (naming_context, + binding.name (), + indentation); + } + return 0; +} + + +// Print an object with <name> +static void +print_object (const ACE_TString &name, + u_long indentation) +{ + // Set indentation + ::indent (indentation); + cout << name << endl; +} + + +// Print an context with <name> and <parent> +static void +print_context (ACE_Registry::Naming_Context &parent, + const ACE_TString &name, + u_long indentation) +{ + // Set indentation + indent (indentation); + cout << name << endl; + + ACE_Registry::Naming_Context child_context; + // Find child context + int result = parent.resolve_context (name, + child_context, + KEY_READ); + if (result != 0) + ACE_ERROR ((LM_ERROR, "%s %s\n", "ACE_Registry::Naming_Context::resolve_context failed for:", name.c_str ())); + else + { + // Print contents of the child + result = ::print_naming_context (child_context, + indentation + INDENTATION_LEVEL); + if (result != 0) + ACE_ERROR ((LM_ERROR, "%p\n", "print_naming_context failed")); + } +} + + +// Pretty formating +static void +indent (u_long indentation) +{ + for (; indentation > 0; indentation--) + cout << " "; +} +#else /* !ACE_WIN32 */ +int +ACE_TMAIN (int , ACE_TCHAR *[]) +{ + return 0; +} +#endif /* ACE_WIN32 */ diff --git a/ACE/examples/Registry/test_registry_update.cpp b/ACE/examples/Registry/test_registry_update.cpp new file mode 100644 index 00000000000..443f1a766ff --- /dev/null +++ b/ACE/examples/Registry/test_registry_update.cpp @@ -0,0 +1,161 @@ +// $Id$ + +// Suppose this application belonged to AcmeSoft. AcmeSoft wants to +// keep track of the number of times this application is +// executed. They want two counters: one counts the number of +// executions per machine, the other keeps track of the number of +// executions per user. +// +// This application uses the ACE_Registry class to create and update +// entries in the LOCAL_MACHINE and CURRENT_USER predefined registries +// to store the counters. +// +// Note that this application will not work with remote registries +// if used with the CURRENT_USER predefined registry. + +#include "ace/OS_main.h" + +#if defined (ACE_WIN32) + +#include "ace/Registry.h" + +// FUZZ: disable check_for_streams_include +#include "ace/streams.h" + +ACE_RCSID(Registry, test_registry_update, "$Id$") + +// Name for application's naming context +static ACE_Registry::Name application_context_name; + +// Name for instance counter. +static ACE_Registry::Name counter_name; + +// Protypes +static int update_counter (HKEY predefined, + u_long ¤t_counter); +static void setup_names (); + +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + int result; + u_long current_counter = 0; + + // initialize name + setup_names (); + + // Update counter per user + result = ::update_counter (HKEY_CURRENT_USER, + current_counter); + if (result == 0) + { + cout << "User counter: " << current_counter << endl; + + // Update counter per machine + result = ::update_counter (HKEY_LOCAL_MACHINE, + current_counter); + if (result == 0) + cout << "Machine counter: " << current_counter << endl; + } + + if (result != 0) + ACE_DEBUG ((LM_DEBUG, "test failed\n")); + else + ACE_DEBUG ((LM_DEBUG, "test succeeded\n")); + + return 0; +} + +static int +update_counter (HKEY predefined, + u_long ¤t_counter) +{ + int result; + ACE_Registry::Naming_Context parent_context; + ACE_Registry::Naming_Context application_context; + + // Connect to predefined entry + result = ACE_Predefined_Naming_Contexts::connect (parent_context, + predefined); + if (result != 0) + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "ACE_Predefined_Naming_Contexts::connect failed"), -1); + + // Find application context name + result = parent_context.resolve_context (application_context_name, + application_context); + + if (result != 0) + // Failed to find: create a new context + result = parent_context.bind_new_context (application_context_name, + application_context); + + if (result != 0) + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "ACE_Registry::Naming_Contexts::bind/resolve_context failed"), -1); + + // Counter + u_long counter = 0; + // Represent counter as an ACE_Registry::Object + ACE_Registry::Object object ((void *) &counter, + sizeof counter, + REG_DWORD); + // Find counter + result = application_context.resolve (counter_name, + object); + + if (result != 0) + // Failed to find: create new binding for object + { + counter = 1; + result = application_context.bind (counter_name, + object); + } + else + // Counter was found + { + // increment counter + counter++; + // Update + result = application_context.rebind (counter_name, + object); + } + + if (result != 0) + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "ACE_Registry::Naming_Contexts::bind/resolve failed"), -1); + else + current_counter = counter; + + return 0; +} + + +static void +setup_names () +{ + // Stupid implementation of STL is broken + /* + ::application_context_name.reserve (4); + ::application_context_name [0].id_ = ACE_TEXT ("Software"); + ::application_context_name [1].id_ = ACE_TEXT ("AcmeSoft"); + ::application_context_name [2].id_ = ACE_TEXT ("AcmeApplication"); + ::application_context_name [3].id_ = ACE_TEXT ("1.0"); + + ::counter_name.reserve (1); + ::counter_name [0].id_ = ACE_TEXT ("Instance Counter"); + */ + + ACE_Registry::Name_Component component; + + component.id_ = ACE_TEXT ("Software"), ::application_context_name.insert (component); + component.id_ = ACE_TEXT ("AcmeSoft"), ::application_context_name.insert (component); + component.id_ = ACE_TEXT ("AcmeApplication"), ::application_context_name.insert (component); + component.id_ = ACE_TEXT ("1.0"), ::application_context_name.insert (component); + + component.id_ = ACE_TEXT ("Instance Counter"), ::counter_name.insert (component); +} +#else /* !ACE_WIN32 */ +int +ACE_TMAIN (int , ACE_TCHAR *[]) +{ + return 0; +} +#endif /* ACE_WIN32 */ diff --git a/ACE/examples/Service_Configurator/IPC-tests/Makefile.am b/ACE/examples/Service_Configurator/IPC-tests/Makefile.am new file mode 100644 index 00000000000..0a99932ce34 --- /dev/null +++ b/ACE/examples/Service_Configurator/IPC-tests/Makefile.am @@ -0,0 +1,14 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +SUBDIRS = \ + client \ + server + diff --git a/ACE/examples/Service_Configurator/IPC-tests/README b/ACE/examples/Service_Configurator/IPC-tests/README new file mode 100644 index 00000000000..6f491296af7 --- /dev/null +++ b/ACE/examples/Service_Configurator/IPC-tests/README @@ -0,0 +1,125 @@ +This file describes how to invoke the tests in the +$ACE_ROOT/examples/Service_Configurator/IPC-test/{client,server} +directories. These tests exercise all of the ACE IPC SAP +communication mechanisms, the Reactor event demultiplexor, and the +Service Configurator dynamic service configuration framework. To gain +a deeper understanding of what is going on, you should read the the +Wrapper Facade, Reactor, and Component Configurator patterns in POSA2 +<http://www.cs.wustl.edu/~schmidt/POSA/> and check out the following +papers on the ACE framework components: + +http://www.cs.wustl.edu/~schmidt/PDF/IPC_SAP-92.pdf +http://www.cs.wustl.edu/~schmidt/PDF/Reactor1-93.pdf +http://www.cs.wustl.edu/~schmidt/PDF/Reactor2-93.pdf +http://www.cs.wustl.edu/~schmidt/PDF/reactor-rules.pdf +http://www.cs.wustl.edu/~schmidt/PDF/Svc-Conf.pdf + +The key to running these client/server tests is to understand the +purpose of the svc.conf file located in the +$ACE_ROOT/examples/Service_Configurator/IPC-test/server/ directory. +This file contains a list of services that may be dynamically +configured into a the address space of a network daemon process. If +you look at the example svc.conf file included in the tests you'll see +that some entries are commented out (the comment symbol is the '#', +which is an "ignore until end-of-line comment" with the same semantics +as the UNIX C and Bourne shells). Before reading any further, take a +look at this svc.conf file with your favorite editor or file browser. + +There are several types of entries in this file. The two most +important are the lines beginning with the keywords "static" and +"dynamic". For example, the first non-commented line says: + +static ACE_Service_Manager "-d -p 3911" + +When this line is parsed at startup time by the Service Configurator +object in the ./server_test executable, it causes the pre-configured +Svc_Manager object to be initialized with an "argv" argument of "-d -p +3911." This results in TCP port 3911 being created to listen +connection requests from clients. To see how this works do the +following: + +1. Comment out all the other lines except + + static Svc_Manager "-d -p 3911" + + in the svc.conf file + +2. Start up the ./server_test executable in one window, as follows: + + % ./server_test -d + +3. Make another window on the *same* host and cd to the ./client/ + directory + +4. Run the ./remote_service_directory_test program as follows: + + % ./remote_service_directory_test -p 3911 -h localhost + +If everything has been compiled and initialized correctly, you should +get the following message: + + Svc_Manager 3911/tcp # lists all services in the daemon + +This message is telling you that the Svc_Manager is currently the only +service that is active within the ./server_test program. To configure +and activate another service dynamically, perform the following steps: + +1. *Without* shutting down the ./server_test program, edit the svc.conf + file. Comment out the Svc_Manager line by adding a '#' at the + front, i.e.: + + # static Svc_Manager "-d -p 3911" + + and then uncomment the second line: + + dynamic Remote_Brdcast Service_Object * ./IPC_Tests_Server:remote_broadcast "-p 10001" + +2. If you're running on an OS platform that supports SIGHUP, send the + SIGHUP signal to the process running the ./server_test program. + This will cause the ./server_test program to reconfigure itself + based on the new contents of the svc.conf file. Not every platform + supports SIGHUP. However, the remote_service_directory_test in + ./client/ can be used to reconfigure services, e.g., by passing it + parameters as follows: + + % ./remote_service_directory_test -p 3911 -h localhost -r + + The '-r' flag instructs the server to reconfigure itself. + + After reconfiguration, you'll now have a second active service in + the address space of the ./server_test daemon. To see this, rerun + the remote_service_directory_test command, e.g.: + + % ./remote_service_directory_test -p 3911 -h localhost + + You should now see the following output: + + Svc_Manager 3911/tcp # lists all services in the daemon + Remote_Brdcast 10001/udp # tests broadcasting + + which indicates that the remote broadcast service is now active. + +3. To test the remote broadcast service, run the following program + in the ./client/ directory: + + % ./broadcast_client_test -p 10001 + + This should cause the window running the ./server_test to + display the following output: + + received broadcast datagram from host spare.ics.uci.edu + ---------------------------------------- + testing socket broadcast service + ---------------------------------------- + +If you want to run other tests, using other configurations, simply +uncomment the appropriate lines in the svc.conf file and experiment +with the corresponding test drivers in the ./client/ directory. All +the source code is available so once you get the hang of what is +happening, you might want to take a look at how it is all implemented. +You may be surprised at how much of the ACE framework code is +reused for each different service. Moreover, writing a new service is +often simply a matter of copying an existing file and filling in the +behavior of some of the methods (e.g., the handle_input() method and +the init() method). + diff --git a/ACE/examples/Service_Configurator/IPC-tests/client/.cvsignore b/ACE/examples/Service_Configurator/IPC-tests/client/.cvsignore new file mode 100644 index 00000000000..121d4de020f --- /dev/null +++ b/ACE/examples/Service_Configurator/IPC-tests/client/.cvsignore @@ -0,0 +1,10 @@ +local_dgram_test +local_fifo_test +local_pipe_test +local_spipe_test +local_stream_test +remote_broadcast_test +remote_dgram_test +remote_service_directory_test +remote_stream_test +remote_thr_stream_test diff --git a/ACE/examples/Service_Configurator/IPC-tests/client/Makefile.am b/ACE/examples/Service_Configurator/IPC-tests/client/Makefile.am new file mode 100644 index 00000000000..b6dd5a3d7b8 --- /dev/null +++ b/ACE/examples/Service_Configurator/IPC-tests/client/Makefile.am @@ -0,0 +1,180 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +ACE_BUILDDIR = $(top_builddir) +ACE_ROOT = $(top_srcdir) + +noinst_PROGRAMS = + +## Makefile.Svc_Cfg_IPC_Client_Bcast.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS += remote_broadcast_test + +remote_broadcast_test_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +remote_broadcast_test_SOURCES = \ + broadcast_client_test.cpp + +remote_broadcast_test_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Makefile.Svc_Cfg_IPC_Client_Loc_Dgram.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS += local_dgram_test + +local_dgram_test_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +local_dgram_test_SOURCES = \ + local_dgram_client_test.cpp + +local_dgram_test_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Makefile.Svc_Cfg_IPC_Client_Loc_Fifo.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS += local_fifo_test + +local_fifo_test_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +local_fifo_test_SOURCES = \ + local_fifo_client_test.cpp + +local_fifo_test_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Makefile.Svc_Cfg_IPC_Client_Loc_Pipe.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS += local_pipe_test + +local_pipe_test_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +local_pipe_test_SOURCES = \ + local_pipe_client_test.cpp + +local_pipe_test_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Makefile.Svc_Cfg_IPC_Client_Loc_Spipe.am +noinst_PROGRAMS += local_spipe_test + +local_spipe_test_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +local_spipe_test_SOURCES = \ + local_spipe_client_test.cpp + +local_spipe_test_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Svc_Cfg_IPC_Client_Loc_Stream.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS += local_stream_test + +local_stream_test_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +local_stream_test_SOURCES = \ + local_stream_client_test.cpp + +local_stream_test_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Makefile.Svc_Cfg_IPC_Client_Rem_Dgram.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS += remote_dgram_test + +remote_dgram_test_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +remote_dgram_test_SOURCES = \ + remote_dgram_client_test.cpp + +remote_dgram_test_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Makefile.Svc_Cfg_IPC_Client_Rem_Stream.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS += remote_stream_test + +remote_stream_test_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +remote_stream_test_SOURCES = \ + remote_stream_client_test.cpp + +remote_stream_test_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Makefile.Svc_Cfg_IPC_Client_Rem_Svc_Dir.am +noinst_PROGRAMS += remote_service_directory_test + +remote_service_directory_test_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +remote_service_directory_test_SOURCES = \ + remote_service_directory_test.cpp + +remote_service_directory_test_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Svc_Cfg_IPC_Client_Rem_Thr_Stream.am +noinst_PROGRAMS += remote_thr_stream_test + +remote_thr_stream_test_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +remote_thr_stream_test_SOURCES = \ + remote_thr_stream_client_test.cpp + +remote_thr_stream_test_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Clean up template repositories, etc. +clean-local: + -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.* + -rm -f gcctemp.c gcctemp so_locations *.ics + -rm -rf cxx_repository ptrepository ti_files + -rm -rf templateregistry ir.out + -rm -rf ptrepository SunWS_cache Templates.DB diff --git a/ACE/examples/Service_Configurator/IPC-tests/client/Svc_Cfg_IPC_Client.mpc b/ACE/examples/Service_Configurator/IPC-tests/client/Svc_Cfg_IPC_Client.mpc new file mode 100644 index 00000000000..6876c4aac4d --- /dev/null +++ b/ACE/examples/Service_Configurator/IPC-tests/client/Svc_Cfg_IPC_Client.mpc @@ -0,0 +1,70 @@ +// -*- MPC -*- +// $Id$ + +project(*loc dgram) : aceexe { + avoids += ace_for_tao + exename = local_dgram_test + Source_Files { + local_dgram_client_test.cpp + } +} +project(*loc fifo) : aceexe { + avoids += ace_for_tao + exename = local_fifo_test + Source_Files { + local_fifo_client_test.cpp + } +} +project(*loc pipe) : aceexe { + avoids += ace_for_tao + exename = local_pipe_test + Source_Files { + local_pipe_client_test.cpp + } +} +project(*loc spipe) : aceexe { + exename = local_spipe_test + Source_Files { + local_spipe_client_test.cpp + } +} +project(*loc stream) : aceexe { + avoids += ace_for_tao + exename = local_stream_test + Source_Files { + local_stream_client_test.cpp + } +} +project(*rem dgram) : aceexe { + avoids += ace_for_tao + exename = remote_dgram_test + Source_Files { + remote_dgram_client_test.cpp + } +} +project(*rem svc dir) : aceexe { + exename = remote_service_directory_test + Source_Files { + remote_service_directory_test.cpp + } +} +project(*rem stream) : aceexe { + avoids += ace_for_tao + exename = remote_stream_test + Source_Files { + remote_stream_client_test.cpp + } +} +project(*rem thr_stream) : aceexe { + exename = remote_thr_stream_test + Source_Files { + remote_thr_stream_client_test.cpp + } +} +project(*bcast) : aceexe { + avoids += ace_for_tao + exename = remote_broadcast_test + Source_Files { + broadcast_client_test.cpp + } +} diff --git a/ACE/examples/Service_Configurator/IPC-tests/client/broadcast_client_test.cpp b/ACE/examples/Service_Configurator/IPC-tests/client/broadcast_client_test.cpp new file mode 100644 index 00000000000..4cbb964cd74 --- /dev/null +++ b/ACE/examples/Service_Configurator/IPC-tests/client/broadcast_client_test.cpp @@ -0,0 +1,62 @@ +// $Id$ + +// Tests out the broadcast service of the +// Internet domain IPC-SAP dgram abstraction. + +#include "ace/OS_main.h" +#include "ace/OS_NS_stdio.h" +#include "ace/OS_NS_string.h" +#include "ace/OS_NS_stdlib.h" +#include "ace/INET_Addr.h" +#include "ace/SOCK_Dgram_Bcast.h" +#include "ace/Get_Opt.h" +#include "ace/Log_Msg.h" + +ACE_RCSID(client, broadcast_client_test, "$Id$") + +/* Name of the program. */ +static ACE_TCHAR *program_name; + +/* Port number to use. */ +static unsigned short broadcast_port_number = ACE_DEFAULT_BROADCAST_PORT; + +static void +print_usage_and_die (void) +{ + ACE_OS::fprintf (stderr, "usage: %s [-p broadcast portnum]\n", + program_name); + ACE_OS::exit (1); +} + +void +parse_args (int argc, ACE_TCHAR *argv[]) +{ + ACE_Get_Opt get_opt (argc, argv, ACE_TEXT("p:")); + + for (int c; (c = get_opt ()) != -1; ) + switch (c) + { + case 'p': + broadcast_port_number = ACE_OS::atoi (get_opt.opt_arg ()); + break; + default: + print_usage_and_die (); + break; + } +} + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + program_name = argv[0]; + parse_args (argc, argv); + + ACE_SOCK_Dgram_Bcast sd (ACE_Addr::sap_any); + + static char buf[] = "testing socket broadcast service"; + + if (sd.send (buf, ACE_OS::strlen (buf), broadcast_port_number) == -1) + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "can't send broadcast"), -1); + + return 0; +} diff --git a/ACE/examples/Service_Configurator/IPC-tests/client/local_data b/ACE/examples/Service_Configurator/IPC-tests/client/local_data new file mode 100644 index 00000000000..1faba1b8091 --- /dev/null +++ b/ACE/examples/Service_Configurator/IPC-tests/client/local_data @@ -0,0 +1,22 @@ +locallocallocallocallocallocallocallocal +locallocallocallocallocallocallocallocal +locallocallocallocallocallocallocallocal +locallocallocallocallocallocallocallocal +locallocallocallocallocallocallocallocal +locallocallocallocallocallocallocallocal +locallocallocallocallocallocallocallocal +locallocallocallocallocallocallocallocal +locallocallocallocallocallocallocallocal +locallocallocallocallocallocallocallocal +locallocallocallocallocallocallocallocal +locallocallocallocallocallocallocallocal +locallocallocallocallocallocallocallocal +locallocallocallocallocallocallocallocal +locallocallocallocallocallocallocallocal +locallocallocallocallocallocallocallocal +locallocallocallocallocallocallocallocal +locallocallocallocallocallocallocallocal +locallocallocallocallocallocallocallocal +locallocallocallocallocallocallocallocal +locallocallocallocallocallocallocallocal +locallocallocallocallocallocallocallocal diff --git a/ACE/examples/Service_Configurator/IPC-tests/client/local_dgram_client_test.cpp b/ACE/examples/Service_Configurator/IPC-tests/client/local_dgram_client_test.cpp new file mode 100644 index 00000000000..3f8ed3db866 --- /dev/null +++ b/ACE/examples/Service_Configurator/IPC-tests/client/local_dgram_client_test.cpp @@ -0,0 +1,117 @@ +// $Id$ + +// Tests out the UNIX domain IPC-SAP abstraction. + +#include "ace/OS_main.h" +#include "ace/LSOCK_CODgram.h" +#include "ace/LSOCK_Dgram.h" +#include "ace/UNIX_Addr.h" +#include "ace/Get_Opt.h" +#include "ace/OS_NS_string.h" +#include "ace/OS_NS_stdio.h" +#include "ace/OS_NS_stdlib.h" +#include "ace/OS_NS_unistd.h" +#include "ace/OS_NS_fcntl.h" + +ACE_RCSID(client, local_dgram_client_test, "$Id$") + +#if defined (ACE_HAS_MSG) && !defined (ACE_LACKS_UNIX_DOMAIN_SOCKETS) +// Name of the program. +static ACE_TCHAR *program_name; + +// Name of rendezvous point. +static const ACE_TCHAR *rendezvous_codgram = ACE_TEXT ("/tmp/foo_codgram"); +static const ACE_TCHAR *rendezvous_dgram = ACE_TEXT ("/tmp/foo_dgram"); + +// Name of file to send. +static const ACE_TCHAR *file_name = ACE_TEXT ("local_data"); + +static void +print_usage_and_die (void) +{ + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("usage: %s [-r rendezvous_dgram] ") + ACE_TEXT ("[-c rendezvous_codgram] [-f file]\n"), + program_name)); + ACE_OS::exit (1); +} + +void +parse_args (int argc, ACE_TCHAR *argv[]) +{ + ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("c:f:r:")); + + for (int c; (c = get_opt ()) != -1; ) + switch (c) + { + case 'f': + file_name = get_opt.opt_arg (); + break; + case 'r': + rendezvous_dgram = get_opt.opt_arg (); + break; + case 'c': + rendezvous_codgram = get_opt.opt_arg (); + break; + default: + print_usage_and_die (); + break; + } +} + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + program_name = argv[0]; + + parse_args (argc, argv); + + char *sock_client = ACE_OS::tempnam (); + + ACE_LSOCK_Dgram sd ((ACE_UNIX_Addr) (sock_client)); + if (ACE_OS::unlink (sock_client)) + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("unlink")), + -1); + ACE_OS::free ((void *) sock_client); + + ACE_LSOCK_CODgram sc; + + if (sc.open (ACE_UNIX_Addr (rendezvous_codgram), + ACE_Addr::sap_any) == -1) + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("open")), + -1); + + ACE_HANDLE handle = ACE_OS::open (file_name, O_RDONLY); + + if (handle == -1) + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("open")), + -1); + + // Send the open file descriptor to the server! + + if (sc.send_handle (handle) == -1) + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("send")), + -1); + + char name[ACE_MAX_USERID]; + ACE_OS::cuserid (name); + + if (sd.send (name, + ACE_OS::strlen (name) + 1, + ACE_UNIX_Addr (rendezvous_dgram)) == -1) + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("send")), + -1); + + if (ACE_OS::close (handle) == -1) + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("close")), + -1); + return 0; +} +#else +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("your platform must support sendmsg/recvmsg to run this test\n")), + -1); +} +#endif /* ACE_HAS_MSG */ diff --git a/ACE/examples/Service_Configurator/IPC-tests/client/local_fifo_client_test.cpp b/ACE/examples/Service_Configurator/IPC-tests/client/local_fifo_client_test.cpp new file mode 100644 index 00000000000..9fb26b4088e --- /dev/null +++ b/ACE/examples/Service_Configurator/IPC-tests/client/local_fifo_client_test.cpp @@ -0,0 +1,101 @@ +// $Id$ + +// Send a file through ACE_FIFO communication channel by +// breaking it (the file) into pieces. + +#include "ace/OS_main.h" +#include "ace/Mem_Map.h" +#include "ace/FIFO_Send_Msg.h" +#include "ace/Get_Opt.h" +#include "ace/Log_Msg.h" +#include "ace/OS_NS_stdlib.h" +#include "ace/OS_NS_stropts.h" + +ACE_RCSID(client, local_fifo_client_test, "$Id$") + +// Name of the program. +static ACE_TCHAR *program_name; + +// debug state on or off +static int debug = 0; + +static const ACE_TCHAR *rendezvous_fifo = ACE_TEXT("/tmp/foo_fifo"); + +// Name of file to send. +static const ACE_TCHAR *file_name = ACE_TEXT("./local_data"); + +static void +print_usage_and_die (void) +{ + ACE_ERROR ((LM_ERROR, + "usage: %s [-d] [-f rendezvous_fifo]\n", + program_name)); + ACE_OS::exit (1); +} + +static void +parse_arguments (int argc, ACE_TCHAR *argv[]) +{ + int tracing = 1; + program_name = argv[0]; + + ACE_Get_Opt get_opt (argc, argv, ACE_TEXT("df:")); + + for (int c; (c = get_opt ()) != -1; ) + switch (c) + { + case 'd': + debug = 1; + break; + case 'f': + rendezvous_fifo = get_opt.opt_arg (); + break; + default: + print_usage_and_die (); + break; + } + + if (debug) + ACE_DEBUG ((LM_DEBUG, + "rendezvous_fifo = %s\n" + "trace = %s\n", + rendezvous_fifo, + tracing ? "on" : "off")); +} + +int +ACE_TMAIN(int argc, ACE_TCHAR *argv[]) +{ + parse_arguments (argc, argv); + + ACE_FIFO_Send_Msg fifo; + + if (fifo.open (rendezvous_fifo, + O_WRONLY, + 0666) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "Cannot open %s for requesting a new communication channel" + "in local_fifo_client_test\n", + rendezvous_fifo), + -1); + void *cp = 0; + ACE_Mem_Map mmap (file_name); + + if (mmap (cp) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "mmap"), + -1); + + // Next, send the file's contents. + + ACE_Str_Buf msg (cp, + int (mmap.size ())); + + if (fifo.send (msg) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "send"), + -1); + return 0; +} diff --git a/ACE/examples/Service_Configurator/IPC-tests/client/local_pipe_client_test.cpp b/ACE/examples/Service_Configurator/IPC-tests/client/local_pipe_client_test.cpp new file mode 100644 index 00000000000..7193440b440 --- /dev/null +++ b/ACE/examples/Service_Configurator/IPC-tests/client/local_pipe_client_test.cpp @@ -0,0 +1,150 @@ +// $Id$ + +// Another test of UNIX domain IPC-SAP abstraction. This one opens 2 +// pipes and then ships certain ends over to the server to act as a +// filter! + +#include "ace/OS_main.h" +#include "ace/LSOCK_Connector.h" +#include "ace/UNIX_Addr.h" +#include "ace/Get_Opt.h" +#include "ace/OS_NS_stdlib.h" +#include "ace/OS_NS_unistd.h" +#include "ace/OS_NS_fcntl.h" + +ACE_RCSID(client, local_pipe_client_test, "$Id$") + +#if defined (ACE_HAS_MSG) && !defined (ACE_LACKS_UNIX_DOMAIN_SOCKETS) +// Name of the program. +static ACE_TCHAR *program_name; + +// Name of rendezvous point. +static const ACE_TCHAR *rendezvous = ACE_TEXT ("/tmp/foo_pipe"); + +// Name of file to send. +static const ACE_TCHAR *file_name = ACE_TEXT ("local_data"); + +static void +print_usage_and_die (void) +{ + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("usage: %s [-r rendezvous] [-f file]\n"), + program_name)); + ACE_OS::exit (1); +} + +void +parse_args (int argc, ACE_TCHAR *argv[]) +{ + program_name = argv[0]; + + ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("f:r:")); + + for (int c; (c = get_opt ()) != -1; ) + switch (c) + { + case 'f': + file_name = get_opt.opt_arg (); + break; + case 'r': + rendezvous = get_opt.opt_arg (); + break; + default: + print_usage_and_die (); + break; + } +} + +static int +do_client_processing (ACE_LSOCK_Stream &sc) +{ + ACE_HANDLE fd_read[2]; + ACE_HANDLE fd_write[2]; + char buf[BUFSIZ]; + int n; + + if (ACE_OS::pipe (fd_read) == -1 || ACE_OS::pipe (fd_write) == -1) + return -1; + + if (sc.send_handle (fd_write[0]) == -1 || sc.send_handle (fd_read[1]) == -1) + return -1; + + // Close off the ends we aren't interested in. + + if (ACE_OS::close (fd_read[1]) || ACE_OS::close (fd_write[0]) == -1) + return -1; + + // Do a silly dup just for fun... + + ACE_HANDLE fd1 = ACE_OS::open (file_name, O_RDONLY); + + if (fd1 == ACE_INVALID_HANDLE) + return -1; + + while ((n = ACE_OS::read (fd1, buf, sizeof buf)) > 0) + { + if (ACE_OS::write (fd_write[1], + buf, + n) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("write")), + -1); + if ((n = ACE_OS::read (fd_read[0], + buf, + sizeof buf)) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("read")), + -1); + if (ACE_OS::write (ACE_STDOUT, + buf, + n) == -1) + return -1; + } + + if (ACE_OS::close (fd_read[0]) == -1 + || ACE_OS::close (fd_write[1]) == -1 + || ACE_OS::close (fd1) == -1) + ACE_OS::exit (1); + + return 0; +} + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + parse_args (argc, argv); + + ACE_LSOCK_Stream sc; + ACE_LSOCK_Connector con; + + if (con.connect (sc, + ACE_UNIX_Addr (rendezvous)) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("connect")), + -1); + + if (do_client_processing (sc) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("do_client_processing")), + -1); + + if (sc.close () == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("close")), + -1); + + return 0; +} +#else +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("your platform must support sendmsg/recvmsg to run this test\n")), + -1); +} +#endif /* ACE_HAS_MSG */ diff --git a/ACE/examples/Service_Configurator/IPC-tests/client/local_spipe_client_test.cpp b/ACE/examples/Service_Configurator/IPC-tests/client/local_spipe_client_test.cpp new file mode 100644 index 00000000000..91d81338ea1 --- /dev/null +++ b/ACE/examples/Service_Configurator/IPC-tests/client/local_spipe_client_test.cpp @@ -0,0 +1,106 @@ +// $Id$ + +// Send a file through ACE_SPIPE communication channel by +// breaking it (the file) into pieces. + +#include "ace/OS_main.h" +#include "ace/Mem_Map.h" +#include "ace/SPIPE_Connector.h" +#include "ace/Get_Opt.h" +#include "ace/Log_Msg.h" + +ACE_RCSID(client, local_spipe_client_test, "$Id$") + +#if defined (ACE_HAS_STREAM_PIPES) + +static ACE_TCHAR *program_name; + +// debug state on or off +static int debug = 0; + +static const ACE_TCHAR *rendezvous_spipe = ACE_TEXT ("/tmp/foo_spipe"); + +// Name of file to send. +static const ACE_TCHAR *file_name = ACE_TEXT ("./local_data"); + +static void +print_usage_and_die (void) +{ + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("usage: %s [-d] [-r rendezvous_spipe]\n"), + program_name)); + ACE_OS::exit (1); +} + +static void +parse_arguments (int argc, ACE_TCHAR *argv[]) +{ + program_name = argv[0]; + ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("dr:")); + + for (int c; (c = get_opt ()) != -1; ) + switch (c) + { + case 'd': + debug = 1; + break; + case 'r': + rendezvous_spipe = get_opt.opt_arg (); + break; + default: + print_usage_and_die (); + break; + } + if (debug) + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("rendezvous_spipe = %s\n"), + rendezvous_spipe)); +} + +int +ACE_TMAIN(int argc, ACE_TCHAR *argv[]) +{ + parse_arguments (argc, argv); + + ACE_SPIPE_Stream spipe; + ACE_SPIPE_Connector con; + + if (con.connect (spipe, + ACE_SPIPE_Addr (rendezvous_spipe)) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("Cannot open %s for requesting a new ") + ACE_TEXT ("communication channel in %p\n"), + rendezvous_spipe, + ACE_TEXT ("local_spipe_client_test")), + -1); + + ACE_Mem_Map mmap (file_name); + void *cp; + + if (mmap (cp) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("mmap")), + -1); + + // Next, send the file's contents. + + ACE_Str_Buf msg (cp, int (mmap.size ())); + + if (spipe.send ((ACE_Str_Buf *) 0, &msg) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("send")), + -1); + return 0; +} +#else +#include <stdio.h> +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("This feature is not supported\n")), + -1); +} +#endif /* ACE_HAS_STREAM_PIPES */ diff --git a/ACE/examples/Service_Configurator/IPC-tests/client/local_stream_client_test.cpp b/ACE/examples/Service_Configurator/IPC-tests/client/local_stream_client_test.cpp new file mode 100644 index 00000000000..390b14e19b8 --- /dev/null +++ b/ACE/examples/Service_Configurator/IPC-tests/client/local_stream_client_test.cpp @@ -0,0 +1,113 @@ +// $Id$ + +// Tests out the UNIX domain IPC-SAP abstraction. + +#include "ace/OS_main.h" +#include "ace/LSOCK_Connector.h" +#include "ace/UNIX_Addr.h" +#include "ace/Get_Opt.h" +#include "ace/OS_NS_stdlib.h" +#include "ace/OS_NS_unistd.h" +#include "ace/OS_NS_fcntl.h" + +ACE_RCSID(client, local_stream_client_test, "$Id$") + +#if defined (ACE_HAS_MSG) && !defined (ACE_LACKS_UNIX_DOMAIN_SOCKETS) +// Name of the program. +static ACE_TCHAR *program_name; + +// Name of rendezvous point. +static const ACE_TCHAR *rendezvous = ACE_TEXT ("/tmp/foo_stream"); + +// Name of file to send. +static const ACE_TCHAR *file_name = ACE_TEXT ("local_data"); + +static void +print_usage_and_die (void) +{ + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("usage: %s [-r rendezvous] [-f file]\n"), + program_name)); + ACE_OS::exit (1); +} + +void +parse_args (int argc, ACE_TCHAR *argv[]) +{ + program_name = argv[0]; + ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("f:r:")); + + for (int c; (c = get_opt ()) != -1; ) + switch (c) + { + case 'f': + file_name = get_opt.opt_arg (); + break; + case 'r': + rendezvous = get_opt.opt_arg (); + break; + default: + print_usage_and_die (); + break; + } +} + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + parse_args (argc, argv); + + int fd; + char buf[BUFSIZ]; + int n; + + ACE_LSOCK_Stream sc; + ACE_LSOCK_Connector con; + + if (con.connect (sc, + ACE_UNIX_Addr (rendezvous)) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("connect")), + -1); + + if ((fd = ACE_OS::open (file_name, + O_RDONLY)) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("open")), + -1); + + // Send the open file descriptor to the server! + + if (sc.send_handle (fd) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("send_handle")), + -1); + + if ((n = sc.recv_n (buf, + sizeof buf)) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("recv")), + -1); + else + ACE_OS::write (ACE_STDOUT, buf, n); + + if (ACE_OS::close (fd) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("close")), + -1); + + return 0; +} +#else +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("your platform must support sendmsg/recvmsg to run this test\n")), + -1); +} +#endif /* ACE_HAS_MSG */ diff --git a/ACE/examples/Service_Configurator/IPC-tests/client/remote_data b/ACE/examples/Service_Configurator/IPC-tests/client/remote_data new file mode 100644 index 00000000000..ae7e1fbb88e --- /dev/null +++ b/ACE/examples/Service_Configurator/IPC-tests/client/remote_data @@ -0,0 +1,22 @@ +remoteremoteremoteremoteremoteremoteremoteremote +remoteremoteremoteremoteremoteremoteremoteremote +remoteremoteremoteremoteremoteremoteremoteremote +remoteremoteremoteremoteremoteremoteremoteremote +remoteremoteremoteremoteremoteremoteremoteremote +remoteremoteremoteremoteremoteremoteremoteremote +remoteremoteremoteremoteremoteremoteremoteremote +remoteremoteremoteremoteremoteremoteremoteremote +remoteremoteremoteremoteremoteremoteremoteremote +remoteremoteremoteremoteremoteremoteremoteremote +remoteremoteremoteremoteremoteremoteremoteremote +remoteremoteremoteremoteremoteremoteremoteremote +remoteremoteremoteremoteremoteremoteremoteremote +remoteremoteremoteremoteremoteremoteremoteremote +remoteremoteremoteremoteremoteremoteremoteremote +remoteremoteremoteremoteremoteremoteremoteremote +remoteremoteremoteremoteremoteremoteremoteremote +remoteremoteremoteremoteremoteremoteremoteremote +remoteremoteremoteremoteremoteremoteremoteremote +remoteremoteremoteremoteremoteremoteremoteremote +remoteremoteremoteremoteremoteremoteremoteremote +remoteremoteremoteremoteremoteremoteremoteremote diff --git a/ACE/examples/Service_Configurator/IPC-tests/client/remote_data1 b/ACE/examples/Service_Configurator/IPC-tests/client/remote_data1 new file mode 100644 index 00000000000..6faaee46729 --- /dev/null +++ b/ACE/examples/Service_Configurator/IPC-tests/client/remote_data1 @@ -0,0 +1,22 @@ +remote1remote1remote1remote1remote1remote1remote1remote1 +remote1remote1remote1remote1remote1remote1remote1remote1 +remote1remote1remote1remote1remote1remote1remote1remote1 +remote1remote1remote1remote1remote1remote1remote1remote1 +remote1remote1remote1remote1remote1remote1remote1remote1 +remote1remote1remote1remote1remote1remote1remote1remote1 +remote1remote1remote1remote1remote1remote1remote1remote1 +remote1remote1remote1remote1remote1remote1remote1remote1 +remote1remote1remote1remote1remote1remote1remote1remote1 +remote1remote1remote1remote1remote1remote1remote1remote1 +remote1remote1remote1remote1remote1remote1remote1remote1 +remote1remote1remote1remote1remote1remote1remote1remote1 +remote1remote1remote1remote1remote1remote1remote1remote1 +remote1remote1remote1remote1remote1remote1remote1remote1 +remote1remote1remote1remote1remote1remote1remote1remote1 +remote1remote1remote1remote1remote1remote1remote1remote1 +remote1remote1remote1remote1remote1remote1remote1remote1 +remote1remote1remote1remote1remote1remote1remote1remote1 +remote1remote1remote1remote1remote1remote1remote1remote1 +remote1remote1remote1remote1remote1remote1remote1remote1 +remote1remote1remote1remote1remote1remote1remote1remote1 +remote1remote1remote1remote1remote1remote1remote1remote1 diff --git a/ACE/examples/Service_Configurator/IPC-tests/client/remote_data2 b/ACE/examples/Service_Configurator/IPC-tests/client/remote_data2 new file mode 100644 index 00000000000..ae6bf12d49f --- /dev/null +++ b/ACE/examples/Service_Configurator/IPC-tests/client/remote_data2 @@ -0,0 +1,22 @@ +remote2remote2remote2remote2remote2remote2remote2remote2 +remote2remote2remote2remote2remote2remote2remote2remote2 +remote2remote2remote2remote2remote2remote2remote2remote2 +remote2remote2remote2remote2remote2remote2remote2remote2 +remote2remote2remote2remote2remote2remote2remote2remote2 +remote2remote2remote2remote2remote2remote2remote2remote2 +remote2remote2remote2remote2remote2remote2remote2remote2 +remote2remote2remote2remote2remote2remote2remote2remote2 +remote2remote2remote2remote2remote2remote2remote2remote2 +remote2remote2remote2remote2remote2remote2remote2remote2 +remote2remote2remote2remote2remote2remote2remote2remote2 +remote2remote2remote2remote2remote2remote2remote2remote2 +remote2remote2remote2remote2remote2remote2remote2remote2 +remote2remote2remote2remote2remote2remote2remote2remote2 +remote2remote2remote2remote2remote2remote2remote2remote2 +remote2remote2remote2remote2remote2remote2remote2remote2 +remote2remote2remote2remote2remote2remote2remote2remote2 +remote2remote2remote2remote2remote2remote2remote2remote2 +remote2remote2remote2remote2remote2remote2remote2remote2 +remote2remote2remote2remote2remote2remote2remote2remote2 +remote2remote2remote2remote2remote2remote2remote2remote2 +remote2remote2remote2remote2remote2remote2remote2remote2 diff --git a/ACE/examples/Service_Configurator/IPC-tests/client/remote_data3 b/ACE/examples/Service_Configurator/IPC-tests/client/remote_data3 new file mode 100644 index 00000000000..7f2ec1aa81b --- /dev/null +++ b/ACE/examples/Service_Configurator/IPC-tests/client/remote_data3 @@ -0,0 +1,22 @@ +remote3remote3remote3remote3remote3remote3remote3remote3 +remote3remote3remote3remote3remote3remote3remote3remote3 +remote3remote3remote3remote3remote3remote3remote3remote3 +remote3remote3remote3remote3remote3remote3remote3remote3 +remote3remote3remote3remote3remote3remote3remote3remote3 +remote3remote3remote3remote3remote3remote3remote3remote3 +remote3remote3remote3remote3remote3remote3remote3remote3 +remote3remote3remote3remote3remote3remote3remote3remote3 +remote3remote3remote3remote3remote3remote3remote3remote3 +remote3remote3remote3remote3remote3remote3remote3remote3 +remote3remote3remote3remote3remote3remote3remote3remote3 +remote3remote3remote3remote3remote3remote3remote3remote3 +remote3remote3remote3remote3remote3remote3remote3remote3 +remote3remote3remote3remote3remote3remote3remote3remote3 +remote3remote3remote3remote3remote3remote3remote3remote3 +remote3remote3remote3remote3remote3remote3remote3remote3 +remote3remote3remote3remote3remote3remote3remote3remote3 +remote3remote3remote3remote3remote3remote3remote3remote3 +remote3remote3remote3remote3remote3remote3remote3remote3 +remote3remote3remote3remote3remote3remote3remote3remote3 +remote3remote3remote3remote3remote3remote3remote3remote3 +remote3remote3remote3remote3remote3remote3remote3remote3 diff --git a/ACE/examples/Service_Configurator/IPC-tests/client/remote_data4 b/ACE/examples/Service_Configurator/IPC-tests/client/remote_data4 new file mode 100644 index 00000000000..6c5a9633d56 --- /dev/null +++ b/ACE/examples/Service_Configurator/IPC-tests/client/remote_data4 @@ -0,0 +1,22 @@ +remote4remote4remote4remote4remote4remote4remote4remote4 +remote4remote4remote4remote4remote4remote4remote4remote4 +remote4remote4remote4remote4remote4remote4remote4remote4 +remote4remote4remote4remote4remote4remote4remote4remote4 +remote4remote4remote4remote4remote4remote4remote4remote4 +remote4remote4remote4remote4remote4remote4remote4remote4 +remote4remote4remote4remote4remote4remote4remote4remote4 +remote4remote4remote4remote4remote4remote4remote4remote4 +remote4remote4remote4remote4remote4remote4remote4remote4 +remote4remote4remote4remote4remote4remote4remote4remote4 +remote4remote4remote4remote4remote4remote4remote4remote4 +remote4remote4remote4remote4remote4remote4remote4remote4 +remote4remote4remote4remote4remote4remote4remote4remote4 +remote4remote4remote4remote4remote4remote4remote4remote4 +remote4remote4remote4remote4remote4remote4remote4remote4 +remote4remote4remote4remote4remote4remote4remote4remote4 +remote4remote4remote4remote4remote4remote4remote4remote4 +remote4remote4remote4remote4remote4remote4remote4remote4 +remote4remote4remote4remote4remote4remote4remote4remote4 +remote4remote4remote4remote4remote4remote4remote4remote4 +remote4remote4remote4remote4remote4remote4remote4remote4 +remote4remote4remote4remote4remote4remote4remote4remote4 diff --git a/ACE/examples/Service_Configurator/IPC-tests/client/remote_dgram_client_test.cpp b/ACE/examples/Service_Configurator/IPC-tests/client/remote_dgram_client_test.cpp new file mode 100644 index 00000000000..e5bec64d8c6 --- /dev/null +++ b/ACE/examples/Service_Configurator/IPC-tests/client/remote_dgram_client_test.cpp @@ -0,0 +1,92 @@ +// $Id$ + +// Tests out the Internet domain IPC-SAP dgram abstraction. + +#include "ace/OS_main.h" +#include "ace/OS_NS_stdlib.h" +#include "ace/Mem_Map.h" +#include "ace/SOCK_Dgram.h" +#include "ace/INET_Addr.h" +#include "ace/Get_Opt.h" +#include "ace/Log_Msg.h" + +ACE_RCSID(client, remote_dgram_client_test, "$Id$") + +// Name of the program. +static const ACE_TCHAR *program_name; + +// Port number to use. +static u_short port_number = ACE_DEFAULT_SERVER_PORT; + +// Name of remote host. +static const ACE_TCHAR *host_name = ACE_DEFAULT_SERVER_HOST; + +// Name of file to send. +static const ACE_TCHAR *file_name = ACE_TEXT("./remote_data"); + +static void print_usage_and_die (void) +{ + ACE_ERROR ((LM_ERROR, + "usage: %s [-p portnum] [-h host_name] [-f file]\n", + program_name)); + ACE_OS::exit (1); +} + +void +parse_args (int argc, ACE_TCHAR *argv[]) +{ + program_name = argv[0]; + + ACE_Get_Opt get_opt (argc, argv, ACE_TEXT("f:h:p:")); + + for (int c; (c = get_opt ()) != -1; ) + switch (c) + { + case 'f': + file_name = get_opt.opt_arg (); + break; + case 'h': + host_name = get_opt.opt_arg (); + break; + case 'p': + port_number = ACE_OS::atoi (get_opt.opt_arg ()); + break; + default: + print_usage_and_die (); + break; + } +} + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + parse_args (argc, argv); + + ACE_SOCK_Dgram sd (ACE_Addr::sap_any); + void *cp = 0; + ACE_INET_Addr sa (port_number, host_name); + + ACE_Mem_Map mmap (file_name); + + if (mmap (cp) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "mmap"), + -1); + + // Next, send the file's contents. + + ssize_t cc = sd.send (cp, mmap.size (), sa); + + if (cc == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "send"), + -1); + else if (cc != (ssize_t) mmap.size ()) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "Not all the contents of mmap file are sent."), + -1); + return 0; +} diff --git a/ACE/examples/Service_Configurator/IPC-tests/client/remote_service_directory_test.cpp b/ACE/examples/Service_Configurator/IPC-tests/client/remote_service_directory_test.cpp new file mode 100644 index 00000000000..cee8ca1469f --- /dev/null +++ b/ACE/examples/Service_Configurator/IPC-tests/client/remote_service_directory_test.cpp @@ -0,0 +1,111 @@ +// $Id$ + +// Test program for the INET IPC-SAPs... + +#include "ace/OS_main.h" +#include "ace/OS_NS_stdlib.h" +#include "ace/OS_NS_unistd.h" +#include "ace/OS_NS_string.h" +#include "ace/SOCK_Connector.h" +#include "ace/INET_Addr.h" +#include "ace/Get_Opt.h" +#include "ace/Log_Msg.h" + +ACE_RCSID(client, remote_service_directory_test, "$Id$") + +// Port number to use. +static unsigned short port_number = ACE_DEFAULT_SERVICE_PORT; + +// Name of remote host. +static const ACE_TCHAR *host_name = ACE_DEFAULT_SERVER_HOST; + +// Trigger a remote reconfiguration. +static int remote_reconfigure = 0; + +static void +print_usage_and_die (void) +{ + ACE_ERROR ((LM_ERROR, + "usage: %n [-p portnum] [-h host_name] [-r]\n")); + ACE_OS::exit (1); +} + +void +parse_args (int argc, ACE_TCHAR *argv[]) +{ + ACE_Get_Opt get_opt (argc, argv, ACE_TEXT("p:h:r")); + + for (int c; (c = get_opt ()) != -1; ) + switch (c) + { + case 'h': + host_name = get_opt.opt_arg (); + break; + case 'p': + port_number = ACE_OS::atoi (get_opt.opt_arg ()); + break; + case 'r': + remote_reconfigure = 1; + break; + default: + print_usage_and_die (); + break; + } +} + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + ACE_LOG_MSG->open (argv[0]); + + parse_args (argc, argv); + // Default is to ask the server for ``help.'' + static char buf[BUFSIZ] = "help\n"; + int n; + ACE_SOCK_Stream sc; + ACE_SOCK_Connector con; + + if (con.connect (sc, + ACE_INET_Addr (port_number, + host_name)) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n%a", + "connect", + 1), + -1); + + if (remote_reconfigure) + // Remotely instruct the server to reconfigure itself. + ACE_OS::strcpy (buf, "reconfigure\n"); + + // Send the command. + + if (sc.send_n (buf, + ACE_OS::strlen (buf) + 1) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n%a", + "send", + 1), -1); + + // Next, read the response. + + while ((n = sc.recv (buf, + sizeof buf)) > 0) + if (ACE_OS::write (ACE_STDOUT, + buf, + n) != n) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n%a", + "write", + 1), + -1); + + if (sc.close () == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n%a", + "close", + 1), + -1); + + return 0; +} diff --git a/ACE/examples/Service_Configurator/IPC-tests/client/remote_stream_client_test.cpp b/ACE/examples/Service_Configurator/IPC-tests/client/remote_stream_client_test.cpp new file mode 100644 index 00000000000..d7d4ef7346c --- /dev/null +++ b/ACE/examples/Service_Configurator/IPC-tests/client/remote_stream_client_test.cpp @@ -0,0 +1,134 @@ +// $Id$ + +// Test program for the INET IPC-SAPs... + +#include "ace/OS_main.h" +#include "ace/OS_NS_stdlib.h" +#include "ace/OS_NS_string.h" +#include "ace/OS_NS_unistd.h" +#include "ace/Mem_Map.h" +#include "ace/SOCK_Connector.h" +#include "ace/SOCK_CODgram.h" +#include "ace/INET_Addr.h" +#include "ace/Get_Opt.h" +#include "ace/Log_Msg.h" + +ACE_RCSID(client, remote_stream_client_test, "$Id$") + +// Name of the program. +static const ACE_TCHAR *program_name; + +// Port number to use. +static u_short port_number = ACE_DEFAULT_SERVER_PORT; + +// Name of remote host. +static const ACE_TCHAR *host_name = ACE_DEFAULT_SERVER_HOST; + +// Name of file to send. +static const ACE_TCHAR *file_name = ACE_TEXT("./remote_data"); + +static void +print_usage_and_die (void) +{ + ACE_ERROR ((LM_ERROR, + "usage: %s [-p portnum] [-h host_name] [-f file]\n", + program_name)); + ACE_OS::exit (1); +} + +void +parse_args (int argc, ACE_TCHAR *argv[]) +{ + program_name = argv[0]; + ACE_Get_Opt get_opt (argc, argv, ACE_TEXT("f:h:p:")); + + for (int c; (c = get_opt ()) != -1; ) + switch (c) + { + case 'f': + file_name = get_opt.opt_arg (); + break; + case 'h': + host_name = get_opt.opt_arg (); + break; + case 'p': + port_number = ACE_OS::atoi (get_opt.opt_arg ()); + break; + default: + print_usage_and_die (); + break; + } +} + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + parse_args (argc, argv); + ACE_INET_Addr sa (port_number, host_name); + void *cp = 0; + char buf[BUFSIZ]; + int n; + ACE_SOCK_CODgram dc; + + if (dc.open (sa, ACE_Addr::sap_any) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "open"), + -1); + + // First send the name of the file as a datagram. + + iovec iov[2]; + + iov[0].iov_base = (char *) "filename: "; + iov[0].iov_len = 11; + iov[1].iov_base = (char *) file_name; + iov[1].iov_len = ACE_OS::strlen (file_name); + + if (dc.send (iov, 2) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "send"), + -1); + + ACE_SOCK_Stream sc; + ACE_SOCK_Connector con; + + if (con.connect (sc, sa) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "connect"), + -1); + + ACE_Mem_Map mmap (file_name); + + if (mmap (cp) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "mmap"), + -1); + + // Next, send the file's contents. + + if (sc.send_n (cp, mmap.size ()) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "send_urg"), + -1); + + if (sc.close_writer () == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "close_writer"), + -1); + + if ((n = sc.recv_n (buf, sizeof buf)) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "recv"), + -1); + else + ACE_OS::write (ACE_STDOUT, buf, n); + + return 0; +} diff --git a/ACE/examples/Service_Configurator/IPC-tests/client/remote_thr_stream_client_test.cpp b/ACE/examples/Service_Configurator/IPC-tests/client/remote_thr_stream_client_test.cpp new file mode 100644 index 00000000000..113c809069d --- /dev/null +++ b/ACE/examples/Service_Configurator/IPC-tests/client/remote_thr_stream_client_test.cpp @@ -0,0 +1,122 @@ +// $Id$ + +// Test program for the INET ACE_TLI-SAPs... + +#include "ace/OS_main.h" +#include "ace/OS_NS_stdlib.h" +#include "ace/OS_NS_unistd.h" +#include "ace/Mem_Map.h" +#include "ace/TLI_Connector.h" +#include "ace/INET_Addr.h" +#include "ace/Get_Opt.h" +#include "ace/Log_Msg.h" + +ACE_RCSID(client, remote_thr_stream_client_test, "$Id$") + +#if defined (ACE_HAS_TLI) + +// Name of the program. +static const ACE_TCHAR *program_name; + +// Port number to use. +static u_short port_number = ACE_DEFAULT_THR_PORT; + +// Name of remote host. +static const ACE_TCHAR *host_name = ACE_DEFAULT_SERVER_HOST; + +// Name of file to send. +static const ACE_TCHAR *file_name = ACE_TEXT ("./remote_data"); + +static void print_usage_and_die (void) +{ + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("usage: %s [-p portnum] [-h host_name] [-f file]\n"), + program_name)); + ACE_OS::exit (1); +} + +void +parse_args (int argc, ACE_TCHAR *argv[]) +{ + program_name = argv[0]; + ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("f:h:p:")); + + for (int c; (c = get_opt ()) != -1; ) + switch (c) + { + case 'f': + file_name = get_opt.opt_arg (); + break; + case 'h': + host_name = get_opt.opt_arg (); + break; + case 'p': + port_number = ACE_OS::atoi (get_opt.opt_arg ()); + break; + default: + print_usage_and_die (); + break; + } +} + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + parse_args (argc, argv); + void *cp; + char buf[BUFSIZ]; + ACE_TLI_Stream sc; + ACE_TLI_Connector con; + + if (con.connect (sc, + ACE_INET_Addr (port_number, + host_name)) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("open")), + -1); + + ACE_Mem_Map mmap (file_name, PROT_READ); + + if (mmap (cp) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("mmap")), -1); + + // Next, send the file's contents. + + if (sc.send_n (cp, mmap.size ()) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("send_n")), + -1); + + if (sc.sndrel () == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("close_writer")), + -1); + + for (int n; (n = sc.recv (buf, sizeof buf)) > 0; ) + if (ACE_OS::write (ACE_STDOUT, buf, n) != n) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("write")), + -1); + + if (sc.close () == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("close")), + -1); + return 0; +} +#else +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("you must have TLI to run this test\n")), + 1); +} +#endif /* ACE_HAS_TLI */ diff --git a/ACE/examples/Service_Configurator/IPC-tests/server/.cvsignore b/ACE/examples/Service_Configurator/IPC-tests/server/.cvsignore new file mode 100644 index 00000000000..74fdfbc7f93 --- /dev/null +++ b/ACE/examples/Service_Configurator/IPC-tests/server/.cvsignore @@ -0,0 +1 @@ +server_test diff --git a/ACE/examples/Service_Configurator/IPC-tests/server/Handle_Broadcast.cpp b/ACE/examples/Service_Configurator/IPC-tests/server/Handle_Broadcast.cpp new file mode 100644 index 00000000000..30db7825244 --- /dev/null +++ b/ACE/examples/Service_Configurator/IPC-tests/server/Handle_Broadcast.cpp @@ -0,0 +1,38 @@ +// $Id$ + +#include "Handle_Broadcast.h" + +ACE_RCSID(server, Handle_Broadcast, "$Id$") + +#if defined (SunOS4) +extern "C" +{ + int init (void); + int fini (void); + void __sti__Handle_Broadcast_C_init_(); + void __std__Handle_Broadcast_C_init_(); +} + +int +init (void) +{ + __sti__Handle_Broadcast_C_init_(); + return 0; +} + +int +fini (void) +{ + __std__Handle_Broadcast_C_init_(); + return 0; +} +#endif /* SunOS4 */ + +unsigned short Handle_Broadcast::DEFAULT_PORT = ACE_DEFAULT_BROADCAST_PORT; + +#if !defined (__ACE_INLINE__) +#include "Handle_Broadcast.i" +#endif /* __ACE_INLINE__ */ + +Handle_Broadcast remote_broadcast; +ACE_Service_Object_Type rb (&remote_broadcast, ACE_TEXT("Remote_Brdcast")); diff --git a/ACE/examples/Service_Configurator/IPC-tests/server/Handle_Broadcast.h b/ACE/examples/Service_Configurator/IPC-tests/server/Handle_Broadcast.h new file mode 100644 index 00000000000..8b382f9fd73 --- /dev/null +++ b/ACE/examples/Service_Configurator/IPC-tests/server/Handle_Broadcast.h @@ -0,0 +1,50 @@ +// -*- C++ -*- +// +// $Id$ + +/* Handles INET broadcast datagram messages from remote hosts on the local subnet. */ + +#ifndef _HANDLE_BROADCAST_H +#define _HANDLE_BROADCAST_H + +#include "ace/Service_Config.h" +#include "ace/Reactor.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Service_Types.h" +#include "ace/INET_Addr.h" +#include "ace/SOCK_Dgram.h" +#include "ace/Log_Msg.h" +#include "ace/svc_export.h" + +class ACE_Svc_Export Handle_Broadcast : public ACE_Service_Object, public ACE_SOCK_Dgram +{ +public: + Handle_Broadcast (void); + ~Handle_Broadcast (void); + virtual int init (int argc, ACE_TCHAR *argv[]); + virtual int info (ACE_TCHAR **, size_t) const; + virtual int fini (void); + +private: + int open (const ACE_INET_Addr &r, int async = 0); + virtual ACE_HANDLE get_handle (void) const; + virtual int handle_input (ACE_HANDLE fd); + virtual int handle_close (ACE_HANDLE fd, ACE_Reactor_Mask); + + static unsigned short DEFAULT_PORT; +}; + +extern ACE_Service_Object_Type rb; + +#if defined (__ACE_INLINE__) +#define ACE_INLINE inline +#include "Handle_Broadcast.i" +#else +#define ACE_INLINE +#endif /* __ACE_INLINE__ */ + +#endif /* _HANDLE_BROADCAST_H */ diff --git a/ACE/examples/Service_Configurator/IPC-tests/server/Handle_Broadcast.i b/ACE/examples/Service_Configurator/IPC-tests/server/Handle_Broadcast.i new file mode 100644 index 00000000000..ce7f42617e7 --- /dev/null +++ b/ACE/examples/Service_Configurator/IPC-tests/server/Handle_Broadcast.i @@ -0,0 +1,116 @@ +/* -*- C++ -*- */ +// $Id$ + +#include "ace/Get_Opt.h" +#include "ace/OS_NS_stdio.h" +#include "ace/OS_NS_string.h" +#include "ace/OS_NS_unistd.h" + +ACE_INLINE +Handle_Broadcast::~Handle_Broadcast (void) +{ +} + +ACE_INLINE +Handle_Broadcast::Handle_Broadcast (void) +{ +} + +ACE_INLINE int +Handle_Broadcast::open (const ACE_INET_Addr &r, int async) +{ + if (this->ACE_SOCK_Dgram::open (r) == -1) + return -1; + else if (async && ACE_SOCK_Dgram::enable (ACE_SIGIO) == -1) + return -1; + else + return 0; +} + +ACE_INLINE int +Handle_Broadcast::info (ACE_TCHAR **strp, size_t length) const +{ + ACE_TCHAR buf[BUFSIZ]; + ACE_INET_Addr sa; + + if (this->get_local_addr (sa) == -1) + return -1; + + ACE_OS::sprintf (buf, ACE_TEXT("%d/"), sa.get_port_number ()); + ACE_OS::strcat (buf, ACE_TEXT("udp # tests broadcasting\n")); + + if (*strp == 0 && (*strp = ACE_OS::strdup (buf)) == 0) + return -1; + else + ACE_OS::strncpy (*strp, buf, length); + return ACE_OS::strlen (buf); +} + +ACE_INLINE int +Handle_Broadcast::init (int argc, ACE_TCHAR *argv[]) +{ + ACE_INET_Addr sba (Handle_Broadcast::DEFAULT_PORT); + ACE_Get_Opt get_opt (argc, argv, ACE_TEXT("p:"), 0); + + for (int c; (c = get_opt ()) != -1; ) + switch (c) + { + case 'p': + sba.set (ACE_OS::atoi (get_opt.opt_arg ())); + break; + default: + break; + } + + if (this->open (sba) == -1) + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("open")), -1); + else if (ACE_Reactor::instance ()->register_handler + (this, ACE_Event_Handler::ACCEPT_MASK) == -1) + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), + ACE_TEXT ("registering service with ACE_Reactor")), -1); + return 0; +} + +ACE_INLINE int +Handle_Broadcast::fini (void) +{ + return ACE_Reactor::instance ()->remove_handler + (this, ACE_Event_Handler::ACCEPT_MASK); +} + +ACE_INLINE ACE_HANDLE +Handle_Broadcast::get_handle (void) const +{ + return this->ACE_SOCK_Dgram::get_handle (); +} + +ACE_INLINE int +Handle_Broadcast::handle_input (ACE_HANDLE) +{ + ACE_INET_Addr sa; + char buf[8 * 1024]; /* 8 k buffer */ + ssize_t n = this->recv (buf, sizeof buf, sa); + + if (n== -1) + return -1; + else + ACE_DEBUG ((LM_INFO, + ACE_TEXT ("received broadcast datagram from host %C\n"), + sa.get_host_name ())); + + ACE_OS::puts (ACE_TEXT ("----------------------------------------")); + ACE_OS::write (ACE_STDOUT, buf, n); + + if (buf[n - 1] != '\n') + putchar ('\n'); + + ACE_OS::puts (ACE_TEXT ("----------------------------------------")); + + return 0; +} + +ACE_INLINE int +Handle_Broadcast::handle_close (ACE_HANDLE, ACE_Reactor_Mask) +{ + return this->ACE_SOCK_Dgram::close (); +} diff --git a/ACE/examples/Service_Configurator/IPC-tests/server/Handle_L_CODgram.cpp b/ACE/examples/Service_Configurator/IPC-tests/server/Handle_L_CODgram.cpp new file mode 100644 index 00000000000..6fe631fdb41 --- /dev/null +++ b/ACE/examples/Service_Configurator/IPC-tests/server/Handle_L_CODgram.cpp @@ -0,0 +1,19 @@ +// $Id$ + +#include "Handle_L_CODgram.h" + +#if !defined (ACE_LACKS_UNIX_DOMAIN_SOCKETS) + +ACE_RCSID(server, Handle_L_CODgram, "$Id$") + +const ACE_TCHAR *Handle_L_CODgram::DEFAULT_RENDEZVOUS = + ACE_TEXT ("/tmp/foo_codgram"); + +#if !defined (__ACE_INLINE__) +#include "Handle_L_CODgram.i" +#endif /* __ACE_INLINE__ */ + +Handle_L_CODgram local_codgram; +ACE_Service_Object_Type lc (&local_codgram, ACE_TEXT ("Local_CODgram")); + +#endif /* ACE_LACKS_UNIX_DOMAIN_SOCKETS */ diff --git a/ACE/examples/Service_Configurator/IPC-tests/server/Handle_L_CODgram.h b/ACE/examples/Service_Configurator/IPC-tests/server/Handle_L_CODgram.h new file mode 100644 index 00000000000..852c0557cda --- /dev/null +++ b/ACE/examples/Service_Configurator/IPC-tests/server/Handle_L_CODgram.h @@ -0,0 +1,51 @@ +/* -*- C++ -*- */ +// $Id$ + +// Handles UNIX datagram messages from local host. + +#ifndef _HANDLE_L_CODGRAM_H +#define _HANDLE_L_CODGRAM_H + +#include "ace/Service_Config.h" +#include "ace/Reactor.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Service_Types.h" +#include "ace/LSOCK_CODgram.h" +#include "ace/UNIX_Addr.h" +#include "ace/svc_export.h" + +#if !defined (ACE_LACKS_UNIX_DOMAIN_SOCKETS) + +class ACE_Svc_Export Handle_L_CODgram : public ACE_Service_Object, public ACE_LSOCK_CODgram +{ +public: + Handle_L_CODgram (void); + virtual int init (int argc, ACE_TCHAR *argv[]); + virtual int info (ACE_TCHAR **, size_t) const; + virtual int fini (void); + +public: + int open (const ACE_UNIX_Addr &suad, int async = 0); + virtual ACE_HANDLE get_handle (void) const; + virtual int handle_input (ACE_HANDLE); + virtual int handle_close (ACE_HANDLE, ACE_Reactor_Mask); + + ACE_TCHAR rendezvous[MAXPATHLEN + 1]; + static const ACE_TCHAR *DEFAULT_RENDEZVOUS; +}; + +extern ACE_Service_Object_Type lc; + +#if defined (__ACE_INLINE__) +#define ACE_INLINE inline +#include "Handle_L_CODgram.i" +#else +#define ACE_INLINE +#endif /* __ACE_INLINE__ */ + +#endif /* ACE_LACKS_UNIX_DOMAIN_SOCKETS */ +#endif /* _HANDLE_L_CODGRAM_H */ diff --git a/ACE/examples/Service_Configurator/IPC-tests/server/Handle_L_CODgram.i b/ACE/examples/Service_Configurator/IPC-tests/server/Handle_L_CODgram.i new file mode 100644 index 00000000000..a77d75e1fa8 --- /dev/null +++ b/ACE/examples/Service_Configurator/IPC-tests/server/Handle_L_CODgram.i @@ -0,0 +1,123 @@ +/* -*- C++ -*- */ +// $Id$ + +#include "ace/Get_Opt.h" +#include "ace/OS_NS_stdio.h" +#include "ace/OS_NS_string.h" +#include "ace/OS_NS_unistd.h" + +ACE_INLINE +Handle_L_CODgram::Handle_L_CODgram (void) +{ +} + +ACE_INLINE int +Handle_L_CODgram::open (const ACE_UNIX_Addr &suad, int async) +{ + if (this->ACE_LSOCK_CODgram::open (ACE_Addr::sap_any, suad) == -1) + return -1; + else if (async && this->ACE_LSOCK_CODgram::enable (ACE_SIGIO) == -1) + return -1; + else + return 0; +} + +ACE_INLINE int +Handle_L_CODgram::info (ACE_TCHAR **strp, size_t length) const +{ + ACE_TCHAR buf[BUFSIZ]; + ACE_UNIX_Addr sa; + + if (ACE_LSOCK_CODgram::get_local_addr (sa) == -1) + return -1; + + ACE_OS::strcpy (buf, ACE_TEXT_CHAR_TO_TCHAR (sa.get_path_name ())); + ACE_OS::strcat (buf, ACE_TEXT (" # tests local connected datagram\n")); + + if (*strp == 0 && (*strp = ACE_OS::strdup (buf)) == 0) + return -1; + else + ACE_OS::strncpy (*strp, buf, length); + return ACE_OS::strlen (buf); +} + +ACE_INLINE int +Handle_L_CODgram::init (int argc, ACE_TCHAR *argv[]) +{ + ACE_UNIX_Addr sucd; + ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("r:"), 0); + const ACE_TCHAR *r = Handle_L_CODgram::DEFAULT_RENDEZVOUS; + + for (int c; (c = get_opt ()) != -1; ) + switch (c) + { + case 'r': + r = get_opt.opt_arg (); + break; + default: + break; + } + + ACE_OS::strncpy (this->rendezvous, r, MAXPATHLEN); + ACE_OS::unlink (this->rendezvous); + sucd.set (this->rendezvous); + if (this->open (sucd) == -1) + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("open")), -1); + else if (ACE_Reactor::instance ()->register_handler + (this, ACE_Event_Handler::ACCEPT_MASK) == -1) + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), + ACE_TEXT ("registering service with ACE_Reactor")), + -1); + return 0; +} + +ACE_INLINE int +Handle_L_CODgram::fini(void) +{ + return ACE_Reactor::instance ()->remove_handler + (this, ACE_Event_Handler::ACCEPT_MASK); +} + +ACE_INLINE ACE_HANDLE +Handle_L_CODgram::get_handle (void) const +{ + return ACE_LSOCK_CODgram::get_handle (); +} + +ACE_INLINE int +Handle_L_CODgram::handle_input (ACE_HANDLE) +{ + ACE_HANDLE handle = ACE_INVALID_HANDLE; + char buf[BUFSIZ]; + + if (this->recv_handle (handle) == -1) + return -1; + else + ACE_DEBUG ((LM_INFO, ACE_TEXT ("received handle (%d)\n"), handle)); + + ACE_OS::puts ("----------------------------------------"); + + for (;;) + { + ssize_t n = ACE_OS::read (handle, buf, sizeof buf); + + if (n <= 0) + break; + + ACE_OS::write (ACE_STDOUT, buf, n); + } + + ACE_OS::puts ("----------------------------------------"); + + if (ACE_OS::close (handle) == -1) + return -1; + + return 0; +} + +ACE_INLINE int +Handle_L_CODgram::handle_close (ACE_HANDLE, ACE_Reactor_Mask) +{ + this->ACE_LSOCK_CODgram::close (); + return ACE_OS::unlink (this->rendezvous); +} diff --git a/ACE/examples/Service_Configurator/IPC-tests/server/Handle_L_Dgram.cpp b/ACE/examples/Service_Configurator/IPC-tests/server/Handle_L_Dgram.cpp new file mode 100644 index 00000000000..c502da057f7 --- /dev/null +++ b/ACE/examples/Service_Configurator/IPC-tests/server/Handle_L_Dgram.cpp @@ -0,0 +1,18 @@ +// $Id$ + +#include "Handle_L_Dgram.h" + +ACE_RCSID(server, Handle_L_Dgram, "$Id$") + +#if !defined (ACE_LACKS_UNIX_DOMAIN_SOCKETS) + +const ACE_TCHAR *Handle_L_Dgram::DEFAULT_RENDEZVOUS = + ACE_TEXT ("/tmp/foo_dgram"); + +#if !defined (__ACE_INLINE__) +#include "Handle_L_Dgram.i" +#endif /* __ACE_INLINE__ */ + +Handle_L_Dgram local_dgram; +ACE_Service_Object_Type ld (&local_dgram, ACE_TEXT ("Local_Dgram")); +#endif /* ACE_LACKS_UNIX_DOMAIN_SOCKETS */ diff --git a/ACE/examples/Service_Configurator/IPC-tests/server/Handle_L_Dgram.h b/ACE/examples/Service_Configurator/IPC-tests/server/Handle_L_Dgram.h new file mode 100644 index 00000000000..ac1eac69117 --- /dev/null +++ b/ACE/examples/Service_Configurator/IPC-tests/server/Handle_L_Dgram.h @@ -0,0 +1,51 @@ +// -*- C++ -*- +// $Id$ + +// Handles UNIX datagram messages from local host. + +#ifndef _HANDLE_L_DGRAM_H +#define _HANDLE_L_DGRAM_H + +#include "ace/Service_Config.h" +#include "ace/Reactor.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Service_Types.h" +#include "ace/LSOCK_Dgram.h" +#include "ace/UNIX_Addr.h" +#include "ace/svc_export.h" + +#if !defined (ACE_LACKS_UNIX_DOMAIN_SOCKETS) + +class ACE_Svc_Export Handle_L_Dgram : public ACE_Service_Object, public ACE_LSOCK_Dgram +{ +public: + Handle_L_Dgram (void); + virtual int init (int argc, ACE_TCHAR *argv[]); + virtual int info (ACE_TCHAR **, size_t) const; + virtual int fini (void); + +private: + int open (const ACE_UNIX_Addr &suad, int async = 0); + virtual int get_handle (void) const; + virtual int handle_input (int fd); + virtual int handle_close (int fd, ACE_Reactor_Mask); + + ACE_TCHAR rendezvous[MAXPATHLEN + 1]; + static const ACE_TCHAR *DEFAULT_RENDEZVOUS; +}; + +extern ACE_Service_Object_Type ld; + +#if defined (__ACE_INLINE__) +#define ACE_INLINE inline +#include "Handle_L_Dgram.i" +#else +#define ACE_INLINE +#endif /* __ACE_INLINE__ */ + +#endif /* ACE_LACKS_UNIX_DOMAIN_SOCKETS */ +#endif /* _HANDLE_L_DGRAM_H */ diff --git a/ACE/examples/Service_Configurator/IPC-tests/server/Handle_L_Dgram.i b/ACE/examples/Service_Configurator/IPC-tests/server/Handle_L_Dgram.i new file mode 100644 index 00000000000..3b2ab29331f --- /dev/null +++ b/ACE/examples/Service_Configurator/IPC-tests/server/Handle_L_Dgram.i @@ -0,0 +1,116 @@ +/* -*- C++ -*- */ +// $Id$ + +#include "ace/Get_Opt.h" +#include "ace/OS_NS_stdio.h" +#include "ace/OS_NS_string.h" +#include "ace/OS_NS_unistd.h" + +ACE_INLINE +Handle_L_Dgram::Handle_L_Dgram (void) +{ +} + +ACE_INLINE int +Handle_L_Dgram::open (const ACE_UNIX_Addr &suad, int async) +{ + if (this->ACE_LSOCK_Dgram::open (suad) == -1) + return -1; + else if (async && this->ACE_LSOCK_Dgram::enable (ACE_SIGIO) == -1) + return -1; + else + return 0; +} + +ACE_INLINE int +Handle_L_Dgram::info (ACE_TCHAR **strp, size_t length) const +{ + ACE_TCHAR buf[BUFSIZ]; + ACE_UNIX_Addr sa; + + if (this->ACE_LSOCK_Dgram::get_local_addr (sa) == -1) + return -1; + + ACE_OS::strcpy (buf, ACE_TEXT_CHAR_TO_TCHAR (sa.get_path_name ())); + ACE_OS::strcat (buf, ACE_TEXT (" # tests local datagram\n")); + + if (*strp == 0 && (*strp = ACE_OS::strdup (buf)) == 0) + return -1; + else + ACE_OS::strncpy (*strp, buf, length); + return ACE_OS::strlen (buf); +} + +ACE_INLINE int +Handle_L_Dgram::init (int argc, ACE_TCHAR *argv[]) +{ + ACE_UNIX_Addr sudg; + ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("r:"), 0); + const ACE_TCHAR *r = Handle_L_Dgram::DEFAULT_RENDEZVOUS; + + for (int c; (c = get_opt ()) != -1; ) + switch (c) + { + case 'r': + r = get_opt.opt_arg (); + break; + default: + break; + } + + ACE_OS::strncpy (this->rendezvous, r, MAXPATHLEN); + ACE_OS::unlink (this->rendezvous); + sudg.set (this->rendezvous); + if (this->open (sudg) == -1) + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("open")), -1); + else if (ACE_Reactor::instance ()->register_handler (this, + ACE_Event_Handler::ACCEPT_MASK) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("registering service with ACE_Reactor")), + -1); + return 0; +} + +ACE_INLINE int +Handle_L_Dgram::fini (void) +{ + return ACE_Reactor::instance ()->remove_handler (this, ACE_Event_Handler::ACCEPT_MASK); +} + +ACE_INLINE int +Handle_L_Dgram::get_handle (void) const +{ + return this->ACE_LSOCK_Dgram::get_handle (); +} + +ACE_INLINE int +Handle_L_Dgram::handle_input (int) +{ + ACE_UNIX_Addr sa; + char buf[8 * 1024]; /* 8 k buffer */ + int n; + + if ((n = this->recv (buf, sizeof buf, sa)) == -1) + return -1; + else + ACE_DEBUG ((LM_INFO, ACE_TEXT ("received datagram from %s\n"), + sa.get_path_name ())); + + ACE_OS::puts ("----------------------------------------"); + ACE_OS::write (ACE_STDOUT, buf, n); + + if (buf[n - 1] != '\n') + putchar ('\n'); + + ACE_OS::puts ("----------------------------------------"); + + return 0; +} + +ACE_INLINE int +Handle_L_Dgram::handle_close (int, ACE_Reactor_Mask) +{ + this->ACE_LSOCK_Dgram::close (); + return ACE_OS::unlink (this->rendezvous); +} diff --git a/ACE/examples/Service_Configurator/IPC-tests/server/Handle_L_FIFO.cpp b/ACE/examples/Service_Configurator/IPC-tests/server/Handle_L_FIFO.cpp new file mode 100644 index 00000000000..609f7b3c24f --- /dev/null +++ b/ACE/examples/Service_Configurator/IPC-tests/server/Handle_L_FIFO.cpp @@ -0,0 +1,38 @@ +// $Id$ + +#include "Handle_L_FIFO.h" + +ACE_RCSID(server, Handle_L_FIFO, "$Id$") + +#if defined (SunOS4) +extern "C" +{ + int init (void); + int fini (void); + void __sti__Handle_L_FIFO_C_init_(); + void __std__Handle_L_FIFO_C_init_(); +} + +int +init (void) +{ + __sti__Handle_L_FIFO_C_init_(); + return 0; +} + +int +fini (void) +{ + __std__Handle_L_FIFO_C_init_(); + return 0; +} +#endif /* SunOS4 */ + +const ACE_TCHAR *Handle_L_FIFO::DEFAULT_RENDEZVOUS = ACE_TEXT("/tmp/foo_fifo"); + +#if !defined (__ACE_INLINE__) +#include "Handle_L_FIFO.i" +#endif /* __ACE_INLINE__ */ + +Handle_L_FIFO local_fifo; +ACE_Service_Object_Type lf (&local_fifo, ACE_TEXT("Local_FIFO")); diff --git a/ACE/examples/Service_Configurator/IPC-tests/server/Handle_L_FIFO.h b/ACE/examples/Service_Configurator/IPC-tests/server/Handle_L_FIFO.h new file mode 100644 index 00000000000..4375b2d105c --- /dev/null +++ b/ACE/examples/Service_Configurator/IPC-tests/server/Handle_L_FIFO.h @@ -0,0 +1,49 @@ +// -*- C++ -*- +// +// $Id$ + +/* Handle connections from local UNIX ACE_FIFO */ +/* Read from a well known ACE_FIFO and write to stdout. */ + +#ifndef _HANDLE_L_FIFO_H +#define _HANDLE_L_FIFO_H + +#include "ace/Service_Config.h" +#include "ace/Reactor.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Service_Types.h" +#include "ace/FIFO_Recv_Msg.h" +#include "ace/Log_Msg.h" +#include "ace/svc_export.h" + +class ACE_Svc_Export Handle_L_FIFO : public ACE_Service_Object, public ACE_FIFO_Recv_Msg +{ +public: + Handle_L_FIFO (void); + virtual int init (int argc, ACE_TCHAR *argv[]); + virtual int info (ACE_TCHAR **, size_t) const; + virtual int fini (void); + +private: + int open (const ACE_TCHAR *rendezvous_fifo); + virtual ACE_HANDLE get_handle (void) const; + virtual int handle_input (ACE_HANDLE fd); + virtual int handle_close (ACE_HANDLE fd, ACE_Reactor_Mask); + + static const ACE_TCHAR *DEFAULT_RENDEZVOUS; +}; + +extern ACE_Service_Object_Type lf; + +#if defined (__ACE_INLINE__) +#define ACE_INLINE inline +#include "Handle_L_FIFO.i" +#else +#define ACE_INLINE +#endif /* __ACE_INLINE__ */ + +#endif /* _HANDLE_L_FIFO_H */ diff --git a/ACE/examples/Service_Configurator/IPC-tests/server/Handle_L_FIFO.i b/ACE/examples/Service_Configurator/IPC-tests/server/Handle_L_FIFO.i new file mode 100644 index 00000000000..f6cd0cda734 --- /dev/null +++ b/ACE/examples/Service_Configurator/IPC-tests/server/Handle_L_FIFO.i @@ -0,0 +1,101 @@ +/* -*- C++ -*- */ +// $Id$ + +#include "ace/Get_Opt.h" +#include "ace/OS_NS_stdio.h" +#include "ace/OS_NS_string.h" +#include "ace/OS_NS_stropts.h" +#include "ace/OS_NS_unistd.h" + +ACE_INLINE +Handle_L_FIFO::Handle_L_FIFO (void) +{ +} + +ACE_INLINE int +Handle_L_FIFO::open (const ACE_TCHAR *rendezvous_fifo) +{ + if (this->ACE_FIFO_Recv_Msg::open (rendezvous_fifo) == -1) + return -1; + else + return 0; +} + +ACE_INLINE int +Handle_L_FIFO::info (ACE_TCHAR **strp, size_t length) const +{ + ACE_TCHAR buf[BUFSIZ]; + const ACE_TCHAR *rendezvous_fifo; + + this->get_local_addr (rendezvous_fifo); + + ACE_OS::strcpy (buf, rendezvous_fifo); + ACE_OS::strcat (buf, ACE_TEXT(" # tests local ACE_FIFO\n")); + + if (*strp == 0 && (*strp = ACE_OS::strdup (buf)) == 0) + return -1; + else + ACE_OS::strncpy (*strp, buf, length); + return ACE_OS::strlen (buf); +} + +ACE_INLINE int +Handle_L_FIFO::init (int argc, ACE_TCHAR *argv[]) +{ + const ACE_TCHAR *rendezvous_fifo = Handle_L_FIFO::DEFAULT_RENDEZVOUS; + ACE_Get_Opt get_opt (argc, argv, ACE_TEXT("r:"), 0); + + for (int c; (c = get_opt ()) != -1; ) + switch (c) + { + case 'r': + rendezvous_fifo = get_opt.opt_arg (); + break; + default: + break; + } + + ACE_OS::unlink (rendezvous_fifo); + if (this->open (rendezvous_fifo) == -1) + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("open")), -1); + else if (ACE_Reactor::instance ()->register_handler + (this, ACE_Event_Handler::READ_MASK) == -1) + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), + ACE_TEXT ("registering service with ACE_Reactor")), + -1); + return 0; +} + +ACE_INLINE int +Handle_L_FIFO::fini (void) +{ + return ACE_Reactor::instance ()->remove_handler + (this, ACE_Event_Handler::ACCEPT_MASK); +} + +ACE_INLINE ACE_HANDLE +Handle_L_FIFO::get_handle (void) const +{ + return this->ACE_FIFO::get_handle (); +} + +ACE_INLINE int +Handle_L_FIFO::handle_input (ACE_HANDLE) +{ + char buf[PIPE_BUF]; + ACE_Str_Buf msg (buf, 0, sizeof buf); + + /* Accept communication requests */ + if (this->recv (msg) == -1) + return -1; + else + + ACE_OS::write (ACE_STDOUT, (const char *) msg.buf, (int) msg.len); + return 0; +} + +ACE_INLINE int +Handle_L_FIFO::handle_close (ACE_HANDLE, ACE_Reactor_Mask) +{ + return this->ACE_FIFO::remove (); +} diff --git a/ACE/examples/Service_Configurator/IPC-tests/server/Handle_L_Pipe.cpp b/ACE/examples/Service_Configurator/IPC-tests/server/Handle_L_Pipe.cpp new file mode 100644 index 00000000000..a4508266363 --- /dev/null +++ b/ACE/examples/Service_Configurator/IPC-tests/server/Handle_L_Pipe.cpp @@ -0,0 +1,66 @@ +// $Id$ + +#include "Handle_L_Pipe.h" +#include "ace/OS_NS_ctype.h" +#include "ace/OS_NS_unistd.h" + +ACE_RCSID(server, Handle_L_Pipe, "$Id$") + +#if !defined (ACE_LACKS_UNIX_DOMAIN_SOCKETS) + +// Uppercase N bytes of S. + +char * +Handle_L_Pipe::upper_case (char s[], int n) +{ + while (--n >= 0) + if (ACE_OS::ace_islower (s[n])) + s[n] = ACE_OS::ace_toupper (s[n]); + + return s; +} + +int +Handle_L_Pipe::handle_input (ACE_HANDLE) +{ + ACE_LSOCK_Stream new_local_stream; + int n; + ACE_HANDLE fd1 = ACE_INVALID_HANDLE; + ACE_HANDLE fd2 = ACE_INVALID_HANDLE; + char buf[BUFSIZ]; + + if (this->accept (new_local_stream) == -1) + return -1; + + if (new_local_stream.recv_handle (fd1) == -1 + || new_local_stream.recv_handle (fd2) == -1) + return -1; + else + ACE_DEBUG ((LM_INFO, + ACE_TEXT ("received file descriptors %d and %d\n"), + fd1, + fd2)); + + if ((n = ACE_OS::read (fd1, buf, sizeof buf)) == -1) + return -1; + else if (ACE_OS::write (fd2, this->upper_case (buf, n), n) == -1) + return -1; + if (ACE_OS::close (fd1) == -1 + || ACE_OS::close (fd2) == -1) + return -1; + if (new_local_stream.close () == -1) + return -1; + + return 0; +} + +const ACE_TCHAR *Handle_L_Pipe::DEFAULT_RENDEZVOUS = ACE_TEXT ("/tmp/foo_pipe"); + +#if !defined (__ACE_INLINE__) +#include "Handle_L_Pipe.i" +#endif /* __ACE_INLINE__ */ + +Handle_L_Pipe local_pipe; +ACE_Service_Object_Type lp (&local_pipe, ACE_TEXT ("Local_Pipe")); + +#endif /* ACE_LACKS_UNIX_DOMAIN_SOCKETS */ diff --git a/ACE/examples/Service_Configurator/IPC-tests/server/Handle_L_Pipe.h b/ACE/examples/Service_Configurator/IPC-tests/server/Handle_L_Pipe.h new file mode 100644 index 00000000000..51d5bae1dac --- /dev/null +++ b/ACE/examples/Service_Configurator/IPC-tests/server/Handle_L_Pipe.h @@ -0,0 +1,55 @@ +// -*- C++ -*- +// $Id$ + +// Handle connections from local UNIX domain sockets that are sending +// end-points from a pipe! + +#ifndef _HANDLE_L_PIPE_H +#define _HANDLE_L_PIPE_H + +#include "ace/Service_Config.h" +#include "ace/Reactor.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Service_Types.h" +#include "ace/UNIX_Addr.h" +#include "ace/LSOCK_Acceptor.h" +#include "ace/svc_export.h" + +#if !defined (ACE_LACKS_UNIX_DOMAIN_SOCKETS) + +class ACE_Svc_Export Handle_L_Pipe : public ACE_Service_Object, public ACE_LSOCK_Acceptor +{ +public: + Handle_L_Pipe (void); + ~Handle_L_Pipe (void); + virtual int init (int argc, ACE_TCHAR *argv[]); + virtual int info (ACE_TCHAR **, size_t) const; + virtual int fini (void); + +private: + int open (const ACE_UNIX_Addr &suap, int async = 0); + virtual ACE_HANDLE get_handle (void) const; + virtual int handle_input (ACE_HANDLE fd); + virtual int handle_close (ACE_HANDLE fd, ACE_Reactor_Mask); + + char *upper_case (char s[], int n); + + ACE_TCHAR rendezvous[MAXPATHLEN + 1]; + static const ACE_TCHAR *DEFAULT_RENDEZVOUS; +}; + +extern ACE_Service_Object_Type lp; + +#if defined (__ACE_INLINE__) +#define ACE_INLINE inline +#include "Handle_L_Pipe.i" +#else +#define ACE_INLINE +#endif /* __ACE_INLINE__ */ + +#endif /* ACE_LACKS_UNIX_DOMAIN_SOCKETS */ +#endif /* _HANDLE_L_PIPE_H */ diff --git a/ACE/examples/Service_Configurator/IPC-tests/server/Handle_L_Pipe.i b/ACE/examples/Service_Configurator/IPC-tests/server/Handle_L_Pipe.i new file mode 100644 index 00000000000..ce978aa85ea --- /dev/null +++ b/ACE/examples/Service_Configurator/IPC-tests/server/Handle_L_Pipe.i @@ -0,0 +1,96 @@ +/* -*- C++ -*- */ +// $Id$ + +#include "ace/Get_Opt.h" +#include "ace/OS_NS_stdio.h" +#include "ace/OS_NS_string.h" +#include "ace/OS_NS_unistd.h" + +ACE_INLINE +Handle_L_Pipe::~Handle_L_Pipe (void) +{ +} + +ACE_INLINE +Handle_L_Pipe::Handle_L_Pipe (void) +{ +} + +ACE_INLINE int +Handle_L_Pipe::open (const ACE_UNIX_Addr &suap, int async) +{ + if (this->ACE_LSOCK_Acceptor::open (suap) == -1) + return -1; + else if (async && this->ACE_LSOCK_Acceptor::enable (ACE_SIGIO) == -1) + return -1; + else + return 0; +} + +ACE_INLINE int +Handle_L_Pipe::info (ACE_TCHAR **strp, size_t length) const +{ + ACE_TCHAR buf[BUFSIZ]; + ACE_UNIX_Addr sa; + + if (ACE_LSOCK_Acceptor::get_local_addr (sa) == -1) + return -1; + + ACE_OS::strcpy (buf, ACE_TEXT_CHAR_TO_TCHAR (sa.get_path_name ())); + ACE_OS::strcat (buf, ACE_TEXT (" # tests local pipe\n")); + + if (*strp == 0 && (*strp = ACE_OS::strdup (buf)) == 0) + return -1; + else + ACE_OS::strncpy (*strp, buf, length); + return ACE_OS::strlen (buf); +} + +ACE_INLINE int +Handle_L_Pipe::init (int argc, ACE_TCHAR *argv[]) +{ + ACE_UNIX_Addr sup; + const ACE_TCHAR *r = Handle_L_Pipe::DEFAULT_RENDEZVOUS; + ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("r:"), 0); + + for (int c; (c = get_opt ()) != -1; ) + switch (c) + { + case 'r': + r = get_opt.opt_arg (); + break; + default: + break; + } + + ACE_OS::strncpy (this->rendezvous, r, MAXPATHLEN); + ACE_OS::unlink (this->rendezvous); + sup.set (this->rendezvous); + if (this->open (sup) == -1) + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("open")), -1); + else if (ACE_Reactor::instance ()->register_handler + (this, ACE_Event_Handler::ACCEPT_MASK) == -1) + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), + ACE_TEXT ("registering service with ACE_Reactor")), -1); + return 0; +} + +ACE_INLINE int +Handle_L_Pipe::fini (void) +{ + return ACE_Reactor::instance ()->remove_handler + (this, ACE_Event_Handler::ACCEPT_MASK); +} + +ACE_INLINE int +Handle_L_Pipe::get_handle (void) const +{ + return ACE_LSOCK_Acceptor::get_handle (); +} + +ACE_INLINE int +Handle_L_Pipe::handle_close (ACE_HANDLE, ACE_Reactor_Mask) +{ + this->ACE_LSOCK_Acceptor::close (); + return ACE_OS::unlink (this->rendezvous); +} diff --git a/ACE/examples/Service_Configurator/IPC-tests/server/Handle_L_SPIPE.cpp b/ACE/examples/Service_Configurator/IPC-tests/server/Handle_L_SPIPE.cpp new file mode 100644 index 00000000000..9bbb4e7ead7 --- /dev/null +++ b/ACE/examples/Service_Configurator/IPC-tests/server/Handle_L_SPIPE.cpp @@ -0,0 +1,18 @@ +// $Id$ + +#include "Handle_L_SPIPE.h" + +ACE_RCSID(server, Handle_L_SPIPE, "$Id$") + +#if !defined (__ACE_INLINE__) +#include "Handle_L_SPIPE.i" +#endif /* __ACE_INLINE__ */ + +#if defined (ACE_HAS_STREAM_PIPES) + +const ACE_TCHAR *Handle_L_SPIPE::DEFAULT_RENDEZVOUS = ACE_TEXT ("/tmp/foo_spipe"); + +Handle_L_SPIPE local_spipe; +ACE_Service_Object_Type lsp (&local_spipe, ACE_TEXT ("Local_SPIPE")); + +#endif /* ACE_HAS_STREAM_PIPES */ diff --git a/ACE/examples/Service_Configurator/IPC-tests/server/Handle_L_SPIPE.h b/ACE/examples/Service_Configurator/IPC-tests/server/Handle_L_SPIPE.h new file mode 100644 index 00000000000..02a4aba2044 --- /dev/null +++ b/ACE/examples/Service_Configurator/IPC-tests/server/Handle_L_SPIPE.h @@ -0,0 +1,52 @@ +/* -*- C++ -*- */ +// $Id$ + +/* Handle connections from local UNIX ACE_SPIPE */ +/* Read from a well known ACE_SPIPE and write to stdout. */ + +#ifndef _HANDLE_L_SPIPE_H +#define _HANDLE_L_SPIPE_H + +#include "ace/Service_Config.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Service_Types.h" +#include "ace/SPIPE_Acceptor.h" +#include "ace/Log_Msg.h" +#include "ace/svc_export.h" + +#if defined (ACE_HAS_STREAM_PIPES) + +class ACE_Svc_Export Handle_L_SPIPE : public ACE_Service_Object, public ACE_SPIPE_Acceptor +{ +public: + Handle_L_SPIPE (void); + virtual int init (int argc, ACE_TCHAR *argv[]); + virtual int info (ACE_TCHAR **, size_t) const; + virtual int fini (void); + +private: + int open (const ACE_SPIPE_Addr &rendezvous_spipe); + virtual int get_handle (void) const; + virtual int handle_input (int fd); + virtual int handle_close (int fd, ACE_Reactor_Mask); + + static const ACE_TCHAR *DEFAULT_RENDEZVOUS; +}; + +extern ACE_Service_Object_Type lsp; + +#if defined (__ACE_INLINE__) +#define ACE_INLINE inline +#include "Handle_L_SPIPE.i" +#else +#define ACE_INLINE +#endif /* __ACE_INLINE__ */ + +#endif /* _HANDLE_L_SPIPE_H */ + + +#endif /* ACE_HAS_STREAM_PIPES */ diff --git a/ACE/examples/Service_Configurator/IPC-tests/server/Handle_L_SPIPE.i b/ACE/examples/Service_Configurator/IPC-tests/server/Handle_L_SPIPE.i new file mode 100644 index 00000000000..910938d8648 --- /dev/null +++ b/ACE/examples/Service_Configurator/IPC-tests/server/Handle_L_SPIPE.i @@ -0,0 +1,131 @@ +// -*- C++ -*- +// +// $Id$ + + +#include "ace/SPIPE_Stream.h" + +#if defined (ACE_HAS_STREAM_PIPES) + +#include "ace/Reactor.h" +#include "ace/Get_Opt.h" +#include "ace/OS_NS_stdio.h" +#include "ace/OS_NS_unistd.h" +#include "ace/OS_NS_string.h" + + +ACE_INLINE +Handle_L_SPIPE::Handle_L_SPIPE (void) +{ +} + +ACE_INLINE int +Handle_L_SPIPE::open (const ACE_SPIPE_Addr &rendezvous_spipe) +{ + if (this->ACE_SPIPE_Acceptor::open (rendezvous_spipe) == -1) + return -1; + else + return 0; +} + +ACE_INLINE int +Handle_L_SPIPE::info (ACE_TCHAR **strp, size_t length) const +{ + ACE_TCHAR buf[BUFSIZ]; + ACE_SPIPE_Addr sa; + + if (ACE_SPIPE_Acceptor::get_local_addr (sa) == -1) + return -1; + + ACE_OS::strcpy (buf, sa.get_path_name ()); + ACE_OS::strcat (buf, ACE_TEXT (" # tests local STREAM pipe\n")); + + if (*strp == 0 && (*strp = ACE_OS::strdup (buf)) == 0) + return -1; + else + ACE_OS::strncpy (*strp, buf, length); + return ACE_OS::strlen (buf); +} + +ACE_INLINE int +Handle_L_SPIPE::init (int argc, ACE_TCHAR *argv[]) +{ + ACE_SPIPE_Addr susp; + const ACE_TCHAR *rendezvous = Handle_L_SPIPE::DEFAULT_RENDEZVOUS; + ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("r:"), 0); + + for (int c; (c = get_opt ()) != -1; ) + switch (c) + { + case 'r': + rendezvous = get_opt.opt_arg (); + break; + default: + break; + } + + ACE_OS::unlink (rendezvous); + susp.set (rendezvous); + if (this->open (susp) == -1) + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("open")), -1); + else if (ACE_Reactor::instance ()->register_handler + (this, ACE_Event_Handler::ACCEPT_MASK) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("registering service with ACE_Reactor")), + -1); + return 0; +} + +ACE_INLINE int +Handle_L_SPIPE::fini (void) +{ + return ACE_Reactor::instance ()->remove_handler + (this, ACE_Event_Handler::ACCEPT_MASK); +} + +ACE_INLINE int +Handle_L_SPIPE::get_handle (void) const +{ + return ACE_SPIPE::get_handle(); +} + +ACE_INLINE int +Handle_L_SPIPE::handle_input (int) +{ + ACE_SPIPE_Stream new_spipe; + char buf[PIPE_BUF]; + ACE_Str_Buf msg (buf, 0, sizeof buf); + int flags = 0; + + /* Accept communication requests */ + if (this->ACE_SPIPE_Acceptor::accept (new_spipe) == -1) + return -1; + else + { + ACE_SPIPE_Addr sa; + + new_spipe.get_remote_addr (sa); + + ACE_DEBUG ((LM_INFO, + ACE_TEXT ("accepted request from %s (gid = %d, uid = %d)\n"), + sa.get_path_name (), sa.group_id (), sa.user_id ())); + } + + while (new_spipe.recv ((ACE_Str_Buf *) 0, &msg, &flags) >= 0) + if (msg.len != 0) + ACE_OS::write (ACE_STDOUT, (const char *) msg.buf, (int) msg.len); + else + break; + + if (new_spipe.close () == -1) + return -1; + return 0; +} + +ACE_INLINE int +Handle_L_SPIPE::handle_close (int, ACE_Reactor_Mask) +{ + return this->ACE_SPIPE_Acceptor::remove (); +} +#endif /* ACE_HAS_STREAM_PIPES */ diff --git a/ACE/examples/Service_Configurator/IPC-tests/server/Handle_L_Stream.cpp b/ACE/examples/Service_Configurator/IPC-tests/server/Handle_L_Stream.cpp new file mode 100644 index 00000000000..074f0057e74 --- /dev/null +++ b/ACE/examples/Service_Configurator/IPC-tests/server/Handle_L_Stream.cpp @@ -0,0 +1,22 @@ +// $Id$ + +#include "Handle_L_Stream.h" + +ACE_RCSID(server, Handle_L_Stream, "$Id$") + +#if !defined (ACE_LACKS_UNIX_DOMAIN_SOCKETS) + +// Static variables. + +const ACE_TCHAR *Handle_L_Stream::DEFAULT_RENDEZVOUS = ACE_TEXT ("/tmp/foo_stream"); +char *Handle_L_Stream::login_name = 0; +char Handle_L_Stream::login[ACE_MAX_USERID]; + +#if !defined (__ACE_INLINE__) +#include "Handle_L_Stream.i" +#endif /* __ACE_INLINE__ */ + +Handle_L_Stream local_stream; +ACE_Service_Object_Type ls (&local_stream, ACE_TEXT ("Local_Stream")); + +#endif /* ACE_LACKS_UNIX_DOMAIN_SOCKETS */ diff --git a/ACE/examples/Service_Configurator/IPC-tests/server/Handle_L_Stream.h b/ACE/examples/Service_Configurator/IPC-tests/server/Handle_L_Stream.h new file mode 100644 index 00000000000..912af48a292 --- /dev/null +++ b/ACE/examples/Service_Configurator/IPC-tests/server/Handle_L_Stream.h @@ -0,0 +1,53 @@ +// -*- C++ -*- +// $Id$ + +// Handle connections from local UNIX domain sockets. + +#ifndef _HANDLE_L_STREAM_H +#define _HANDLE_L_STREAM_H + +#include "ace/Service_Config.h" +#include "ace/Reactor.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Service_Types.h" +#include "ace/UNIX_Addr.h" +#include "ace/LSOCK_Acceptor.h" +#include "ace/svc_export.h" + +#if !defined (ACE_LACKS_UNIX_DOMAIN_SOCKETS) + +class ACE_Svc_Export Handle_L_Stream : public ACE_Service_Object, public ACE_LSOCK_Acceptor +{ +public: + Handle_L_Stream (void); + ~Handle_L_Stream (void); + virtual int init (int argc, ACE_TCHAR *argv[]); + virtual int info (ACE_TCHAR **, size_t) const; + virtual int fini (void); + +private: + int open (const ACE_UNIX_Addr &suas, int async = 0); + virtual ACE_HANDLE get_handle (void) const; + virtual int handle_input (ACE_HANDLE fd); + virtual int handle_close (ACE_HANDLE fd, ACE_Reactor_Mask); + + ACE_TCHAR rendezvous[MAXPATHLEN + 1]; + static const ACE_TCHAR *DEFAULT_RENDEZVOUS; + static char *login_name; + static char login[ACE_MAX_USERID]; +}; + +extern ACE_Service_Object_Type ls; + +#if defined (__ACE_INLINE__) +#define ACE_INLINE inline +#include "Handle_L_Stream.i" +#else +#define ACE_INLINE +#endif /* __ACE_INLINE__ */ +#endif /* ACE_LACKS_UNIX_DOMAIN_SOCKETS */ +#endif /* _HANDLE_L_STREAM_H */ diff --git a/ACE/examples/Service_Configurator/IPC-tests/server/Handle_L_Stream.i b/ACE/examples/Service_Configurator/IPC-tests/server/Handle_L_Stream.i new file mode 100644 index 00000000000..80b21852293 --- /dev/null +++ b/ACE/examples/Service_Configurator/IPC-tests/server/Handle_L_Stream.i @@ -0,0 +1,149 @@ +/* -*- C++ -*- */ +// $Id$ + +#include "ace/Get_Opt.h" +#include "ace/OS_NS_stdio.h" +#include "ace/OS_NS_string.h" +#include "ace/OS_NS_time.h" +#include "ace/OS_NS_unistd.h" + +ACE_INLINE +Handle_L_Stream::~Handle_L_Stream (void) +{ +} + +ACE_INLINE +Handle_L_Stream::Handle_L_Stream (void) +{ + if (Handle_L_Stream::login_name == 0) + Handle_L_Stream::login_name = ACE_OS::cuserid (Handle_L_Stream::login); +} + +ACE_INLINE int +Handle_L_Stream::open (const ACE_UNIX_Addr &suas, + int async) +{ + if (this->ACE_LSOCK_Acceptor::open (suas) == -1) + return -1; + else if (async && this->ACE_LSOCK_Acceptor::enable (ACE_SIGIO) == -1) + return -1; + else + return 0; +} + +ACE_INLINE int +Handle_L_Stream::info (ACE_TCHAR **strp, size_t length) const +{ + ACE_TCHAR buf[BUFSIZ]; + ACE_UNIX_Addr sa; + + if (this->get_local_addr (sa) == -1) + return -1; + + ACE_OS::strcpy (buf, ACE_TEXT_CHAR_TO_TCHAR (sa.get_path_name ())); + ACE_OS::strcat (buf, ACE_TEXT (" # tests local ACE_Stream\n")); + + if (*strp == 0 && (*strp = ACE_OS::strdup (buf)) == 0) + return -1; + else + ACE_OS::strncpy (*strp, buf, length); + return ACE_OS::strlen (buf); +} + +ACE_INLINE int +Handle_L_Stream::init (int argc, ACE_TCHAR *argv[]) +{ + ACE_UNIX_Addr sus; + const ACE_TCHAR *r = Handle_L_Stream::DEFAULT_RENDEZVOUS; + ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("r:"), 0); + + for (int c; (c = get_opt ()) != -1; ) + switch (c) + { + case 'r': + r = get_opt.opt_arg (); + break; + default: + break; + } + + ACE_OS::strncpy (this->rendezvous, r, MAXPATHLEN); + ACE_OS::unlink (this->rendezvous); + sus.set (this->rendezvous); + + if (this->open (sus) == -1) + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("open")), -1); + else if (ACE_Reactor::instance ()->register_handler + (this, ACE_Event_Handler::ACCEPT_MASK) == -1) + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), + ACE_TEXT ("registering service with ACE_Reactor")), -1); + return 0; +} + +ACE_INLINE int +Handle_L_Stream::fini (void) +{ + return ACE_Reactor::instance ()->remove_handler + (this, ACE_Event_Handler::ACCEPT_MASK); +} + +ACE_INLINE ACE_HANDLE +Handle_L_Stream::get_handle (void) const +{ + return ACE_LSOCK_Acceptor::get_handle (); +} + +ACE_INLINE int +Handle_L_Stream::handle_input (ACE_HANDLE) +{ + ACE_LSOCK_Stream new_local_stream; + ACE_UNIX_Addr sa; + ACE_HANDLE handle = ACE_INVALID_HANDLE; + char buf[BUFSIZ]; + + if (this->accept (new_local_stream, &sa) == -1) + return -1; + else if (new_local_stream.recv_handle (handle) == -1) + return -1; + else + ACE_DEBUG ((LM_INFO, + ACE_TEXT ("received file descriptor %d on ACE_Stream %s\n"), + handle, sa.get_path_name ())); + + ACE_OS::puts ("----------------------------------------"); + + for (;;) + { + ssize_t n = ACE_OS::read (handle, buf, sizeof buf); + + if (n <= 0) + break; + + ACE_OS::write (ACE_STDOUT, buf, n); + } + + ACE_OS::puts ("----------------------------------------"); + + time_t t = ACE_OS::time (0L); + ACE_TCHAR *cs = ACE_OS::ctime (&t); + + if (new_local_stream.send (4, + Handle_L_Stream::login_name, + ACE_OS::strlen (Handle_L_Stream::login_name), + ACE_TEXT_ALWAYS_CHAR (cs), + ACE_OS::strlen (cs)) == -1) + return -1; + else if (ACE_OS::close (handle) == -1) + return -1; + else if (new_local_stream.close () == -1) + return -1; + else + return 0; +} + +ACE_INLINE int +Handle_L_Stream::handle_close (ACE_HANDLE, ACE_Reactor_Mask) +{ + this->ACE_LSOCK_Acceptor::close (); + return ACE_OS::unlink (this->rendezvous); +} diff --git a/ACE/examples/Service_Configurator/IPC-tests/server/Handle_R_Dgram.cpp b/ACE/examples/Service_Configurator/IPC-tests/server/Handle_R_Dgram.cpp new file mode 100644 index 00000000000..0cab7190ca8 --- /dev/null +++ b/ACE/examples/Service_Configurator/IPC-tests/server/Handle_R_Dgram.cpp @@ -0,0 +1,38 @@ +// $Id$ + +#include "Handle_R_Dgram.h" + +ACE_RCSID(server, Handle_R_Dgram, "Handle_R_Dgram.cpp,v 4.2 1998/07/31 22:55:19 gonzo Exp") + +#if defined (SunOS4) +extern "C" +{ + int init (void); + int fini (void); + void __sti__Handle_R_Dgram_C_init_(); + void __std__Handle_R_Dgram_C_init_(); +} + +int +init (void) +{ + __sti__Handle_R_Dgram_C_init_(); + return 0; +} + +int +fini (void) +{ + __std__Handle_R_Dgram_C_init_(); + return 0; +} +#endif /* SunOS4 */ + +unsigned short Handle_R_Dgram::DEFAULT_PORT = ACE_DEFAULT_SERVER_PORT; + +#if !defined (__ACE_INLINE__) +#include "Handle_R_Dgram.i" +#endif /* __ACE_INLINE__ */ + +Handle_R_Dgram remote_dgram; +ACE_Service_Object_Type rd (&remote_dgram, ACE_TEXT ("Remote_Dgram")); diff --git a/ACE/examples/Service_Configurator/IPC-tests/server/Handle_R_Dgram.h b/ACE/examples/Service_Configurator/IPC-tests/server/Handle_R_Dgram.h new file mode 100644 index 00000000000..858d72ff993 --- /dev/null +++ b/ACE/examples/Service_Configurator/IPC-tests/server/Handle_R_Dgram.h @@ -0,0 +1,47 @@ +// -*- C++ -*- +// $Id$ + +/* Handles INET datagram messages from remote hosts. */ + +#ifndef _HANDLE_R_DGRAM_H +#define _HANDLE_R_DGRAM_H + +#include "ace/Service_Config.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Service_Types.h" +#include "ace/INET_Addr.h" +#include "ace/SOCK_Dgram.h" +#include "ace/Log_Msg.h" +#include "ace/svc_export.h" + +class ACE_Svc_Export Handle_R_Dgram : public ACE_Service_Object, public ACE_SOCK_Dgram +{ +public: + Handle_R_Dgram (void); + virtual int init (int argc, ACE_TCHAR *argv[]); + virtual int info (ACE_TCHAR **, size_t) const; + virtual int fini (void); + +private: + int open (const ACE_INET_Addr &r, int async = 0); + virtual ACE_HANDLE get_handle (void) const; + virtual int handle_input (ACE_HANDLE fd); + virtual int handle_close (ACE_HANDLE fd, ACE_Reactor_Mask); + + static u_short DEFAULT_PORT; +}; + +extern ACE_Service_Object_Type rd; + +#if defined (__ACE_INLINE__) +#define ACE_INLINE inline +#include "Handle_R_Dgram.i" +#else +#define ACE_INLINE +#endif /* __ACE_INLINE__ */ + +#endif /* _HANDLE_R_DGRAM_H */ diff --git a/ACE/examples/Service_Configurator/IPC-tests/server/Handle_R_Dgram.i b/ACE/examples/Service_Configurator/IPC-tests/server/Handle_R_Dgram.i new file mode 100644 index 00000000000..88212a988f0 --- /dev/null +++ b/ACE/examples/Service_Configurator/IPC-tests/server/Handle_R_Dgram.i @@ -0,0 +1,111 @@ +/* -*- C++ -*- */ +// $Id$ + +#include "ace/Get_Opt.h" +#include "ace/OS_NS_stdio.h" +#include "ace/OS_NS_string.h" +#include "ace/OS_NS_unistd.h" + +ACE_INLINE +Handle_R_Dgram::Handle_R_Dgram (void) +{ +} + +ACE_INLINE int +Handle_R_Dgram::open (const ACE_INET_Addr &r, int async) +{ + if (this->ACE_SOCK_Dgram::open (r) == -1) + return -1; + else if (async && this->ACE_SOCK_Dgram::enable (ACE_SIGIO) == -1) + return -1; + else + return 0; +} + +ACE_INLINE int +Handle_R_Dgram::info (ACE_TCHAR **strp, size_t length) const +{ + ACE_TCHAR buf[BUFSIZ]; + ACE_INET_Addr sa; + + if (this->get_local_addr (sa) == -1) + return -1; + + ACE_OS::sprintf (buf, ACE_TEXT ("%d/"), sa.get_port_number ()); + ACE_OS::strcat (buf, ACE_TEXT ("udp # tests remote dgram\n")); + + if (*strp == 0 && (*strp = ACE_OS::strdup (buf)) == 0) + return -1; + else + ACE_OS::strncpy (*strp, buf, length); + return ACE_OS::strlen (buf); +} + +ACE_INLINE int +Handle_R_Dgram::init (int argc, ACE_TCHAR *argv[]) +{ + ACE_INET_Addr sidg (Handle_R_Dgram::DEFAULT_PORT); + ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("p:"), 0); + + for (int c; (c = get_opt ()) != -1; ) + switch (c) + { + case 'p': + sidg.set (ACE_OS::atoi (get_opt.opt_arg ())); + break; + default: + break; + } + + if (this->open (sidg) == -1) + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("open")), -1); + else if (ACE_Reactor::instance ()->register_handler + (this, ACE_Event_Handler::ACCEPT_MASK) == -1) + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), + ACE_TEXT ("registering service with ACE_Reactor")), -1); + return 0; +} + +ACE_INLINE int +Handle_R_Dgram::fini (void) +{ + return ACE_Reactor::instance ()->remove_handler + (this, ACE_Event_Handler::ACCEPT_MASK); +} + +ACE_INLINE ACE_HANDLE +Handle_R_Dgram::get_handle (void) const +{ + return ACE_SOCK_Dgram::get_handle (); +} + +ACE_INLINE int +Handle_R_Dgram::handle_input (ACE_HANDLE) +{ + ACE_INET_Addr sa; + char buf[8 * 1024]; /* 8 k buffer */ + ssize_t n = this->recv (buf, sizeof buf, sa); + + if (n == -1) + return -1; + else + ACE_DEBUG ((LM_INFO, + ACE_TEXT ("received datagram from host %C on port %d\n"), + sa.get_host_name (), sa.get_port_number ())); + + ACE_OS::puts ("----------------------------------------"); + ACE_OS::write (ACE_STDOUT, buf, n); + + if (buf[n - 1] != '\n') + putchar ('\n'); + + ACE_OS::puts ("----------------------------------------"); + + return 0; +} + +ACE_INLINE int +Handle_R_Dgram::handle_close (ACE_HANDLE, ACE_Reactor_Mask) +{ + return this->ACE_SOCK_Dgram::close (); +} diff --git a/ACE/examples/Service_Configurator/IPC-tests/server/Handle_R_Stream.cpp b/ACE/examples/Service_Configurator/IPC-tests/server/Handle_R_Stream.cpp new file mode 100644 index 00000000000..95553833e72 --- /dev/null +++ b/ACE/examples/Service_Configurator/IPC-tests/server/Handle_R_Stream.cpp @@ -0,0 +1,42 @@ +// $Id$ + +#include "Handle_R_Stream.h" + +ACE_RCSID(server, Handle_R_Stream, "$Id$") + +#if defined (SunOS4) +extern "C" +{ + int init (void); + int fini (void); + void __sti__Handle_R_Stream_C_recv_n_(); + void __std__Handle_R_Stream_C_recv_n_(); +} + +int +init (void) +{ + __sti__Handle_R_Stream_C_recv_n_(); + return 0; +} + +int +fini (void) +{ + __std__Handle_R_Stream_C_recv_n_(); + return 0; +} +#endif /* SunOS4 */ + +// Static variables. + +u_short Handle_R_Stream::DEFAULT_PORT = ACE_DEFAULT_SERVER_PORT; +char *Handle_R_Stream::login_name = 0; +char Handle_R_Stream::login[ACE_MAX_USERID]; + +#if !defined (__ACE_INLINE__) +#include "Handle_R_Stream.i" +#endif /* __ACE_INLINE__ */ + +Handle_R_Stream remote_stream; +ACE_Service_Object_Type rs (&remote_stream, ACE_TEXT("Remote_Stream")); diff --git a/ACE/examples/Service_Configurator/IPC-tests/server/Handle_R_Stream.h b/ACE/examples/Service_Configurator/IPC-tests/server/Handle_R_Stream.h new file mode 100644 index 00000000000..9878321cec8 --- /dev/null +++ b/ACE/examples/Service_Configurator/IPC-tests/server/Handle_R_Stream.h @@ -0,0 +1,53 @@ +// -*- C++ -*- +// +// $Id$ + +/* Handle connections from remote INET connections. */ + +#ifndef _HANDLE_R_STREAM_H +#define _HANDLE_R_STREAM_H + +#include "ace/Service_Config.h" +#include "ace/Reactor.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Service_Types.h" +#include "ace/SOCK_Stream.h" +#include "ace/SOCK_Acceptor.h" +#include "ace/INET_Addr.h" +#include "ace/Log_Msg.h" +#include "ace/svc_export.h" + +class ACE_Svc_Export Handle_R_Stream : public ACE_Service_Object, public ACE_SOCK_Acceptor +{ +public: + Handle_R_Stream (void); + virtual int init (int argc, ACE_TCHAR *argv[]); + virtual int info (ACE_TCHAR **, size_t) const; + virtual int fini (void); + +private: + int open (const ACE_INET_Addr &sia, int async = 0); + virtual ACE_HANDLE get_handle (void) const; + virtual int handle_input (ACE_HANDLE fd); + virtual int handle_close (ACE_HANDLE fd, ACE_Reactor_Mask); + + ACE_SOCK_Stream new_remote_stream; + static u_short DEFAULT_PORT; + static char *login_name; + static char login[ACE_MAX_USERID]; +}; + +extern ACE_Service_Object_Type rs; + +#if defined (__ACE_INLINE__) +#define ACE_INLINE inline +#include "Handle_R_Stream.i" +#else +#define ACE_INLINE +#endif /* __ACE_INLINE__ */ + +#endif /* _HANDLE_R_STREAM_H */ diff --git a/ACE/examples/Service_Configurator/IPC-tests/server/Handle_R_Stream.i b/ACE/examples/Service_Configurator/IPC-tests/server/Handle_R_Stream.i new file mode 100644 index 00000000000..f126cd13aee --- /dev/null +++ b/ACE/examples/Service_Configurator/IPC-tests/server/Handle_R_Stream.i @@ -0,0 +1,153 @@ +/* -*- C++ -*- */ +// $Id$ + +#include "ace/Get_Opt.h" +#include "ace/WFMO_Reactor.h" +#include "ace/OS_NS_stdio.h" +#include "ace/OS_NS_string.h" +#include "ace/OS_NS_time.h" +#include "ace/OS_NS_unistd.h" + +ACE_INLINE +Handle_R_Stream::Handle_R_Stream (void) +{ + if (Handle_R_Stream::login_name == 0) + Handle_R_Stream::login_name = ACE_OS::cuserid (Handle_R_Stream::login); +} + +ACE_INLINE int +Handle_R_Stream::open (const ACE_INET_Addr &sia, int async) +{ + if (this->ACE_SOCK_Acceptor::open (sia) == -1) + return -1; + else if (async && this->ACE_SOCK_Acceptor::enable (ACE_SIGIO) == -1) + return -1; + else + return 0; +} + +ACE_INLINE int +Handle_R_Stream::info (ACE_TCHAR **strp, size_t length) const +{ + ACE_TCHAR buf[BUFSIZ]; + ACE_INET_Addr sa; + + if (this->get_local_addr (sa) == -1) + return -1; + + ACE_OS::sprintf (buf, + ACE_TEXT("%d/%s %s"), + sa.get_port_number (), + ACE_TEXT("tcp"), + ACE_TEXT("# tests remote stream\n")); + + if (*strp == 0 && (*strp = ACE_OS::strdup (buf)) == 0) + return -1; + else + ACE_OS::strncpy (*strp, buf, length); + return ACE_OS::strlen (buf); +} + +ACE_INLINE int +Handle_R_Stream::init (int argc, ACE_TCHAR *argv[]) +{ + ACE_INET_Addr sis (Handle_R_Stream::DEFAULT_PORT); + ACE_Get_Opt get_opt (argc, argv, ACE_TEXT("p:"), 0); + + for (int c; (c = get_opt ()) != -1; ) + switch (c) + { + case 'p': + sis.set (ACE_OS::atoi (get_opt.opt_arg ())); + break; + default: + break; + } + + if (this->open (sis) == -1) + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "open"), -1); + + else if (ACE_Reactor::instance ()->register_handler + (this, ACE_Event_Handler::ACCEPT_MASK) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "registering service with ACE_Reactor\n"), + -1); + return 0; +} + +ACE_INLINE int +Handle_R_Stream::fini (void) +{ + return ACE_Reactor::instance ()->remove_handler + (this, ACE_Event_Handler::ACCEPT_MASK); +} + +ACE_INLINE ACE_HANDLE +Handle_R_Stream::get_handle (void) const +{ + return ACE_SOCK_Acceptor::get_handle (); +} + +ACE_INLINE int +Handle_R_Stream::handle_input (ACE_HANDLE) +{ + char buf[BUFSIZ]; + int bytes; + + // Try to find out if the implementation of the reactor that we are + // using requires us to reset the event association for the newly + // created handle. This is because the newly created handle will + // inherit the properties of the listen handle, including its event + // associations. + int reset_new_handle = + ACE_Reactor::instance ()->uses_event_associations (); + + if (this->accept (this->new_remote_stream, // stream + 0, // remote address + 0, // timeout + 1, // restart + reset_new_handle // reset new handler + ) == -1) + return -1; + else + ACE_DEBUG ((LM_INFO, "new_remote_stream fd = %d\n", + this->new_remote_stream.get_handle ())); + + ACE_INET_Addr sa; + + if (this->new_remote_stream.get_remote_addr (sa) == -1) + return -1; + + ACE_DEBUG ((LM_INFO, + "accepted from host %s at port %d\n", + sa.get_host_name (), + sa.get_port_number ())); + + ACE_OS::puts (ACE_TEXT ("----------------------------------------")); + + while ((bytes = this->new_remote_stream.recv (buf, sizeof buf)) > 0) + ACE_OS::write (ACE_STDOUT, buf, bytes); + + ACE_OS::puts (ACE_TEXT ("----------------------------------------")); + + time_t t = ACE_OS::time (0L); + ACE_TCHAR *cs = ACE_OS::ctime (&t); + + if (this->new_remote_stream.send (4, + Handle_R_Stream::login_name, + ACE_OS::strlen (Handle_R_Stream::login_name), + cs, + ACE_OS::strlen (cs)) == -1) + return -1; + + if (this->new_remote_stream.close () == -1) + return -1; + + return 0; +} + +ACE_INLINE int +Handle_R_Stream::handle_close (ACE_HANDLE, ACE_Reactor_Mask) +{ + return this->ACE_SOCK_Acceptor::close (); +} diff --git a/ACE/examples/Service_Configurator/IPC-tests/server/Handle_Thr_Stream.cpp b/ACE/examples/Service_Configurator/IPC-tests/server/Handle_Thr_Stream.cpp new file mode 100644 index 00000000000..fb53c0f8d70 --- /dev/null +++ b/ACE/examples/Service_Configurator/IPC-tests/server/Handle_Thr_Stream.cpp @@ -0,0 +1,195 @@ +// $Id$ + +#if !defined (ACE_HANDLE_THR_STREAM_C) +#define ACE_HANDLE_THR_STREAM_C + +#include "ace/OS_NS_stdio.h" +#include "ace/OS_NS_string.h" +#include "ace/OS_NS_unistd.h" +#include "ace/Get_Opt.h" +#include "ace/INET_Addr.h" +#include "ace/TLI_Acceptor.h" +#include "Handle_Thr_Stream.h" + +ACE_RCSID(server, Handle_Thr_Stream, "$Id$") + +#if defined (ACE_HAS_THREADS) + +#include "ace/OS_NS_time.h" + +// Shorthand names. +#define SVH SVC_HANDLER +#define PR_AC_1 ACE_PEER_ACCEPTOR_1 +#define PR_AC_2 ACE_PEER_ACCEPTOR_2 +#define PR_ST_1 ACE_PEER_STREAM_1 +#define PR_ST_2 ACE_PEER_STREAM_2 + +template <class SVH, PR_AC_1> +Handle_Thr_Acceptor<SVH, PR_AC_2>::~Handle_Thr_Acceptor (void) +{ +} + +template <class SVH, PR_AC_1> +Handle_Thr_Acceptor<SVH, PR_AC_2>::Handle_Thr_Acceptor (void) + : thr_flags_ (THR_DETACHED | THR_NEW_LWP) +{ +} + +template <class SVH, PR_AC_1> int +Handle_Thr_Acceptor<SVH, PR_AC_2>::info (ACE_TCHAR **strp, + size_t length) const +{ + ACE_TCHAR buf[BUFSIZ]; + ACE_INET_Addr sa; + + if (this->acceptor ().get_local_addr (sa) == -1) + return -1; + + ACE_OS::sprintf (buf, ACE_TEXT("%d/"), sa.get_port_number ()); + ACE_OS::strcat (buf, ACE_TEXT("tcp # tests threaded remote stream\n")); + + if (*strp == 0 && (*strp = ACE_OS::strdup (buf)) == 0) + return -1; + else + ACE_OS::strncpy (*strp, buf, length); + return ACE_OS::strlen (buf); +} + +template <class SVH, PR_AC_1> int +Handle_Thr_Acceptor<SVH, PR_AC_2>::init (int argc, ACE_TCHAR *argv[]) +{ + ACE_INET_Addr local_addr (ACE_DEFAULT_THR_PORT); + int n_threads = ACE_DEFAULT_THREADS; + + ACE_Get_Opt get_opt (argc, argv, ACE_TEXT("p:t:"), 0); + + for (int c; (c = get_opt ()) != -1; ) + switch (c) + { + case 'p': + local_addr.set (ACE_OS::atoi (get_opt.opt_arg ())); + break; + case 't': + n_threads = ACE_OS::atoi (get_opt.opt_arg ()); + break; + default: + break; + } + + // Initialize the threading strategy. + if (this->thr_strategy_.open (&this->thr_mgr_, + this->thr_flags_, + n_threads) == -1) + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("open")), -1); + + // Initialize the Acceptor base class, passing in the desired + // concurrency strategy. + else if (this->open (local_addr, + ACE_Reactor::instance (), + 0, + 0, + &this->thr_strategy_) == -1) + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("open")), -1); + else + return 0; +} + +template <class SVH, PR_AC_1> int +Handle_Thr_Acceptor<SVH, PR_AC_2>::fini (void) +{ + return ACE_Reactor::instance ()->remove_handler + (this, ACE_Event_Handler::ACCEPT_MASK); +} + +template <PR_ST_1> +CLI_Stream<PR_ST_2>::CLI_Stream (ACE_Thread_Manager *thr_mgr) + : inherited (thr_mgr) +{ +} + +template <PR_ST_1> int +CLI_Stream<PR_ST_2>::close (u_long) +{ + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%t) client stream object closing down\n"))); + this->peer ().close (); + + // Must be allocated dynamically! + delete this; + return 0; +} + +template <PR_ST_1> int +CLI_Stream<PR_ST_2>::open (void *) +{ + ACE_INET_Addr sa; + + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) client handle = %d\n"), + this->peer ().get_handle ())); + + if (this->peer ().get_remote_addr (sa) == -1) + return -1; + + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) accepted at port %d\n"), + sa.get_port_number ())); + return 0; +} + +template <PR_ST_1> int +CLI_Stream<PR_ST_2>::svc (void) +{ + char buf[BUFSIZ]; + char login_name[ACE_MAX_USERID]; + int bytes; + + ACE_OS::puts ("----------------------------------------"); + + while ((bytes = this->peer ().recv (buf, sizeof buf)) > 0) + ACE_OS::write (ACE_STDOUT, buf, bytes); + + ACE_OS::puts ("----------------------------------------"); + ACE_OS::fflush (stdout); + + time_t t = ACE_OS::time (0L); + ACE_OS::cuserid (login_name); + ACE_OS::sprintf (buf, "user %s %s", + login_name, + ACE_TEXT_ALWAYS_CHAR (ACE_OS::ctime ((const time_t *) &t))); + + if (this->peer ().send_n (buf, ACE_OS::strlen (buf) + 1) == -1) + return -1; + + ACE_DEBUG ((LM_DEBUG, "(%t) sent reply %s", buf)); + return 0; +} + +#undef SVH +#undef PR_AC_1 +#undef PR_AC_2 +#undef PR_ST_1 +#undef PR_ST_2 + +//---------------------------------------- + +#if defined (ACE_HAS_TLI) +#include "ace/TLI_Stream.h" +#include "ace/TLI_Acceptor.h" +#define THR_STREAM ACE_TLI_STREAM +#define THR_ACCEPTOR ACE_TLI_ACCEPTOR +#else +#include "ace/SOCK_Stream.h" +#include "ace/SOCK_Acceptor.h" +#define THR_STREAM ACE_SOCK_STREAM +#define THR_ACCEPTOR ACE_SOCK_ACCEPTOR +#endif /* ACE_HAS_TLI */ +#include "ace/INET_Addr.h" + +typedef CLI_Stream <THR_STREAM> CLI_STREAM; +typedef Handle_Thr_Acceptor<CLI_STREAM, THR_ACCEPTOR> HANDLE_THR_ACCEPTOR; + +// Service object. +HANDLE_THR_ACCEPTOR remote_thr_stream; +ACE_Service_Object_Type rts (&remote_thr_stream, ACE_TEXT("Remote_Thr_Stream")); + +#endif /* ACE_HAS_THREADS */ +#endif /* ACE_HANDLE_THR_STREAM_C */ diff --git a/ACE/examples/Service_Configurator/IPC-tests/server/Handle_Thr_Stream.h b/ACE/examples/Service_Configurator/IPC-tests/server/Handle_Thr_Stream.h new file mode 100644 index 00000000000..994a70009c0 --- /dev/null +++ b/ACE/examples/Service_Configurator/IPC-tests/server/Handle_Thr_Stream.h @@ -0,0 +1,73 @@ +/* -*- C++ -*- */ +// $Id$ + +#ifndef _HANDLE_THR_STREAM_H +#define _HANDLE_THR_STREAM_H + +#include "ace/Acceptor.h" +#include "ace/Svc_Handler.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Service_Types.h" + +#if defined (ACE_HAS_THREADS) + +template <class SVC_HANDLER, ACE_PEER_ACCEPTOR_1> +class Handle_Thr_Acceptor : public ACE_Strategy_Acceptor<SVC_HANDLER, ACE_PEER_ACCEPTOR_2> + // = TITLE + // This factory creates new <SVC_HANDLERS> and runs them with the + // configured <ACE_Thread_Strategy>. +{ +public: + // = Initialization and termination. + Handle_Thr_Acceptor (void); + ~Handle_Thr_Acceptor (void); + + // = Dynamic linking hooks. + virtual int init (int argc, ACE_TCHAR *argv[]); + virtual int info (ACE_TCHAR **, size_t) const; + virtual int fini (void); + +private: + ACE_Thread_Manager thr_mgr_; + // Thread manager. + + ACE_Thread_Strategy<SVC_HANDLER> thr_strategy_; + // Threading strategy. + + int thr_flags_; + // Threading flags. +}; + +template <ACE_PEER_STREAM_1> +class CLI_Stream : public ACE_Svc_Handler<ACE_PEER_STREAM_2, ACE_MT_SYNCH> + // = TITLE + // This class interacts with the client, running in a separate + // thread and handles connections from remote TCP/IP connections. +{ +public: + CLI_Stream (ACE_Thread_Manager * = 0); + + virtual int open (void *); + // Open the service. + + virtual int close (u_long); + // Close down the service. + + virtual int svc (void); + // Execute the service. + +protected: + typedef ACE_Svc_Handler<ACE_PEER_STREAM_2, ACE_MT_SYNCH> inherited; +}; + +extern ACE_Service_Object_Type rts; + +#if defined (ACE_TEMPLATES_REQUIRE_SOURCE) +#include "Handle_Thr_Stream.cpp" +#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */ +#endif /* ACE_HAS_THREADS */ +#endif /* _HANDLE_THR_STREAM_H */ diff --git a/ACE/examples/Service_Configurator/IPC-tests/server/Handle_Timeout.cpp b/ACE/examples/Service_Configurator/IPC-tests/server/Handle_Timeout.cpp new file mode 100644 index 00000000000..9eccf88ef43 --- /dev/null +++ b/ACE/examples/Service_Configurator/IPC-tests/server/Handle_Timeout.cpp @@ -0,0 +1,36 @@ +// $Id$ + +#include "Handle_Timeout.h" + +ACE_RCSID(server, Handle_Timeout, "$Id$") + +#if defined (SunOS4) +extern "C" +{ + int init (void); + int fini (void); + void __sti__Handle_Timeout_C_init_(); + void __std__Handle_Timeout_C_init_(); +} + +int +init (void) +{ + __sti__Handle_Timeout_C_init_(); + return 0; +} + +int +fini (void) +{ + __std__Handle_Timeout_C_init_(); + return 0; +} +#endif /* SunOS4 */ + +#if !defined (__ACE_INLINE__) +#include "Handle_Timeout.i" +#endif /* __ACE_INLINE__ */ + +Handle_Timeout timer_1; +ACE_Service_Object_Type t1 (&timer_1, ACE_TEXT("Timer_1")); diff --git a/ACE/examples/Service_Configurator/IPC-tests/server/Handle_Timeout.h b/ACE/examples/Service_Configurator/IPC-tests/server/Handle_Timeout.h new file mode 100644 index 00000000000..88b6e673aaf --- /dev/null +++ b/ACE/examples/Service_Configurator/IPC-tests/server/Handle_Timeout.h @@ -0,0 +1,45 @@ +// -*- C++ -*- +// +// $Id$ + +/* Handles timeouts. */ + +#ifndef _HANDLE_TIMEOUT_H +#define _HANDLE_TIMEOUT_H + +#include "ace/Service_Config.h" +#include "ace/Reactor.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Service_Types.h" +#include "ace/Log_Msg.h" +#include "ace/svc_export.h" + +class ACE_Svc_Export Handle_Timeout : public ACE_Service_Object +{ +public: + Handle_Timeout (void); + virtual int init (int argc, ACE_TCHAR *argv[]); + virtual int info (ACE_TCHAR **, size_t) const; + virtual int fini (void); + +private: + virtual ACE_HANDLE get_handle (void) const; + virtual int handle_timeout (const ACE_Time_Value &tv, const void *arg); + + int count; +}; + +extern ACE_Service_Object_Type t1; + +#if defined (__ACE_INLINE__) +#define ACE_INLINE inline +#include "Handle_Timeout.i" +#else +#define ACE_INLINE +#endif /* __ACE_INLINE__ */ + +#endif /* _HANDLE_TIMEOUT_H */ diff --git a/ACE/examples/Service_Configurator/IPC-tests/server/Handle_Timeout.i b/ACE/examples/Service_Configurator/IPC-tests/server/Handle_Timeout.i new file mode 100644 index 00000000000..346a22e773c --- /dev/null +++ b/ACE/examples/Service_Configurator/IPC-tests/server/Handle_Timeout.i @@ -0,0 +1,86 @@ +/* -*- C++ -*- */ +// $Id$ + +#include "ace/Service_Config.h" +#include "ace/Get_Opt.h" +#include "ace/OS_NS_stdio.h" +#include "ace/OS_NS_string.h" + +ACE_INLINE +Handle_Timeout::Handle_Timeout (void): count (0) +{ +} + +ACE_INLINE int +Handle_Timeout::info (ACE_TCHAR **strp, size_t length) const +{ + ACE_TCHAR buf[BUFSIZ]; + + ACE_OS::strcpy (buf, ACE_TEXT("# tests timeout facility\n")); + + if (*strp == 0 && (*strp = ACE_OS::strdup (buf)) == 0) + return -1; + else + ACE_OS::strncpy (*strp, buf, length); + return ACE_OS::strlen (buf); +} + +ACE_INLINE int +Handle_Timeout::init (int argc, ACE_TCHAR *argv[]) +{ + ACE_Time_Value delta (10); + ACE_Time_Value interval (1); + ACE_Get_Opt get_opt (argc, argv, ACE_TEXT("a:d:i:"), 0); + int arg = 0; + + for (int c; (c = get_opt ()) != -1; ) + switch (c) + { + case 'd': + delta.sec (ACE_OS::atoi (get_opt.opt_arg ())); + break; + case 'i': + interval.sec (ACE_OS::atoi (get_opt.opt_arg ())); + break; + case 'a': + arg = ACE_OS::atoi (get_opt.opt_arg ()); + break; + default: + break; + } + + if (ACE_Reactor::instance ()->schedule_timer (this, + reinterpret_cast<void *> (arg), + delta, + interval) == -1) + return -1; + else + return 0; +} + +ACE_INLINE int +Handle_Timeout::fini (void) +{ + return 0; +} + +ACE_INLINE ACE_HANDLE +Handle_Timeout::get_handle (void) const +{ + return ACE_INVALID_HANDLE; +} + +ACE_INLINE int +Handle_Timeout::handle_timeout (const ACE_Time_Value &tv, + const void *arg) +{ + if (this->count++ >= 10) + return -1; // Automatically cancel periodic timer... + + // Cast arg to a long, first, because a pointer is the same + // size as a long on all current ACE platforms. + ACE_DEBUG ((LM_INFO, + ACE_TEXT ("time for this(%u) expired at (%d, %d) with arg = %d\n"), + this, tv.sec (), tv.usec (), (int) (long) arg)); + return 0; +} diff --git a/ACE/examples/Service_Configurator/IPC-tests/server/Makefile.am b/ACE/examples/Service_Configurator/IPC-tests/server/Makefile.am new file mode 100644 index 00000000000..58a8a80fccf --- /dev/null +++ b/ACE/examples/Service_Configurator/IPC-tests/server/Makefile.am @@ -0,0 +1,106 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +ACE_BUILDDIR = $(top_builddir) +ACE_ROOT = $(top_srcdir) + + +## Makefile.Svc_Cfg_IPC_Server_Lib.am + +if !BUILD_ACE_FOR_TAO + +noinst_LTLIBRARIES = libIPC_Tests_Server.la + +libIPC_Tests_Server_la_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) \ + -DACE_BUILD_SVC_DLL + +libIPC_Tests_Server_la_SOURCES = \ + Handle_Broadcast.cpp \ + Handle_L_CODgram.cpp \ + Handle_L_Dgram.cpp \ + Handle_L_FIFO.cpp \ + Handle_L_Pipe.cpp \ + Handle_L_SPIPE.cpp \ + Handle_L_Stream.cpp \ + Handle_R_Stream.cpp \ + Handle_Thr_Stream.cpp \ + Handle_Timeout.cpp + +noinst_HEADERS = \ + Handle_Broadcast.h \ + Handle_Broadcast.i \ + Handle_L_CODgram.h \ + Handle_L_CODgram.i \ + Handle_L_Dgram.h \ + Handle_L_Dgram.i \ + Handle_L_FIFO.h \ + Handle_L_FIFO.i \ + Handle_L_Pipe.h \ + Handle_L_Pipe.i \ + Handle_L_SPIPE.h \ + Handle_L_SPIPE.i \ + Handle_L_Stream.h \ + Handle_L_Stream.i \ + Handle_R_Stream.h \ + Handle_R_Stream.i \ + Handle_Thr_Stream.h \ + Handle_Timeout.h \ + Handle_Timeout.i + +endif !BUILD_ACE_FOR_TAO + +## Makefile.Svc_Cfg_IPC_Server_Test.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS = server_test + +server_test_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +server_test_SOURCES = \ + server_test.cpp \ + Handle_Broadcast.h \ + Handle_Broadcast.i \ + Handle_L_CODgram.h \ + Handle_L_CODgram.i \ + Handle_L_Dgram.h \ + Handle_L_Dgram.i \ + Handle_L_FIFO.h \ + Handle_L_FIFO.i \ + Handle_L_Pipe.h \ + Handle_L_Pipe.i \ + Handle_L_SPIPE.h \ + Handle_L_SPIPE.i \ + Handle_L_Stream.h \ + Handle_L_Stream.i \ + Handle_R_Dgram.h \ + Handle_R_Dgram.i \ + Handle_R_Stream.h \ + Handle_R_Stream.i \ + Handle_Thr_Stream.h \ + Handle_Timeout.h \ + Handle_Timeout.i + +server_test_LDADD = \ + libIPC_Tests_Server.la \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Clean up template repositories, etc. +clean-local: + -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.* + -rm -f gcctemp.c gcctemp so_locations *.ics + -rm -rf cxx_repository ptrepository ti_files + -rm -rf templateregistry ir.out + -rm -rf ptrepository SunWS_cache Templates.DB diff --git a/ACE/examples/Service_Configurator/IPC-tests/server/Svc_Cfg_IPC_Server.mpc b/ACE/examples/Service_Configurator/IPC-tests/server/Svc_Cfg_IPC_Server.mpc new file mode 100644 index 00000000000..c44b40c6e32 --- /dev/null +++ b/ACE/examples/Service_Configurator/IPC-tests/server/Svc_Cfg_IPC_Server.mpc @@ -0,0 +1,30 @@ +// -*- MPC -*- +// $Id$ + +project(*Lib) : acelib { + avoids += ace_for_tao + sharedname = IPC_Tests_Server + dynamicflags += ACE_BUILD_SVC_DLL + Source_Files { + Handle_Broadcast.cpp + Handle_L_CODgram.cpp + Handle_L_Dgram.cpp + Handle_L_FIFO.cpp + Handle_L_Pipe.cpp + Handle_L_SPIPE.cpp + Handle_L_Stream.cpp + Handle_R_Stream.cpp + Handle_Thr_Stream.cpp + Handle_Timeout.cpp + } +} + +project(*test) : aceexe { + avoids += ace_for_tao + exename = server_test + after += Svc_Cfg_IPC_Server_Lib + libs += IPC_Tests_Server + Source_Files { + server_test.cpp + } +} diff --git a/ACE/examples/Service_Configurator/IPC-tests/server/server_test.cpp b/ACE/examples/Service_Configurator/IPC-tests/server/server_test.cpp new file mode 100644 index 00000000000..fe88a3eab8e --- /dev/null +++ b/ACE/examples/Service_Configurator/IPC-tests/server/server_test.cpp @@ -0,0 +1,54 @@ +// $Id$ + +// The main test driver for the dynamically configured server. + +#include "ace/OS_NS_unistd.h" +#include "ace/Service_Config.h" +#include "ace/Reactor.h" +#include "ace/Log_Msg.h" +#include "ace/Signal.h" +#include "ace/Sig_Adapter.h" + +ACE_RCSID(server, server_test, "$Id$") + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + if (ACE_Service_Config::open (argc, + argv, + ACE_DEFAULT_LOGGER_KEY, + 0) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("ACE_Service_Config::open")), + -1); + + // Create an adapter to end the event loop. + ACE_Sig_Adapter sa ((ACE_Sig_Handler_Ex) ACE_Reactor::end_event_loop); + + ACE_Sig_Set sig_set; + sig_set.sig_add (SIGINT); + sig_set.sig_add (SIGQUIT); + + // Register ourselves to receive signals so we can shut down + // gracefully. + if (ACE_Reactor::instance ()->register_handler (sig_set, + &sa) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), ACE_TEXT ("register_handler")), + -1); + + // This makes the README demo even easier (for sighup). + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("pid = %d\n"), + ACE_OS::getpid ())); + + // Run forever, performing the configured services until we are shut + // down by a SIGINT/SIGQUIT signal. + + // We use this version of the event loop so that reconfigurations + // are triggered properly. + ACE_Reactor::run_event_loop (); + + return 0; +} diff --git a/ACE/examples/Service_Configurator/IPC-tests/server/svc.conf b/ACE/examples/Service_Configurator/IPC-tests/server/svc.conf new file mode 100644 index 00000000000..6f4e70a3ca5 --- /dev/null +++ b/ACE/examples/Service_Configurator/IPC-tests/server/svc.conf @@ -0,0 +1,19 @@ +# To configure different services, simply uncomment the appropriate lines in this file! +static ACE_Service_Manager "-d -p 3911" +dynamic Remote_Brdcast Service_Object * ./IPC_Tests_Server:remote_broadcast "-p 10001" +dynamic Remote_Stream Service_Object * ./IPC_Tests_Server:remote_stream "-p 20002" +dynamic Remote_Dgram Service_Object * ./IPC_Tests_Server:remote_dgram "-p 15001" +dynamic Timer_1 Service_Object * ./IPC_Tests_Server:timer_1 "-d 5 -i 1 -a 100" +dynamic Local_Stream Service_Object * ./IPC_Tests_Server:local_stream "-r /tmp/foo_stream" +dynamic Local_Pipe Service_Object * ./IPC_Tests_Server:local_pipe "-r /tmp/foo_pipe" +dynamic Local_Fifo Service_Object * ./IPC_Tests_Server:local_fifo "-r /tmp/foo_fifo" +dynamic Local_Dgram Service_Object * ./IPC_Tests_Server:local_dgram "-r /tmp/foo_dgram" +dynamic Local_CODgram Service_Object * ./IPC_Tests_Server:local_codgram "-r /tmp/foo_codgram" +dynamic Local_Spipe Service_Object * ./IPC_Tests_Server:local_spipe "-r /tmp/foo_spipe" +dynamic Remote_Thr_Stream Service_Object * ./IPC_Tests_Server:remote_thr_stream "-p 10001" +#suspend Remote_Stream +#resume Local_SPIPE +#resume Remote_Stream +#remove Remote_Stream +#remove Local_Stream + diff --git a/ACE/examples/Service_Configurator/Makefile.am b/ACE/examples/Service_Configurator/Makefile.am new file mode 100644 index 00000000000..1b78bb27757 --- /dev/null +++ b/ACE/examples/Service_Configurator/Makefile.am @@ -0,0 +1,14 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +SUBDIRS = \ + IPC-tests \ + Misc + diff --git a/ACE/examples/Service_Configurator/Misc/.cvsignore b/ACE/examples/Service_Configurator/Misc/.cvsignore new file mode 100644 index 00000000000..ba2906d0666 --- /dev/null +++ b/ACE/examples/Service_Configurator/Misc/.cvsignore @@ -0,0 +1 @@ +main diff --git a/ACE/examples/Service_Configurator/Misc/Makefile.am b/ACE/examples/Service_Configurator/Misc/Makefile.am new file mode 100644 index 00000000000..f0de4232add --- /dev/null +++ b/ACE/examples/Service_Configurator/Misc/Makefile.am @@ -0,0 +1,50 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +ACE_BUILDDIR = $(top_builddir) +ACE_ROOT = $(top_srcdir) + +## Makefile.Service_Configurator_Misc_Timer.am + +noinst_LTLIBRARIES = libtimer.la + +libtimer_la_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) \ + -DACE_BUILD_SVC_DLL + +libtimer_la_SOURCES = \ + Timer_Service.cpp + +noinst_HEADERS = \ + Timer_Service.h + +## Makefile.Service_Configurator_Misc_Main.am +noinst_PROGRAMS = main + +main_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +main_SOURCES = \ + main.cpp \ + Timer_Service.h + +main_LDADD = \ + libtimer.la \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Clean up template repositories, etc. +clean-local: + -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.* + -rm -f gcctemp.c gcctemp so_locations *.ics + -rm -rf cxx_repository ptrepository ti_files + -rm -rf templateregistry ir.out + -rm -rf ptrepository SunWS_cache Templates.DB diff --git a/ACE/examples/Service_Configurator/Misc/README b/ACE/examples/Service_Configurator/Misc/README new file mode 100644 index 00000000000..c3b22759926 --- /dev/null +++ b/ACE/examples/Service_Configurator/Misc/README @@ -0,0 +1,23 @@ +This directory contains an example that illustrates how the ACE +Service Configurator can configure static and dynamic services, both +from the command-line and from a svc.config file. We define several +instances, i.e., Timer_Service_1 and Timer_Service_2 of the SAME +service just to exercise different configuration options. A "real" +application would usually define different services. + +Windows CE: +----------- + +When using Windows CE (WCE) emulator, make sure that you use the +following command to copy the svc.conf files into the top-level +directory in CE emulator. + + empfile -c svc.conf1 wce:\svc.conf1 + empfile -c svc.conf2 wce:\svc.conf2 + +The command "empfile" moves the files to emulator's root directory and +resigters the files with CE emulator's object store. + +Also make sure you type in at least one argument (which is argv[0],) +when the program dialog box requests you to key in the program +arguments. Otherwise, the program won't run at all. diff --git a/ACE/examples/Service_Configurator/Misc/Service_Configurator_Misc.mpc b/ACE/examples/Service_Configurator/Misc/Service_Configurator_Misc.mpc new file mode 100644 index 00000000000..9c9744fd601 --- /dev/null +++ b/ACE/examples/Service_Configurator/Misc/Service_Configurator_Misc.mpc @@ -0,0 +1,18 @@ +// -*- MPC -*- +// $Id$ + +project(*Timer) : acelib { + sharedname = timer + dynamicflags += ACE_BUILD_SVC_DLL + Source_Files { + Timer_Service.cpp + } +} +project(*Main) : aceexe { + exename = main + after += Service_Configurator_Misc_Timer + libs += timer + Source_Files { + main.cpp + } +} diff --git a/ACE/examples/Service_Configurator/Misc/Timer_Service.cpp b/ACE/examples/Service_Configurator/Misc/Timer_Service.cpp new file mode 100644 index 00000000000..82ace8f657c --- /dev/null +++ b/ACE/examples/Service_Configurator/Misc/Timer_Service.cpp @@ -0,0 +1,135 @@ +// $Id$ + +#include "ace/OS_NS_string.h" +#include "Timer_Service.h" +#include "ace/Log_Msg.h" + +ACE_RCSID(Misc, Timer_Service, "$Id$") + +Timer_Service_1::Timer_Service_1 (void) +{ + ACE_OS::strcpy (this->name_, + ACE_TEXT ("Timer_Service_1")); +} + +int +Timer_Service_1::init (int argc, ACE_TCHAR *argv[]) +{ + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("in Timer_Service::init, argv[0] = %s, argc == %d\n"), + argv[0], argc)); + + // Printout the <argv> values for sanity's sake. + for (int i = 0; i < argc; i++) + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("argv[%d] = %s\n"), + i, argv[i])); + + int interval = Timer_Service_1::TIMEOUT; + + if (argc > 1) + { + // If the second argument exists use this as the interval for + // the periodic timer. Otherwise, go off every TIMEOUT seconds. + + interval = ACE_OS::atoi (argv[1]); + + if (interval == 0) + interval = Timer_Service_1::TIMEOUT; + } + + if (argc > 2) + { + // If the third argument exists use it to control the maximum + // number of timeouts. + this->max_timeouts_ = ACE_OS::atoi (argv[2]); + + if (this->max_timeouts_ == 0) + this->max_timeouts_ = Timer_Service_1::MAX_TIMEOUTS; + } + + this->cur_timeouts_ = 0; + + // If the fourth argument exists take this as an indication to + // enable tracing. +#if defined (ACE_HAS_TRACE) + if (argc > 3) + ACE_Trace::start_tracing (); + else + ACE_Trace::stop_tracing (); +#endif /* ACE_HAS_TRACE */ + + // Register the timer to go off in 1 second, and then to go off + // every <interval> seconds. + if (ACE_Reactor::instance ()->schedule_timer + (this, + 0, + ACE_Time_Value (1), + ACE_Time_Value (interval)) == -1) + return -1; + else + return 0; +} + +int +Timer_Service_1::handle_timeout (const ACE_Time_Value &tv, + const void *) +{ + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%x) in %s::handle_timeout sec = %d, usec = %d") + ACE_TEXT (" cur_timeouts = %d, max_timeouts = %d\n"), + this, + this->name_, + tv.sec (), + tv.usec (), + this->cur_timeouts_, + this->max_timeouts_)); + + this->cur_timeouts_++; + + if (this->cur_timeouts_ == this->max_timeouts_) + // Shutdown the test. + return -1; + else + return 0; +} + +int +Timer_Service_1::handle_close (ACE_HANDLE, + ACE_Reactor_Mask) +{ + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("closing down the timer test\n"))); + + // Remove ourselves from the timer queue. + ACE_Reactor::instance ()->cancel_timer (this); + + ACE_Reactor::end_event_loop(); + return 0; +} + +Timer_Service_2::Timer_Service_2 (void) +{ + ACE_OS::strcpy (this->name_, + ACE_TEXT ("Timer_Service_2")); +} + +Timer_Service_3::Timer_Service_3 (void) +{ + ACE_OS::strcpy (this->name_, + ACE_TEXT ("Timer_Service_3")); +} + +// Define the object that describes the service. +ACE_STATIC_SVC_DEFINE (Timer_Service_1, + ACE_TEXT ("Timer_Service_1"), + ACE_SVC_OBJ_T, + &ACE_SVC_NAME (Timer_Service_1), + ACE_Service_Type::DELETE_THIS | ACE_Service_Type::DELETE_OBJ, + 0) + +// The following are "Factories" used by the <ACE_Service_Config> and +// svc.conf file to dynamically initialize the state of the Timer +// Services. +ACE_SVC_FACTORY_DEFINE (Timer_Service_1) +ACE_SVC_FACTORY_DEFINE (Timer_Service_2) +ACE_SVC_FACTORY_DEFINE (Timer_Service_3) diff --git a/ACE/examples/Service_Configurator/Misc/Timer_Service.h b/ACE/examples/Service_Configurator/Misc/Timer_Service.h new file mode 100644 index 00000000000..01aa77b7317 --- /dev/null +++ b/ACE/examples/Service_Configurator/Misc/Timer_Service.h @@ -0,0 +1,71 @@ +// -*- C++ -*- +// +// $Id$ + +#include "ace/svc_export.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Service_Config.h" +#include "ace/Reactor.h" +#include "ace/Service_Object.h" + + +class ACE_Svc_Export Timer_Service_1 : public ACE_Service_Object +{ + // = TITLE + // Demonstrates a simple timer service that can be configured + // statically. +public: + Timer_Service_1 (void); + // Default constructor. + + virtual int init (int argc, ACE_TCHAR *argv[]); + // Initialization hook. + + virtual int handle_timeout (const ACE_Time_Value &, + const void *); + // Timeout hook. + + virtual int handle_close (ACE_HANDLE, ACE_Reactor_Mask); + // Close hook. + +protected: + ACE_TCHAR name_[BUFSIZ]; + // Keep track of which service this is! + +private: + enum + { + TIMEOUT = 4, // Wait 4 seconds between timeouts + MAX_TIMEOUTS = 10 // Don't timeout for more than 10 times. + }; + + int max_timeouts_; + // Maximum number of timeouts before shutting down the test. + + int cur_timeouts_; + // Current number of timeouts. +}; + +class ACE_Svc_Export Timer_Service_2 : public Timer_Service_1 +{ +public: + Timer_Service_2 (void); + // Default constructor. +}; + +class ACE_Svc_Export Timer_Service_3 : public Timer_Service_1 +{ +public: + Timer_Service_3 (void); + // Default constructor. +}; + +// Declare both static and dynamic services. +ACE_STATIC_SVC_DECLARE_EXPORT (ACE_Svc, Timer_Service_1) +ACE_SVC_FACTORY_DECLARE (Timer_Service_1) +ACE_SVC_FACTORY_DECLARE (Timer_Service_2) +ACE_SVC_FACTORY_DECLARE (Timer_Service_3) diff --git a/ACE/examples/Service_Configurator/Misc/main.cpp b/ACE/examples/Service_Configurator/Misc/main.cpp new file mode 100644 index 00000000000..a7ff6c9da26 --- /dev/null +++ b/ACE/examples/Service_Configurator/Misc/main.cpp @@ -0,0 +1,80 @@ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// examples/Service_Configurator/Misc +// +// = FILENAME +// main.cpp +// +// = DESCRIPTION +// This directory contains an example that illustrates how the ACE +// Service Configurator can configure static and dynamic services, +// both from the command-line and from a svc.config file. +// +// = AUTHOR +// Doug Schmidt <schmidt@cs.wustl.edu> +// +// ============================================================================ + +#include "ace/OS_main.h" +#include "ace/Service_Config.h" +#include "ace/ARGV.h" +#include "ace/Log_Msg.h" +#include "Timer_Service.h" + +ACE_RCSID(Misc, main, "$Id$") + +// Create an object that will insert the <Timer_Service> into the list +// of statically linked services that the <ACE_Service_Config> will +// process at run-time. +ACE_STATIC_SVC_REQUIRE (Timer_Service_1) + +int +ACE_TMAIN (int, ACE_TCHAR *argv[]) +{ + // Set up an argument vector that we can add entries to! + ACE_ARGV args; + + // Manufacture a "fake" svc.conf entry to demonstrate the -S option + // that allows us to pass these entries via the "command-line" + // rather than the svc.conf file. + args.add (argv[0]); + args.add (ACE_TEXT ("-y")); + args.add (ACE_TEXT ("-d")); + args.add (ACE_TEXT ("-S")); + args.add (ACE_TEXT ("\"static Timer_Service_1 'timer 1 10 $TRACE'\"")); + args.add (ACE_TEXT ("-S")); + args.add (ACE_TEXT ("\"dynamic Timer_Service_2 Service_Object * ./Timer:_make_Timer_Service_2() 'timer 2 10 $TRACE'\"")); + // Test the -f option! + args.add (ACE_TEXT ("-fsvc.conf1")); + args.add (ACE_TEXT ("-fsvc.conf2")); + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("argc = %d\n"), + args.argc ())); + + // Print the contents of the combined <ACE_ARGV>. + for (int i = 0; i < args.argc (); i++) + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%d) %s\n"), + i, + args.argv ()[i])); + + int result = ACE_Service_Config::open (args.argc (), + args.argv (), + ACE_DEFAULT_LOGGER_KEY, + 0); + if (result != 0) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("open")), + 1); + + // Run forever, performing the configured services until we + // shutdown. + + ACE_Reactor::run_event_loop (); + return 0; +} diff --git a/ACE/examples/Service_Configurator/Misc/svc.conf1 b/ACE/examples/Service_Configurator/Misc/svc.conf1 new file mode 100644 index 00000000000..d0f552caa6e --- /dev/null +++ b/ACE/examples/Service_Configurator/Misc/svc.conf1 @@ -0,0 +1,8 @@ +# Dynamically configure the Timer_Service into the application process +# and pass in up to 4 arguments. The final 3 arguments are retrieved +# from environment variables, so they can be set by changing your +# environment before running the main program. If you don't have +# these variables set they are ignored. +dynamic Timer_Service_3 Service_Object * + ./Timer:_make_Timer_Service_3() + "timer $INTERVAL $MAX_TIMEOUTS $TRACE" diff --git a/ACE/examples/Service_Configurator/Misc/svc.conf2 b/ACE/examples/Service_Configurator/Misc/svc.conf2 new file mode 100644 index 00000000000..1bef63e8d48 --- /dev/null +++ b/ACE/examples/Service_Configurator/Misc/svc.conf2 @@ -0,0 +1,8 @@ +# Statically configure the Timer_Service, which must have been linked +# statically into the application process. Up to 4 arguments are +# passed in. The final 3 arguments are retrieved from environment +# variables, so they can be set by changing your environment before +# running the main program. If you don't have these variables set +# they are ignored. +static Timer_Service_1 + "timer $INTERVAL $MAX_TIMEOUTS $TRACE" diff --git a/ACE/examples/Shared_Malloc/.cvsignore b/ACE/examples/Shared_Malloc/.cvsignore new file mode 100644 index 00000000000..c5ad2e56e0e --- /dev/null +++ b/ACE/examples/Shared_Malloc/.cvsignore @@ -0,0 +1,4 @@ +malloc +multiple +persistence +posind diff --git a/ACE/examples/Shared_Malloc/Makefile.am b/ACE/examples/Shared_Malloc/Makefile.am new file mode 100644 index 00000000000..baccb0359e0 --- /dev/null +++ b/ACE/examples/Shared_Malloc/Makefile.am @@ -0,0 +1,106 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +ACE_BUILDDIR = $(top_builddir) +ACE_ROOT = $(top_srcdir) + +noinst_PROGRAMS = + +## Makefile.Shared_Malloc.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS += malloc + +malloc_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +malloc_SOURCES = \ + Malloc.cpp \ + Options.cpp \ + test_malloc.cpp \ + Malloc.h \ + Options.h + +malloc_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Makefile.Shared_Malloc_Multiple.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS += multiple + +multiple_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +multiple_SOURCES = \ + Malloc.cpp \ + Options.cpp \ + test_multiple_mallocs.cpp \ + Malloc.h \ + Options.h + +multiple_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Makefile.Shared_Malloc_Persistence.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS += persistence + +persistence_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +persistence_SOURCES = \ + test_persistence.cpp \ + Malloc.h \ + Options.h \ + test_position_independent_malloc.h + +persistence_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Makefile.Shared_Malloc_Posind.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS += posind + +posind_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +posind_SOURCES = \ + Malloc.cpp \ + Options.cpp \ + test_position_independent_malloc.cpp \ + Malloc.h \ + Options.h \ + test_position_independent_malloc.h + +posind_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Clean up template repositories, etc. +clean-local: + -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.* + -rm -f gcctemp.c gcctemp so_locations *.ics + -rm -rf cxx_repository ptrepository ti_files + -rm -rf templateregistry ir.out + -rm -rf ptrepository SunWS_cache Templates.DB diff --git a/ACE/examples/Shared_Malloc/Malloc.cpp b/ACE/examples/Shared_Malloc/Malloc.cpp new file mode 100644 index 00000000000..4499d9fa11b --- /dev/null +++ b/ACE/examples/Shared_Malloc/Malloc.cpp @@ -0,0 +1,69 @@ +// $Id$ + +#include "Options.h" +#include "Malloc.h" +#include "ace/MMAP_Memory_Pool.h" +#include "ace/Local_Memory_Pool.h" + +#ifndef ACE_LACKS_SYSV_SHMEM +# include "ace/Shared_Memory_Pool.h" +#endif /* !ACE_LACKS_SYSV_SHMEM */ + +#ifndef ACE_LACKS_SBRK +# include "ace/Sbrk_Memory_Pool.h" +#endif /* !ACE_LACKS_SBRK */ + +#include "ace/Process_Mutex.h" +#include "ace/Malloc_T.h" + +ACE_RCSID(Shared_Malloc, Malloc, "$Id$") + +// Strategic typedefs for memory allocation. + +typedef ACE_Malloc <ACE_LOCAL_MEMORY_POOL, ACE_SYNCH_MUTEX> L_ALLOCATOR; +typedef ACE_Malloc <ACE_MMAP_MEMORY_POOL, ACE_Process_Mutex> M_ALLOCATOR; + +#if defined (ACE_LACKS_SYSV_SHMEM) +typedef ACE_Malloc <ACE_MMAP_MEMORY_POOL, ACE_SYNCH_MUTEX> SP_ALLOCATOR; +typedef ACE_Malloc <ACE_MMAP_MEMORY_POOL, ACE_SYNCH_MUTEX> ST_ALLOCATOR; +#else +typedef ACE_Malloc <ACE_SHARED_MEMORY_POOL, ACE_Process_Mutex> SP_ALLOCATOR; +typedef ACE_Malloc <ACE_SHARED_MEMORY_POOL, ACE_SYNCH_MUTEX> ST_ALLOCATOR; +#endif /* ACE_LACKS_SYSV_SHMEM */ + +#if defined (ACE_LACKS_SBRK) +typedef ACE_Malloc <ACE_LOCAL_MEMORY_POOL, ACE_SYNCH_MUTEX> SB_ALLOCATOR; +#else +typedef ACE_Malloc <ACE_SBRK_MEMORY_POOL, ACE_SYNCH_MUTEX> SB_ALLOCATOR; +#endif /* ACE_LACKS_SBRK */ + +// Singleton +ACE_Allocator *Malloc::instance_ = 0; + +// This is a factory that decides what type of allocator to create. + +ACE_Allocator * +Malloc::instance (void) +{ + if (Malloc::instance_ == 0) + { + if (Options::instance ()->child ()) + Malloc::instance_ = new ACE_Allocator_Adapter<M_ALLOCATOR>; + else if (Options::instance ()->spawn_threads ()) + { + if (Options::instance ()->use_sbrk ()) + Malloc::instance_ = new ACE_Allocator_Adapter<SB_ALLOCATOR>; + else if (Options::instance ()->use_shmem ()) + Malloc::instance_ = new ACE_Allocator_Adapter<ST_ALLOCATOR>; + else + Malloc::instance_ = new ACE_Allocator_Adapter<L_ALLOCATOR>; + } + else if (Options::instance ()->use_mmap ()) + Malloc::instance_ = new ACE_Allocator_Adapter<M_ALLOCATOR>; + else // Use Shared_Memory_Pool. + Malloc::instance_ = new ACE_Allocator_Adapter<SP_ALLOCATOR>; + } + + return Malloc::instance_; +} + diff --git a/ACE/examples/Shared_Malloc/Malloc.h b/ACE/examples/Shared_Malloc/Malloc.h new file mode 100644 index 00000000000..c88cead8bfb --- /dev/null +++ b/ACE/examples/Shared_Malloc/Malloc.h @@ -0,0 +1,33 @@ +/* -*- C++ -*- */ +// $Id$ + +#ifndef MY_MALLOC_H +#define MY_MALLOC_H + +#include "ace/config-all.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL +class ACE_Allocator; +ACE_END_VERSIONED_NAMESPACE_DECL + +class Malloc + // = TITLE + // Allocator Singleton. +{ +public: + static ACE_Allocator *instance (void); + // Returns static instance. + +private: + Malloc (void); + // Ensure Singleton. + + static ACE_Allocator *instance_; + // Malloc Singleton. +}; + +#endif /* MY_MALLOC_H */ diff --git a/ACE/examples/Shared_Malloc/Options.cpp b/ACE/examples/Shared_Malloc/Options.cpp new file mode 100644 index 00000000000..6716fa66c31 --- /dev/null +++ b/ACE/examples/Shared_Malloc/Options.cpp @@ -0,0 +1,201 @@ +// $Id$ + +#include "ace/Get_Opt.h" +#include "Options.h" +#include "ace/Log_Msg.h" +#include "ace/OS_NS_stdlib.h" +#include "ace/OS_NS_string.h" + +ACE_RCSID (Shared_Malloc, + Options, + "$Id$") + +// Static Singleton instance. +Options *Options::instance_ = 0; + +Options * +Options::instance (void) +{ + if (Options::instance_ == 0) + Options::instance_ = new Options (); + + return Options::instance_; +} + +const char * +Options::program_name (void) +{ + return this->program_name_; +} + +const char * +Options::slave_name (void) +{ + return this->slave_name_; +} + +int +Options::debug (void) +{ + return this->debug_; +} + +int +Options::exec_slave (void) +{ + return this->exec_slave_; +} + +size_t +Options::iteration_count (void) +{ + return this->iteration_count_; +} + +int +Options::use_sbrk (void) +{ + return this->use_sbrk_; +} + +size_t +Options::max_msg_size (void) +{ + return this->max_msg_size_; +} + +size_t +Options::spawn_count (void) +{ + return this->spawn_count_; +} + +int +Options::spawn_threads (void) +{ + return this->spawn_threads_; +} + +int +Options::use_mmap (void) +{ + return this->use_mmap_; +} + +int +Options::use_shmem (void) +{ + return this->use_shmem_; +} + +int +Options::child (void) +{ + return this->child_; +} + +// Explain usage and exit. + +void +Options::print_usage_and_die (void) +{ + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("usage: %n") + ACE_TEXT ("\n[-d] (run in debugging mode)\n") + ACE_TEXT ("[-e] (use exec(2) in addition to fork(2))\n") + ACE_TEXT ("[-l] (use C++ new operator rather than sbrk(2)\n") + ACE_TEXT ("[-L max_msg_size]\n") + ACE_TEXT ("[-m] (use mmap rather than SysV shared memory)\n") + ACE_TEXT ("[-p] (use processes rather than threads)\n") + ACE_TEXT ("[-s] (use SysV shared memory rather than mmap)\n") + ACE_TEXT ("[-t number of threads or processes to spawn]\n") + ACE_TEXT ("[-T] (enable tracking)\n") + ACE_TEXT ("[-n iteration_count]\n"))); + ACE_OS::exit (1); + /* NOTREACHED */ +} + +Options::Options (void) + : debug_ (0), + exec_slave_ (0), + iteration_count_ (100), + use_sbrk_ (0), + use_shmem_ (0), + max_msg_size_ (127), + spawn_count_ (1), + spawn_threads_ (1), + use_mmap_ (0), + child_ (0) +{ + ACE_OS::strcpy (this->slave_name_, "slave"); +} + +void +Options::parse_args (int argc, ACE_TCHAR *argv[]) +{ + ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("dehlL:mn:pst:T")); + + ACE_OS::strcpy (this->program_name_, ACE_TEXT_ALWAYS_CHAR (argv[0])); + ACE_LOG_MSG->open (argv[0]); + + // Put in a special-case check for child process. + if (ACE_OS::strcmp (this->program_name_, slave_name_) == 0) + { + this->child_ = 1; + this->use_mmap_ = 1; + } + + for (int c; + (c = get_opt ()) != -1; + ) + { + switch (c) + { + case 'd': + this->debug_ = 1; + break; + case 'e': + this->exec_slave_ = 1; + break; + case 'h': + this->print_usage_and_die (); + /* NOTREACHED */ + break; + case 'l': + this->use_sbrk_ = 0; + break; + case 'L': + this->max_msg_size_ = ACE_OS::atoi (get_opt.opt_arg ()); + break; + case 'm': + this->use_mmap_ = 1; + break; + case 'n': + this->iteration_count_ = ACE_OS::atoi (get_opt.opt_arg ()); + break; + case 'p': // Spawn processes rather than threads + this->spawn_threads_ = 0; + break; + case 's': + // Use System V shared memory... + this->use_shmem_ = 1; + break; + case 't': + this->spawn_count_ = ACE_OS::atoi (get_opt.opt_arg ()); + break; + case 'T': +#if defined (ACE_HAS_TRACE) + ACE_Trace::start_tracing (); +#endif /* ACE_HAS_TRACE */ + break; + default: + this->print_usage_and_die (); + /* NOTREACHED */ + break; + } + } + + // Switch to using MMAP when the -p and -e options are enabled. + if (this->exec_slave_ == 1 && this->spawn_threads_ == 0) + this->use_mmap_ = 1; +} diff --git a/ACE/examples/Shared_Malloc/Options.h b/ACE/examples/Shared_Malloc/Options.h new file mode 100644 index 00000000000..67956d80cc3 --- /dev/null +++ b/ACE/examples/Shared_Malloc/Options.h @@ -0,0 +1,86 @@ +/* -*- C++ -*- */ +// $Id$ + +#ifndef _OPTIONS +#define _OPTIONS + +#include "ace/os_include/os_stddef.h" +#include "ace/os_include/os_limits.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +class Options + // = TITLE + // Options Singleton. +{ +public: + static Options *instance (void); + // Return Singleton. + + void parse_args (int argc, ACE_TCHAR *argv[]); + // Parse the arguments. + + // = Accessor methods. + const char *program_name (void); + const char *slave_name (void); + int debug (void); + int exec_slave (void); + size_t iteration_count (void); + int use_sbrk (void); + int use_shmem (void); + size_t max_msg_size (void); + size_t spawn_count (void); + int spawn_threads (void); + int use_mmap (void); + int child (void); + +private: + Options (void); + // Ensure Singleton. + + static Options *instance_; + // Singleton. + + void print_usage_and_die (void); + // Explain usage and exit. + + char program_name_[MAXPATHLEN]; + // Name of the program. + + char slave_name_[MAXPATHLEN]; + // Name of slave process. + + int debug_; + // Flag to indicate if we are debugging. + + int exec_slave_; + // Flag to indicate if we should exec after forking. + + size_t iteration_count_; + // Number of iterations to call malloc_recurse(). + + int use_sbrk_; + // Should we use sbrk(2)? + + int use_shmem_; + // Should we use Shared Memory? + + size_t max_msg_size_; + // Maximum number of bytes to malloc. + + size_t spawn_count_; + // Number of threads. + + int spawn_threads_; + // Spawn threads vs. processes. + + int use_mmap_; + // Use mmap() as the backing store. + + int child_; + // We're a child process. +}; + +#endif /* _OPTIONS */ diff --git a/ACE/examples/Shared_Malloc/Shared_Malloc.mpc b/ACE/examples/Shared_Malloc/Shared_Malloc.mpc new file mode 100644 index 00000000000..42753246815 --- /dev/null +++ b/ACE/examples/Shared_Malloc/Shared_Malloc.mpc @@ -0,0 +1,37 @@ +// -*- MPC -*- +// $Id$ + +project : aceexe { + avoids += ace_for_tao + exename = malloc + Source_Files { + Malloc.cpp + Options.cpp + test_malloc.cpp + } +} +project(*multiple) : aceexe { + avoids += ace_for_tao + exename = multiple + Source_Files { + Malloc.cpp + Options.cpp + test_multiple_mallocs.cpp + } +} +project(*persistence) : aceexe { + avoids += ace_for_tao + exename = persistence + Source_Files { + test_persistence.cpp + } +} +project(*posind) : aceexe { + avoids += ace_for_tao + exename = posind + Source_Files { + Malloc.cpp + Options.cpp + test_position_independent_malloc.cpp + } +} diff --git a/ACE/examples/Shared_Malloc/test_malloc.cpp b/ACE/examples/Shared_Malloc/test_malloc.cpp new file mode 100644 index 00000000000..b6143aa989c --- /dev/null +++ b/ACE/examples/Shared_Malloc/test_malloc.cpp @@ -0,0 +1,228 @@ +// $Id$ + +// This program tests out all the various ACE_Malloc combinations and +// the ACE_Allocator_Adapter. + +#include "ace/Thread.h" +#include "ace/Thread_Manager.h" +#include "ace/Malloc.h" +#include "ace/Signal.h" +#include "ace/OS_NS_stdio.h" +#include "ace/OS_NS_string.h" +#include "ace/OS_NS_sys_wait.h" +#include "ace/OS_NS_unistd.h" +#include "Malloc.h" +#include "Options.h" + +ACE_RCSID(Shared_Malloc, test_malloc, "$Id$") + +static int +gen_size (void) +{ +#if defined (ACE_HAS_THREADS) + ACE_RANDR_TYPE seed = static_cast<ACE_RANDR_TYPE> (reinterpret_cast<unsigned long> (&seed)); + return (ACE_OS::rand_r (seed) % Options::instance ()->max_msg_size ()) + 1; +#else + return (ACE_OS::rand () % Options::instance ()->max_msg_size ()) + 1; +#endif /* ACE_HAS_THREADS */ +} + +// Recursively allocate and deallocate dynamic memory. + +static int +malloc_recurse (int count) +{ + static char default_char = 0; + + if (count <= 0) + { + if (Options::instance ()->debug ()) + { + // Note that you'll need to #define ACE_HAS_MALLOC_STATS in + // the main ACE config.h file and remake ACE to enable this. + ACE_MALLOC_STATS (Malloc::instance ()->print_stats ()); + } + } + else + { + int alloc_size = gen_size (); + void *ptr = Malloc::instance ()->malloc (alloc_size); + + if (ptr == 0) + ACE_ERROR ((LM_ERROR, + "(%P|%t) *** malloc of size %d failed, %p\n%a", + "malloc", + alloc_size)); + else + { + ACE_OS::memset (ptr, default_char++, alloc_size); + + if (Options::instance ()->debug ()) + ACE_DEBUG ((LM_INFO, + "(%P|%t) %u (alloc), size = %d\n", + ptr, + alloc_size)); + + // Call ourselves recursively + malloc_recurse (count - 1); + + if (Options::instance ()->debug ()) + ACE_DEBUG ((LM_INFO, + "(%P|%t) %u (free), size = %d\n", + ptr, + alloc_size)); + Malloc::instance ()->free (ptr); + } + } + + return 0; +} + +#if defined (ACE_HAS_THREADS) +static void * +worker (void *arg) +{ + // Cast the arg to a long, first, because a pointer is the same + // size as a long on all current ACE platforms. + malloc_recurse ((int) (long) arg); + + return 0; +} +#endif /* ACE_HAS_THREADS */ + +// Create the appropriate type of process/thread. + +static void +spawn (void) +{ + if (Options::instance ()->spawn_threads ()) + { +#if defined (ACE_HAS_THREADS) + if (ACE_Thread_Manager::instance ()->spawn (ACE_THR_FUNC (worker), + (void *) Options::instance ()->iteration_count (), + THR_BOUND) == -1) + ACE_ERROR ((LM_ERROR, "%p\n%a", "thread create failed")); +#else + if (Options::instance ()->spawn_count () > 1) + ACE_ERROR ((LM_ERROR, + "only one thread may be run in a process on this platform\n%a", + 1)); +#endif /* ACE_HAS_THREADS */ + } +#if !defined (ACE_WIN32) + else if (ACE_OS::fork (ACE_TEXT_CHAR_TO_TCHAR (Options::instance ()->program_name ())) == 0) + { + if (Options::instance ()->exec_slave ()) + { + char iterations[20]; + char msg_size[20]; + + ACE_OS::sprintf (iterations, "%lu", + (unsigned long) + Options::instance ()->iteration_count ()); + ACE_OS::sprintf (msg_size, "%lu", + (unsigned long) + Options::instance ()->max_msg_size ()); + const char *cp = 0; + + if (Options::instance ()->debug ()) + cp = "-d"; + else + cp = ""; + + const char *argv[] = + { + Options::instance ()->slave_name (), + "-p", + "-n", + iterations, + "-L", + msg_size, + cp, + 0 + }; + + if (ACE_OS::execv (Options::instance ()->program_name (), + (char *const *) argv) == -1) + ACE_ERROR ((LM_ERROR, "%p\n", "exec failed")); + ACE_OS::_exit (1); + } + else + { + ACE_DEBUG ((LM_INFO, + "(%P|%t) about to recurse with iteration count = %d\n", + Options::instance ()->iteration_count ())); + + malloc_recurse (Options::instance ()->iteration_count ()); + Malloc::instance ()->remove (); + ACE_OS::exit (0); + } + } +#endif /* ACE_WIN32 */ +} + +// Wait for all the child processes/threads to exit. + +static void +wait_for_children (void) +{ + if (Options::instance ()->spawn_threads ()) + { +#if defined (ACE_HAS_THREADS) + // Wait for the threads to terminate. + ACE_Thread_Manager::instance ()->wait (); +#else + malloc_recurse (Options::instance ()->iteration_count ()); +#endif /* ACE_HAS_THREADS */ + } +#if !defined (ACE_WIN32) + else + { + pid_t pid; + + while ((pid = ACE_OS::wait (0)) != -1) + ACE_DEBUG ((LM_DEBUG, "(%P|%t) reaped pid = %d\n", pid)); + } +#endif /* ACE_WIN32 */ +} + +extern "C" void +handler (int) +{ + Malloc::instance ()->remove (); + ACE_ERROR ((LM_ERROR, "(%P|%t) removed handler\n%a", 0)); +} + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + // Register a signal handler. + ACE_Sig_Action sa ((ACE_SignalHandler) handler, SIGINT); + ACE_UNUSED_ARG (sa); + + Options::instance ()->parse_args (argc, argv); + +#if !defined (ACE_WIN32) + if (Options::instance ()->child ()) + { + ACE_DEBUG ((LM_INFO, + "(%P|%t) about to recurse with iteration count = %d, debug = %d\n", + Options::instance ()->iteration_count ())); + + // We've been forked... + malloc_recurse (Options::instance ()->iteration_count ()); + Malloc::instance ()->remove (); + } + else +#endif /* ACE_WIN32 */ + { + for (size_t i = 0; + i < Options::instance ()->spawn_count (); + i++) + spawn (); + + wait_for_children (); + Malloc::instance ()->remove (); + } + return 0; +} diff --git a/ACE/examples/Shared_Malloc/test_multiple_mallocs.cpp b/ACE/examples/Shared_Malloc/test_multiple_mallocs.cpp new file mode 100644 index 00000000000..1638a762060 --- /dev/null +++ b/ACE/examples/Shared_Malloc/test_multiple_mallocs.cpp @@ -0,0 +1,125 @@ +// $Id$ + +// Test the capability of <ACE_Malloc> to handle multiple mallocs +// rooted at different base addresses. + +#include "ace/OS_NS_string.h" +#include "ace/Malloc_T.h" +#include "ace/MMAP_Memory_Pool.h" +#include "ace/Auto_Ptr.h" +#include "ace/Process_Mutex.h" + +ACE_RCSID(Shared_Malloc, test_multiple_mallocs, "$Id$") + +typedef ACE_Malloc <ACE_MMAP_MEMORY_POOL, ACE_Process_Mutex> TEST_MALLOC; + +#if (ACE_HAS_POSITION_INDEPENDENT_POINTERS == 1) +// The Address for the shared memory mapped files defaults to wherever +// the OS wants to map it. +const void *REQUEST_BASE_ADDR = 0; +const void *RESPONSE_BASE_ADDR = 0; +#else +// Default address for shared memory mapped files and SYSV shared +// memory (defaults to 64 M). +const void *REQUEST_BASE_ADDR = ((void *) (64 * 1024 * 1024)); + +// Default address for shared memory mapped files and SYSV shared +// memory (defaults to 64 M). +const void *RESPONSE_BASE_ADDR = ((void *) (128 * 1024 * 1024)); +#endif /* ACE_HAS_POSITION_INDEPENDENT_POINTERS == 1 */ + +static const char *request_string = "hello from request repository"; +static const char *response_string = "hello from response repository"; + +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_MMAP_Memory_Pool_Options request_options (REQUEST_BASE_ADDR); + + // Create an adapter version of an allocator. + ACE_Allocator_Adapter<TEST_MALLOC> *adapter_ptr = 0; + ACE_NEW_RETURN (adapter_ptr, + ACE_Allocator_Adapter<TEST_MALLOC> ("request_file", + "request_lock", + &request_options), + 1); + + auto_ptr <ACE_Allocator_Adapter<TEST_MALLOC> > shmem_request (adapter_ptr); + ACE_MMAP_Memory_Pool_Options response_options (RESPONSE_BASE_ADDR); + + TEST_MALLOC *ptr = 0; + // Create a non-adapter version of an allocator. + ACE_NEW_RETURN (ptr, + TEST_MALLOC (ACE_TEXT("response_file"), + ACE_TEXT("response_lock"), + &response_options), + 1); + auto_ptr <TEST_MALLOC> shmem_response (ptr); + void *data = 0; + + // If we find "foo" then we're running the "second" time, so we must + // release the resources. + if (shmem_request->find ("foo", + data) == 0) + { + ACE_DEBUG ((LM_DEBUG, + "%s\n", + data)); + shmem_request->remove (); + } + + // This is the first time in, so we allocate the memory and bind it + // to the name "foo". + else + { + ACE_ALLOCATOR_RETURN (data, + shmem_request->malloc (ACE_OS::strlen (request_string) + 1), + 1); + ACE_OS::strcpy ((char *) data, + request_string); + + if (shmem_request->bind ("foo", + data) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "bind"), + 1); + } + data = 0; + + // If we find "foo" then we're running the "second" time, so we must + // release the resources. + if (shmem_response->find ("foo", + data) == 0) + { + ACE_DEBUG ((LM_DEBUG, + "%s\n", + data)); + shmem_response->remove (); + ACE_DEBUG ((LM_DEBUG, + "all shared memory resources have been released\n")); + } + + // This is the first time in, so we allocate the memory and bind it + // to the name "foo". + else + { + ACE_ALLOCATOR_RETURN (data, + shmem_response->malloc (ACE_OS::strlen (response_string) + 1), + 1); + ACE_OS::strcpy ((char *) data, + response_string); + + if (shmem_response->bind ("foo", + data) == -1) + ACE_ERROR ((LM_ERROR, + "%p\n", + "bind")); + else + ACE_DEBUG ((LM_DEBUG, + "Run again to see results and release resources.\n")); + } + + return 0; +} + diff --git a/ACE/examples/Shared_Malloc/test_persistence.cpp b/ACE/examples/Shared_Malloc/test_persistence.cpp new file mode 100644 index 00000000000..8c3df750853 --- /dev/null +++ b/ACE/examples/Shared_Malloc/test_persistence.cpp @@ -0,0 +1,350 @@ +// $Id$ + +// Test the persistence capabilities of <ACE_Malloc> when configured +// for mmap-based shared memory management. + +// This examples uses scanf to read user inputs from stdin into fixed +// sized buffers. This may cause buffers to overrun. + +#include "ace/OS_NS_string.h" +#include "ace/Malloc_T.h" +#include "ace/MMAP_Memory_Pool.h" + +// FUZZ: disable check_for_streams_include +#include "ace/streams.h" + +#include "ace/Null_Mutex.h" + +ACE_RCSID (Shared_Malloc, + test_persistence, + "$Id$") + +typedef ACE_Malloc <ACE_MMAP_MEMORY_POOL, ACE_Null_Mutex> TEST_MALLOC; +typedef ACE_Malloc_LIFO_Iterator <ACE_MMAP_MEMORY_POOL, ACE_Null_Mutex> MALLOC_LIFO_ITERATOR; +typedef ACE_Malloc_FIFO_Iterator <ACE_MMAP_MEMORY_POOL, ACE_Null_Mutex> MALLOC_FIFO_ITERATOR; + +// Shared memory manager. +static TEST_MALLOC *shmem_allocator = 0; + +// Backing store name. +static ACE_TCHAR backing_store[MAXPATHLEN + 1] = ACE_TEXT (""); + +class Employee +{ +public: + Employee (void): name_ (0), id_ (0) {} + + Employee (const char *name, u_long id) : id_ (id) + { + size_t len = ACE_OS::strlen (name) + 1; + this->name_ = reinterpret_cast<char *> (shmem_allocator->malloc (len)); + ACE_OS::strcpy (this->name_, name); + } + + ~Employee (void) { shmem_allocator->free (this->name_); } + + const char *name (void) const { return this->name_; } + + void name (const char *name) + { + if (this->name_) + shmem_allocator->free (this->name_); + + size_t len = ACE_OS::strlen (name) + 1; + this->name_ = reinterpret_cast<char *> (shmem_allocator->malloc (len)); + ACE_OS::strcpy (this->name_, name); + } + + u_long id (void) const { return id_; } + + void id (u_long id) { id_ = id; } + + void *operator new (size_t) + { + return shmem_allocator->malloc (sizeof (Employee)); + } + +#if defined (ACE_HAS_NEW_NOTHROW) + void *operator new (size_t, const ACE_nothrow_t&) + { + return shmem_allocator->malloc (sizeof (Employee)); + } +#if !defined (ACE_LACKS_PLACEMENT_OPERATOR_DELETE) + void operator delete (void *p, const ACE_nothrow_t&) throw () + { + shmem_allocator->free (p); + } +#endif /* ACE_LACKS_PLACEMENT_OPERATOR_DELETE */ +#endif + + void operator delete (void *pointer) + { + shmem_allocator->free (pointer); + } + +private: + char *name_; + // Employee name. + + u_long id_; + // Employee ID. +}; + +class GUI_Handler +{ +public: + GUI_Handler (void) { menu (); } + + ~GUI_Handler (void) + { + TEST_MALLOC::MEMORY_POOL &pool = + shmem_allocator->memory_pool (); + pool.sync (); + } + + int service(void) + { + char option[BUFSIZ]; + char buf1[BUFSIZ]; + char buf2[BUFSIZ]; + + if (::scanf ("%s", option) <= 0) + { + ACE_ERROR ((LM_ERROR, + "try again\n")); + return 0; + } + + int result = 0; + switch (option[0]) + { + case 'I' : + case 'i' : + if (::scanf ("%s %s", buf1, buf2) <= 0) + break; + result = insert_employee (buf1, + ACE_OS::atoi (buf2)); + break; + case 'F' : + case 'f' : + if (::scanf ("%s", buf1) <= 0) + break; + result = find_employee (buf1); + break; + case 'D' : + case 'd' : + if (::scanf ("%s", buf1) <= 0) + break; + result = delete_employee (buf1); + break; + case 'L' : + case 'l' : + result = list_employees (); + break; + case 'Q' : + case 'q' : + return -1; + ACE_NOTREACHED(break); + default : + cout << "unrecognized command" << endl; + } + if (result == 0) + cout << "Last operation was successful!!" << endl; + else + cout << "Last operation failed!! " << endl; + + menu (); + + return 0; + } + + void menu(void) + { + cout << endl; + cout << "\t************************** " << endl; + cout << "\tThe employee database menu " << endl; + cout << endl; + cout << "\t<I> Insert <name> <id> " << endl; + cout << "\t<D> Delete <name> " << endl; + cout << "\t<F> Find <name> " << endl; + cout << endl; + cout << "\t<L> List all employees " << endl; + cout << endl; + cout << "\t<Q> Quit " << endl; + cout << "\t************************** " << endl; + } + +private: + int insert_employee (const char *name, + u_long id); + int find_employee (const char *name); + int list_employees (void); + int delete_employee (const char *name); +}; + +int +GUI_Handler::insert_employee (const char *name, + u_long id) +{ + if (find_employee (name) == 0) + ACE_ERROR_RETURN ((LM_ERROR, + "Employee already exists\n"), + -1); + + Employee *new_employee = 0; + + ACE_NEW_RETURN (new_employee, + Employee (name, id), + -1); + + if (shmem_allocator->bind (name, + new_employee) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "bind failed\n"), + -1); + return 0; +} + +int +GUI_Handler::find_employee (const char *name) +{ + void *temp = 0; + + if (shmem_allocator->find (name, + temp) == 0) + { + Employee *employee = reinterpret_cast<Employee *> (temp); + + ACE_DEBUG ((LM_DEBUG, + "The following employee was found.......\n\n")); + ACE_DEBUG ((LM_DEBUG, + "Employee name: %s\nEmployee id: %d\n", + employee->name (), + employee->id ())); + return 0; + } + + return -1; +} + +int +GUI_Handler::list_employees (void) +{ + ACE_DEBUG ((LM_DEBUG, + "The following employees were found.......\n\n")); + + { + ACE_DEBUG ((LM_DEBUG, + "LIFO order:\n")); + MALLOC_LIFO_ITERATOR iterator (*shmem_allocator); + + for (void *temp = 0; + iterator.next (temp) != 0; + iterator.advance ()) + { + Employee *employee = reinterpret_cast<Employee *> (temp); + ACE_DEBUG ((LM_DEBUG, + "Employee name: %s\nEmployee id: %d\n", + employee->name (), + employee->id ())); + } + } + + { + ACE_DEBUG ((LM_DEBUG, + "FIFO order:\n")); + MALLOC_FIFO_ITERATOR iterator (*shmem_allocator); + + for (void *temp = 0; + iterator.next (temp) != 0; + iterator.advance ()) + { + Employee *employee = reinterpret_cast<Employee *> (temp); + ACE_DEBUG ((LM_DEBUG, + "Employee name: %s\nEmployee id: %d\n", + employee->name (), + employee->id ())); + } + } + return 0; +} + +int +GUI_Handler::delete_employee (const char *name) +{ + void *temp = 0; + + if (shmem_allocator->unbind (name, + temp) == 0) + { + Employee *employee = reinterpret_cast<Employee *> (temp); + + ACE_DEBUG ((LM_DEBUG, + "The following employee was found and deleted.......\n\n")); + + ACE_DEBUG ((LM_DEBUG, + "Employee name: %s\nEmployee id: %d\n", + employee->name (), + employee->id ())); + + delete employee; + return 0; + } + + ACE_DEBUG ((LM_DEBUG, + "There is no employee with name %s", + name)); + return -1; +} + +void +parse_args (int argc, ACE_TCHAR *argv[]) +{ + if (argc > 1) + ACE_OS::strcpy (backing_store, argv[1]); +} + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + parse_args (argc, argv); + + if (ACE_OS::strcmp (backing_store, ACE_TEXT ("")) == 0) + { +#if defined (ACE_DEFAULT_BACKING_STORE) + // Create a temporary file. + ACE_OS::strcpy (backing_store, + ACE_DEFAULT_BACKING_STORE); +#else /* ACE_DEFAULT_BACKING_STORE */ + if (ACE::get_temp_dir (backing_store, + MAXPATHLEN - 17) == -1) // -17 for ace-malloc-XXXXXX + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("Temporary path too long, ") + ACE_TEXT ("defaulting to current directory\n"))); + backing_store[0] = 0; + } + + // Add the filename to the end + ACE_OS::strcat (backing_store, ACE_TEXT ("ace-malloc-XXXXXX")); + +#endif /* ACE_DEFAULT_BACKING_STORE */ + } + + ACE_NEW_RETURN (shmem_allocator, + TEST_MALLOC (backing_store), + -1); + + GUI_Handler handler; + + for (;;) + if (handler.service () == -1) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("closing down ....\n"))); + break; + } + + return 0; +} + diff --git a/ACE/examples/Shared_Malloc/test_position_independent_malloc.cpp b/ACE/examples/Shared_Malloc/test_position_independent_malloc.cpp new file mode 100644 index 00000000000..b4c66e54957 --- /dev/null +++ b/ACE/examples/Shared_Malloc/test_position_independent_malloc.cpp @@ -0,0 +1,190 @@ +// $Id$ + +// Test the capability of the "position-independent" <ACE_Malloc> to +// handle a single malloc that can be rooted at different base +// addresses each time it's used. The actual backing store used by +// <ACE_Malloc> is located in a memory-mapped file. + +#include "test_position_independent_malloc.h" +#include "ace/PI_Malloc.h" +#include "ace/Based_Pointer_T.h" +#include "ace/Get_Opt.h" +#include "ace/Auto_Ptr.h" +#include "ace/Process_Mutex.h" +#include "ace/Malloc_T.h" +#include "ace/MMAP_Memory_Pool.h" + +ACE_RCSID(Shared_Malloc, test_multiple_mallocs, "$Id$") + +#if (ACE_HAS_POSITION_INDEPENDENT_POINTERS == 1) +typedef ACE_PI_Control_Block CONTROL_BLOCK; +#else +typedef ACE_Control_Block CONTROL_BLOCK; +#endif /* ACE_HAS_POSITION_INDEPENDENT_POINTERS == 1 */ + +typedef ACE_Malloc_T <ACE_MMAP_MEMORY_POOL, ACE_Process_Mutex, CONTROL_BLOCK> TEST_MALLOC; + +// Default address for memory-mapped files. +static void *base_addr = ACE_DEFAULT_BASE_ADDR; + +static void +print (Test_Data *data) +{ + for (Test_Data *t = data; t != 0; t = t->next_) + { + ACE_DEBUG ((LM_DEBUG, + "<<<<\ni1_ = %d, i2_ = %d, i3_ = %d\n", + t->i1_, + t->i2_, + t->i3_)); + ACE_DEBUG ((LM_DEBUG, + "*t->bpl_ = %d, t->long_test_->array_[0] = %d\n>>>>\n", + *t->long_test_->bpl_, + t->long_test_->array_[0])); + } +} + +static void * +initialize (TEST_MALLOC *allocator) +{ + void *ptr; + ACE_ALLOCATOR_RETURN (ptr, + allocator->malloc (sizeof (Test_Data)), + 0); + Test_Data *data1 = new (ptr) Test_Data; + + data1->i1_ = 111; + data1->i2_ = 222; + data1->i3_ = 333; + + void *gap = 0; + ACE_ALLOCATOR_RETURN (gap, + allocator->malloc (sizeof (256)), + 0); + + allocator->free (gap); + + ACE_ALLOCATOR_RETURN (ptr, + allocator->malloc (sizeof (Test_Data)), + 0); + Test_Data *data2 = new (ptr) Test_Data; + + data1->next_ = 0; + data1->i1_ = 111; + data1->i2_ = 222; + data1->i3_ = 333; + data2->next_ = data1; + data2->i1_ = -111; + data2->i2_ = -222; + data2->i3_ = -333; + + // Test in shared memory using long (array/pointer) + ACE_ALLOCATOR_RETURN (ptr, + allocator->malloc (sizeof (Long_Test)), + 0); + Long_Test *lt = new (ptr) Long_Test; + + lt->array_[0] = 1000; + lt->array_[1] = 1001; + lt->array_[2] = 1002; + lt->array_[3] = 1003; + lt->array_[4] = 1004; + lt->bpl_ = lt->array_; + + data1->long_test_= lt; + + ACE_ASSERT (*lt->bpl_ == 1000); + ACE_ASSERT (lt->bpl_[3] == 1003); + + ACE_ALLOCATOR_RETURN (ptr, + allocator->malloc (sizeof (Long_Test)), + 0); + lt = new (ptr) Long_Test; + + lt->array_[0] = 2000; + lt->array_[1] = 2001; + lt->array_[2] = 2002; + lt->array_[3] = 2003; + lt->array_[4] = 2004; + lt->bpl_ = lt->array_; + + data2->long_test_= lt; + + ACE_ASSERT (*lt->bpl_ == 2000); + ACE_ASSERT (lt->bpl_[4] == 2004); + + return data2; +} + +static void +parse_args (int argc, ACE_TCHAR *argv[]) +{ + ACE_Get_Opt get_opt (argc, argv, ACE_TEXT("a:T")); + + for (int c; + (c = get_opt ()) != -1; + ) + { + switch (c) + { + case 'a': + // Override the default base address. + base_addr = reinterpret_cast<void *> (ACE_OS::atoi (get_opt.opt_arg ())); + break; + case 'T': +#if defined (ACE_HAS_TRACE) + ACE_Trace::start_tracing (); +#endif /* ACE_HAS_TRACE */ + break; + } + } +} + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + parse_args (argc, argv); + + ACE_MMAP_Memory_Pool_Options options (base_addr); + + // Create an allocator. + TEST_MALLOC *ptr = 0; + ACE_NEW_RETURN (ptr, + TEST_MALLOC (ACE_TEXT("test_file"), + ACE_TEXT("test_lock"), + &options), + 1); + auto_ptr <TEST_MALLOC> allocator (ptr); + void *data = 0; + + // This is the first time in, so we allocate the memory and bind it + // to the name "foo". + if (allocator->find ("foo", + data) == -1) + { + data = initialize (allocator.get ()); + + if (allocator->bind ("foo", + data) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "bind"), + 1); + + ACE_DEBUG ((LM_DEBUG, + "Run again to see results and release resources.\n")); + } + // If we find "foo" then we're running the "second" time, so we must + // release the resources. + else + { + print ((Test_Data *) data); + allocator->free (data); + allocator->remove (); + ACE_DEBUG ((LM_DEBUG, + "all resources released\n")); + } + + return 0; +} + diff --git a/ACE/examples/Shared_Malloc/test_position_independent_malloc.h b/ACE/examples/Shared_Malloc/test_position_independent_malloc.h new file mode 100644 index 00000000000..2785a386045 --- /dev/null +++ b/ACE/examples/Shared_Malloc/test_position_independent_malloc.h @@ -0,0 +1,28 @@ +// $Id$ +// +// Define struct used in test_position_independent_malloc.cpp - needs +// to be in a separate file for template generation on AIX IBM C++. + +#ifndef __TEST_POSITION_INDEPENDENT_MALLOC_H +#define __TEST_POSITION_INDEPENDENT_MALLOC_H + +#include "ace/Based_Pointer_T.h" + +// Some test data. +struct Long_Test +{ + ACE_Based_Pointer_Basic<long> bpl_; + long array_[10]; +}; + +// Some more test data. +struct Test_Data +{ + int i1_; + int i2_; + int i3_; + ACE_Based_Pointer<Test_Data> next_; + ACE_Based_Pointer<Long_Test> long_test_; +}; + +#endif /* __TEST_POSITION_INDEPENDENT_MALLOC */ diff --git a/ACE/examples/Shared_Memory/.cvsignore b/ACE/examples/Shared_Memory/.cvsignore new file mode 100644 index 00000000000..7f6e8a792c5 --- /dev/null +++ b/ACE/examples/Shared_Memory/.cvsignore @@ -0,0 +1,2 @@ +testmm +testsv diff --git a/ACE/examples/Shared_Memory/Makefile.am b/ACE/examples/Shared_Memory/Makefile.am new file mode 100644 index 00000000000..864c7a5b071 --- /dev/null +++ b/ACE/examples/Shared_Memory/Makefile.am @@ -0,0 +1,56 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +ACE_BUILDDIR = $(top_builddir) +ACE_ROOT = $(top_srcdir) + +noinst_PROGRAMS = + +## Makefile.Shared_Memory_MM.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS += testmm + +testmm_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +testmm_SOURCES = \ + test_MM.cpp + +testmm_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Makefile.Shared_Memory_SV.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS += testsv + +testsv_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +testsv_SOURCES = \ + test_SV.cpp + +testsv_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Clean up template repositories, etc. +clean-local: + -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.* + -rm -f gcctemp.c gcctemp so_locations *.ics + -rm -rf cxx_repository ptrepository ti_files + -rm -rf templateregistry ir.out + -rm -rf ptrepository SunWS_cache Templates.DB diff --git a/ACE/examples/Shared_Memory/Shared_Memory.mpc b/ACE/examples/Shared_Memory/Shared_Memory.mpc new file mode 100644 index 00000000000..f0ee256597b --- /dev/null +++ b/ACE/examples/Shared_Memory/Shared_Memory.mpc @@ -0,0 +1,17 @@ +// -*- MPC -*- +// $Id$ + +project(*MM) : aceexe { + avoids += ace_for_tao + exename = testmm + Source_Files { + test_MM.cpp + } +} +project(*SV) : aceexe { + avoids += ace_for_tao + exename = testsv + Source_Files { + test_SV.cpp + } +} diff --git a/ACE/examples/Shared_Memory/test_MM.cpp b/ACE/examples/Shared_Memory/test_MM.cpp new file mode 100644 index 00000000000..2d98224f910 --- /dev/null +++ b/ACE/examples/Shared_Memory/test_MM.cpp @@ -0,0 +1,74 @@ +// $Id$ + +#include "ace/Shared_Memory_MM.h" +#include "ace/Log_Msg.h" +#include "ace/OS_NS_errno.h" +#include "ace/OS_NS_unistd.h" +#include "ace/OS_NS_stdlib.h" + +ACE_RCSID(Shared_Memory, test_MM, "$Id$") + +#define SHMSZ 27 +ACE_TCHAR shm_key[] = ACE_TEXT ("/tmp/fooXXXXXX"); + +static void +client (void) +{ + ACE_Shared_Memory *shm_client = new ACE_Shared_Memory_MM (shm_key); + char *shm = (char *) shm_client->malloc (); + + for (char *s = shm; *s != '\0'; s++) + putchar (*s); + + putchar ('\n'); + *shm = '*'; +} + +static void +server (void) +{ + ACE_Shared_Memory *shm_server = new ACE_Shared_Memory_MM (shm_key, SHMSZ); + char *shm = (char *) shm_server->malloc (); + char *s = shm; + + for (char c = 'a'; c <= 'z'; c++) + *s++ = c; + + *s = '\0'; + + // Perform a busy wait (ugh) + while (*shm != '*') + ACE_OS::sleep (1); + + if (shm_server->remove () < 0) + ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("remove"))); + ACE_OS::unlink (shm_key); +} + +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + if ( +#if defined (ACE_LACKS_MKSTEMP) + ACE_OS::mktemp (shm_key) == 0 +#else + ACE_OS::mkstemp (shm_key) == 0 +#endif + || (ACE_OS::unlink (shm_key) == -1 && errno == EPERM)) + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), shm_key), 1); + + switch (ACE_OS::fork ()) + { + case -1: + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("fork")), 1); + case 0: + // Make sure the server starts up first. + ACE_OS::sleep (1); + client (); + break; + default: + server (); + break; + } + return 0; +} diff --git a/ACE/examples/Shared_Memory/test_SV.cpp b/ACE/examples/Shared_Memory/test_SV.cpp new file mode 100644 index 00000000000..26ab56a7115 --- /dev/null +++ b/ACE/examples/Shared_Memory/test_SV.cpp @@ -0,0 +1,64 @@ +// $Id$ + +#include "ace/Shared_Memory_SV.h" +#include "ace/Log_Msg.h" +#include "ace/OS_NS_unistd.h" + +ACE_RCSID(Shared_Memory, test_SV, "$Id$") + +#define SHMSZ 27 +#define SHM_KEY (key_t) 5678 + +static void +client (void) +{ + ACE_Shared_Memory_SV shm_client (SHM_KEY, SHMSZ); + char *shm = (char *) shm_client.malloc (); + + for (char *s = shm; *s != '\0'; s++) + putchar (*s); + + putchar ('\n'); + *shm = '*'; +} + +static void +server (void) +{ + ACE_Shared_Memory_SV shm_server (SHM_KEY, SHMSZ, + ACE_Shared_Memory_SV::ACE_CREATE); + char *shm = (char *) shm_server.malloc (); + char *s = shm; + + for (char c = 'a'; c <= 'z'; c++) + *s++ = c; + + *s = '\0'; + + while (*shm != '*') + ACE_OS::sleep (1); + + if (shm_server.remove () < 0) + ACE_ERROR ((LM_ERROR, "%p\n", "remove")); +} + +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + switch (ACE_OS::fork ()) + { + case -1: + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "fork"), 1); + case 0: + // Make sure the server starts up first. + ACE_OS::sleep (1); + client (); + break; + default: + server (); + break; + } + + return 0; +} + diff --git a/ACE/examples/Smart_Pointers/.cvsignore b/ACE/examples/Smart_Pointers/.cvsignore new file mode 100644 index 00000000000..f309b7d5f8b --- /dev/null +++ b/ACE/examples/Smart_Pointers/.cvsignore @@ -0,0 +1,2 @@ +Widget +gadget diff --git a/ACE/examples/Smart_Pointers/Gadget.cpp b/ACE/examples/Smart_Pointers/Gadget.cpp new file mode 100644 index 00000000000..180fe0107cc --- /dev/null +++ b/ACE/examples/Smart_Pointers/Gadget.cpp @@ -0,0 +1,16 @@ +/* -*- C++ -*- */ +//============================================================================= +/** + * @file Gadget.cpp + * + * $Id$ + * + * @author Christopher Kohlhoff <chris@kohlhoff.com> + */ +//============================================================================= + +#include "Gadget.h" + +Gadget::~Gadget (void) +{ +} diff --git a/ACE/examples/Smart_Pointers/Gadget.h b/ACE/examples/Smart_Pointers/Gadget.h new file mode 100644 index 00000000000..65b1fb0a34e --- /dev/null +++ b/ACE/examples/Smart_Pointers/Gadget.h @@ -0,0 +1,51 @@ +/* -*- C++ -*- */ +//============================================================================= +/** + * @file Gadget.h + * + * $Id$ + * + * @author Christopher Kohlhoff <chris@kohlhoff.com> + */ +//============================================================================= + +#ifndef GADGET_H +#define GADGET_H + +#include "ace/Bound_Ptr.h" +#include "Gadget_Part.h" + +/** + * @class Gadget + * + * @brief An interface for some high-level application object. + */ +class Gadget +{ +public: + /// Destructor. + virtual ~Gadget (void); + + /// Add a new part to the gadget. The gadget automatically takes shared + /// responsibility for the ownership of the part object since we are passing + /// a Gadget_Part_var. + virtual void add_part (Gadget_Part_var part) = 0; + + /// Remove a random part from the gadget. Responsibility for ownership of the + /// part is automatically returned to the caller since we are returning a + /// Gadget_Part_var. + virtual Gadget_Part_var remove_part (void) = 0; + + /// Ask the gadget to print information about the parts that it contains. + virtual void list_parts (void) = 0; +}; + +// The Gadget_var smart pointer has shared (reference counted) ownership +// semantics. +typedef ACE_Strong_Bound_Ptr<Gadget, ACE_SYNCH_MUTEX> Gadget_var; + +// The Gadget_ptr smart pointer has no ownership semantics, but supports +// conversion back into a Gadget_var. +typedef ACE_Weak_Bound_Ptr<Gadget, ACE_SYNCH_MUTEX> Gadget_ptr; + +#endif /* GADGET_H */ diff --git a/ACE/examples/Smart_Pointers/Gadget_Factory.cpp b/ACE/examples/Smart_Pointers/Gadget_Factory.cpp new file mode 100644 index 00000000000..054237169f2 --- /dev/null +++ b/ACE/examples/Smart_Pointers/Gadget_Factory.cpp @@ -0,0 +1,18 @@ +/* -*- C++ -*- */ +//============================================================================= +/** + * @file Gadget_Factory.cpp + * + * $Id$ + * + * @author Christopher Kohlhoff <chris@kohlhoff.com> + */ +//============================================================================= + +#include "Gadget_Factory.h" +#include "Gadget_Impl.h" + +Gadget_var Gadget_Factory::create_gadget (void) +{ + return Gadget_var (new Gadget_Impl); +} diff --git a/ACE/examples/Smart_Pointers/Gadget_Factory.h b/ACE/examples/Smart_Pointers/Gadget_Factory.h new file mode 100644 index 00000000000..dd3c17e7975 --- /dev/null +++ b/ACE/examples/Smart_Pointers/Gadget_Factory.h @@ -0,0 +1,32 @@ +/* -*- C++ -*- */ +//============================================================================= +/** + * @file Gadget_Factory.h + * + * $Id$ + * + * @author Christopher Kohlhoff <chris@kohlhoff.com> + */ +//============================================================================= + +#ifndef GADGET_FACTORY_H +#define GADGET_FACTORY_H + +#include "Gadget.h" + +/** + * @class Gadget_Factory + * + * @brief Used to create Gadget instances. + */ +class Gadget_Factory +{ +public: + /// Create an instance of a gadget. Ownership of the object is automatically + /// transferred to the caller since we return a Gadget_var. This also means + /// that the object will be deleted automatically if the caller "forgets" to + /// collect the return value. + static Gadget_var create_gadget (void); +}; + +#endif /* GADGET_FACTORY_H */ diff --git a/ACE/examples/Smart_Pointers/Gadget_Impl.cpp b/ACE/examples/Smart_Pointers/Gadget_Impl.cpp new file mode 100644 index 00000000000..03dd94f8838 --- /dev/null +++ b/ACE/examples/Smart_Pointers/Gadget_Impl.cpp @@ -0,0 +1,47 @@ +/* -*- C++ -*- */ +//============================================================================= +/** + * @file Gadget_Impl.cpp + * + * $Id$ + * + * @author Christopher Kohlhoff <chris@kohlhoff.com> + */ +//============================================================================= + +#include "Gadget_Impl.h" +#include "ace/Log_Msg.h" + +Gadget_Impl::Gadget_Impl (void) +{ + ACE_DEBUG ((LM_DEBUG, "Gadget_Impl constructor\n")); +} + +Gadget_Impl::~Gadget_Impl (void) +{ + ACE_DEBUG ((LM_DEBUG, "Gadget_Impl destructor\n")); +} + +void Gadget_Impl::add_part (Gadget_Part_var part) +{ + parts_.enqueue_tail (part); +} + +Gadget_Part_var Gadget_Impl::remove_part (void) +{ + Gadget_Part_var removed_part; + if (parts_.dequeue_head (removed_part) == -1) + return Gadget_Part_var(); + return removed_part; +} + +void Gadget_Impl::list_parts (void) +{ + ACE_Unbounded_Queue_Iterator<Gadget_Part_var> iter (parts_); + Gadget_Part_var *current_part; + while (iter.next (current_part)) + { + (*current_part)->print_info (); + iter.advance (); + } +} diff --git a/ACE/examples/Smart_Pointers/Gadget_Impl.h b/ACE/examples/Smart_Pointers/Gadget_Impl.h new file mode 100644 index 00000000000..ed4faf27ca4 --- /dev/null +++ b/ACE/examples/Smart_Pointers/Gadget_Impl.h @@ -0,0 +1,51 @@ +/* -*- C++ -*- */ +//============================================================================= +/** + * @file Gadget_Impl.h + * + * $Id$ + * + * @author Christopher Kohlhoff <chris@kohlhoff.com> + */ +//============================================================================= + +#ifndef GADGET_IMPL_H +#define GADGET_IMPL_H + +#include "ace/Unbounded_Queue.h" +#include "Gadget.h" +#include "Gadget_Part.h" + +/** + * @class Gadget_Impl + * + * @brief An implementation of the Gadget interface. + */ +class Gadget_Impl : public Gadget +{ +public: + /// Constructor. + Gadget_Impl (void); + + /// Destructor. + virtual ~Gadget_Impl (void); + + /// Add a new part to the gadget. The gadget takes ownership of the part + /// object. + virtual void add_part (Gadget_Part_var part); + + /// Remove a random part from the gadget. Ownership of the part is returned + /// to the caller. + virtual Gadget_Part_var remove_part (void); + + /// Ask the gadget to print information about the parts that it contains. + virtual void list_parts (void); + +private: + /// The parts which make up this gadget. The set actually contains instances + /// of Gadget_Part_var to automatically manage the lifetimes of the + /// constituent parts. + ACE_Unbounded_Queue<Gadget_Part_var> parts_; +}; + +#endif /* GADGET_IMPL_H */ diff --git a/ACE/examples/Smart_Pointers/Gadget_Part.cpp b/ACE/examples/Smart_Pointers/Gadget_Part.cpp new file mode 100644 index 00000000000..9f08f2a61e7 --- /dev/null +++ b/ACE/examples/Smart_Pointers/Gadget_Part.cpp @@ -0,0 +1,16 @@ +/* -*- C++ -*- */ +//============================================================================= +/** + * @file Gadget_Part.cpp + * + * $Id$ + * + * @author Christopher Kohlhoff <chris@kohlhoff.com> + */ +//============================================================================= + +#include "Gadget_Part.h" + +Gadget_Part::~Gadget_Part (void) +{ +} diff --git a/ACE/examples/Smart_Pointers/Gadget_Part.h b/ACE/examples/Smart_Pointers/Gadget_Part.h new file mode 100644 index 00000000000..cef4277168a --- /dev/null +++ b/ACE/examples/Smart_Pointers/Gadget_Part.h @@ -0,0 +1,45 @@ +/* -*- C++ -*- */ +//============================================================================= +/** + * @file Gadget_Part.h + * + * $Id$ + * + * @author Christopher Kohlhoff <chris@kohlhoff.com> + */ +//============================================================================= + +#ifndef GADGET_PART_H +#define GADGET_PART_H + +#include "ace/Bound_Ptr.h" +#include "ace/Synch_Traits.h" +#include "ace/Thread_Mutex.h" + +/** + * @class Gadget_Part + * + * @brief An interface for some high-level application object. + */ +class Gadget_Part +{ +public: + /// Destructor. + virtual ~Gadget_Part (void); + + /// Ask the part to print information about itself. + virtual void print_info (void) = 0; + + /// Ask the part to remove itself from the gadget that contains it. + virtual void remove_from_owner (void) = 0; +}; + +// The Gadget_Part_var smart pointer has shared (reference counted) ownership +// semantics. +typedef ACE_Strong_Bound_Ptr<Gadget_Part, ACE_SYNCH_MUTEX> Gadget_Part_var; + +// The Gadget_Part_ptr smart pointer has no ownership semantics, but supports +// conversion back into a Gadget_var. +typedef ACE_Weak_Bound_Ptr<Gadget_Part, ACE_SYNCH_MUTEX> Gadget_Part_ptr; + +#endif /* GADGET_PART_H */ diff --git a/ACE/examples/Smart_Pointers/Gadget_Part_Factory.cpp b/ACE/examples/Smart_Pointers/Gadget_Part_Factory.cpp new file mode 100644 index 00000000000..caf546fffce --- /dev/null +++ b/ACE/examples/Smart_Pointers/Gadget_Part_Factory.cpp @@ -0,0 +1,20 @@ +/* -*- C++ -*- */ +//============================================================================= +/** + * @file Gadget_Part_Factory.cpp + * + * $Id$ + * + * @author Christopher Kohlhoff <chris@kohlhoff.com> + */ +//============================================================================= + +#include "Gadget_Part_Factory.h" +#include "Gadget_Part_Impl.h" + +Gadget_Part_var Gadget_Part_Factory::create_gadget_part (Gadget_ptr owner, + const char* name, + int size) +{ + return Gadget_Part_var (new Gadget_Part_Impl (owner, name, size)); +} diff --git a/ACE/examples/Smart_Pointers/Gadget_Part_Factory.h b/ACE/examples/Smart_Pointers/Gadget_Part_Factory.h new file mode 100644 index 00000000000..a7bc5cb38bd --- /dev/null +++ b/ACE/examples/Smart_Pointers/Gadget_Part_Factory.h @@ -0,0 +1,35 @@ +/* -*- C++ -*- */ +//============================================================================= +/** + * @file Gadget_Part_Factory.h + * + * $Id$ + * + * @author Christopher Kohlhoff <chris@kohlhoff.com> + */ +//============================================================================= + +#ifndef GADGET_PART_FACTORY_H +#define GADGET_PART_FACTORY_H + +#include "Gadget_Part.h" +#include "Gadget.h" + +/** + * @class Gadget_Part_Factory + * + * @brief Used to create Gadget_Part instances. + */ +class Gadget_Part_Factory +{ +public: + /// Create an instance of a gadget. Ownership of the object is automatically + /// transferred to the caller since we return a Gadget_Part_var. This also + /// means that the object will be deleted automatically if the caller + /// "forgets" to collect the return value. + static Gadget_Part_var create_gadget_part (Gadget_ptr owner, + const char *name, + int size); +}; + +#endif /* GADGET_PART_FACTORY_H */ diff --git a/ACE/examples/Smart_Pointers/Gadget_Part_Impl.cpp b/ACE/examples/Smart_Pointers/Gadget_Part_Impl.cpp new file mode 100644 index 00000000000..aeda00711bb --- /dev/null +++ b/ACE/examples/Smart_Pointers/Gadget_Part_Impl.cpp @@ -0,0 +1,68 @@ +/* -*- C++ -*- */ +//============================================================================= +/** + * @file Gadget_Part_Impl.cpp + * + * $Id$ + * + * @author Christopher Kohlhoff <chris@kohlhoff.com> + */ +//============================================================================= + +#include "Gadget_Part_Impl.h" +#include "ace/ACE.h" +#include "ace/Log_Msg.h" +#include "ace/Unbounded_Queue.h" + +Gadget_Part_Impl::Gadget_Part_Impl (Gadget_ptr owner, + const char* name, + int size) + : owner_ (owner), + name_ (ACE::strnew (name)), + size_ (size) +{ + ACE_DEBUG ((LM_DEBUG, "Gadget_Part_Impl constructor\n")); +} + +Gadget_Part_Impl::~Gadget_Part_Impl (void) +{ + ACE_DEBUG ((LM_DEBUG, "Gadget_Part_Impl destructor\n")); + + delete [] name_; +} + +void Gadget_Part_Impl::print_info (void) +{ + ACE_DEBUG ((LM_INFO, "Gadget part: name=%s size=%d\n", name_, size_)); +} + +void Gadget_Part_Impl::remove_from_owner (void) +{ + // Need to guarantee the existence of the owner for the duration of this call. + Gadget_var owner = owner_; + + // Weak pointers are automatically set to NULL if the object they refer to + // is deleted. We can use this fact to check that our owner still exists. + if (owner == 0) + return; + + // Take all existing parts from the owner and build up a temporary list. If + // we find ourselves then we won't add ourselves to the list. + ACE_Unbounded_Queue<Gadget_Part_var> parts; + for (;;) + { + Gadget_Part_var part = owner->remove_part (); + if (part == 0) + break; + if (part != this) + parts.enqueue_tail (part); + } + + // Add the remaining parts back to the gadget. + while (!parts.is_empty ()) + { + Gadget_Part_var part; + parts.dequeue_head (part); + owner->add_part (part); + } +} diff --git a/ACE/examples/Smart_Pointers/Gadget_Part_Impl.h b/ACE/examples/Smart_Pointers/Gadget_Part_Impl.h new file mode 100644 index 00000000000..bcacb84f0c9 --- /dev/null +++ b/ACE/examples/Smart_Pointers/Gadget_Part_Impl.h @@ -0,0 +1,64 @@ +/* -*- C++ -*- */ +//============================================================================= +/** + * @file Gadget_Part_Impl.h + * + * $Id$ + * + * @author Christopher Kohlhoff <chris@kohlhoff.com> + */ +//============================================================================= + +#ifndef GADGET_PART_IMPL_H +#define GADGET_PART_IMPL_H + +#include "Gadget_Part.h" +#include "Gadget.h" + +/** + * @class Gadget_Part_Impl + * + * @brief An implementation of the Gadget_Part interface. + */ +class Gadget_Part_Impl : public Gadget_Part +{ +public: + /// Constructor. + Gadget_Part_Impl (Gadget_ptr owner, const char* name, int size); + + /// Destructor. + virtual ~Gadget_Part_Impl (void); + + /// Ask the part to print information about itself. + virtual void print_info (void); + + /// Ask the part to remove itself from the gadget that contains it. + virtual void remove_from_owner (void); + +private: + /// The gadget that contains this part. + /// + /// Some things to note about the choice of ACE_Weak_Bound_Ptr (from the + /// typedef for Gadget_ptr): + /// - We cannot use an ACE_Strong_Bound_Ptr (Gadget_var) since that would + /// result in circular ownership. + /// - If we use a raw pointer we have no circular ownership problems, but we + /// are unable to guarantee the lifetime of the owner object for the + /// duration of the remove_from_owner call. This may not be a problem in + /// this limited example, but in multithreaded programs remove_from_owner + /// may be called from a different thread to the thread which manages the + /// owner's lifetime. + /// - ACE_Weak_Bound_Ptr (Gadget_ptr) has no ownership semantics, so we have + /// no circular ownership problems. Weak pointers can also be converted + /// back into strong ones, so it is possible to guarantee the lifetime of + /// the owner object for the duration of the remove_from_owner call. + Gadget_ptr owner_; + + /// The name of this part. + char *name_; + + /// The size of this part. + int size_; +}; + +#endif /* GADGET_PART_IMPL_H */ diff --git a/ACE/examples/Smart_Pointers/Makefile.am b/ACE/examples/Smart_Pointers/Makefile.am new file mode 100644 index 00000000000..4595d7dafaa --- /dev/null +++ b/ACE/examples/Smart_Pointers/Makefile.am @@ -0,0 +1,70 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +ACE_BUILDDIR = $(top_builddir) +ACE_ROOT = $(top_srcdir) + +## Makefile.Smart_Pointers_Gadget.am +noinst_PROGRAMS = gadget + +gadget_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +gadget_SOURCES = \ + Gadget.cpp \ + Gadget_Factory.cpp \ + Gadget_Impl.cpp \ + Gadget_Part.cpp \ + Gadget_Part_Factory.cpp \ + Gadget_Part_Impl.cpp \ + gadget_test.cpp \ + Gadget.h \ + Gadget_Factory.h \ + Gadget_Impl.h \ + Gadget_Part.h \ + Gadget_Part_Factory.h \ + Gadget_Part_Impl.h + +gadget_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Smart_Pointers_Widget.am +noinst_PROGRAMS += Widget + +Widget_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +Widget_SOURCES = \ + Widget.cpp \ + Widget_Factory.cpp \ + Widget_Impl.cpp \ + Widget_Part.cpp \ + Widget_Part_Factory.cpp \ + Widget_Part_Impl.cpp \ + widget_test.cpp \ + Widget.h \ + Widget_Factory.h \ + Widget_Impl.h \ + Widget_Part.h \ + Widget_Part_Factory.h \ + Widget_Part_Impl.h + +Widget_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Clean up template repositories, etc. +clean-local: + -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.* + -rm -f gcctemp.c gcctemp so_locations *.ics + -rm -rf cxx_repository ptrepository ti_files + -rm -rf templateregistry ir.out + -rm -rf ptrepository SunWS_cache Templates.DB diff --git a/ACE/examples/Smart_Pointers/README b/ACE/examples/Smart_Pointers/README new file mode 100644 index 00000000000..a23ea1eb828 --- /dev/null +++ b/ACE/examples/Smart_Pointers/README @@ -0,0 +1,29 @@ +$Id$ + +Smart Pointers Example +---------------------- + +This example shows the use of the various smart pointer classes +available in ACE. + +There are two programs in this example. Each program implements a +similar set of classes, but with a different style of using smart +pointers. + +The Widget example is written such that objects may only pass raw +pointers between them, and use smart pointers to manage the object +lifetimes. An advantage of this style is the fine-grained control +over the type of smart pointer used in each situation. For example, +if you know that in a particular section of code there is no +concurrency involved, you can strategise ACE_Refcounted_Auto_Ptr on +ACE_Null_Mutex to eliminate locking overhead. Disadvantages of this +style include greater programming complexity and certain ownership +use cases not being easily supported. + +The Gadget example is written such that objects are always passed +around using one of the ACE_Strong_Bound_Ptr/ACE_Weak_Bound_Ptr +pair of smart pointers. The advantage of this style is the +reduction in complexity of object lifetime management (almost as +"good" as Java ;-) The disadvantage is that you pay a cost for the +reference counting and locking overhead even in situations where it +may not be strictly necessary. diff --git a/ACE/examples/Smart_Pointers/Smart_Pointers.mpc b/ACE/examples/Smart_Pointers/Smart_Pointers.mpc new file mode 100644 index 00000000000..fc2fc781a78 --- /dev/null +++ b/ACE/examples/Smart_Pointers/Smart_Pointers.mpc @@ -0,0 +1,28 @@ +// -*- MPC -*- +// $Id$ + +project(*Gadget) : aceexe { + exename = gadget + Source_Files { + Gadget.cpp + Gadget_Factory.cpp + Gadget_Impl.cpp + Gadget_Part.cpp + Gadget_Part_Factory.cpp + Gadget_Part_Impl.cpp + gadget_test.cpp + } +} + +project(*Widget) : aceexe { + exename = Widget + Source_Files { + Widget.cpp + Widget_Factory.cpp + Widget_Impl.cpp + Widget_Part.cpp + Widget_Part_Factory.cpp + Widget_Part_Impl.cpp + widget_test.cpp + } +} diff --git a/ACE/examples/Smart_Pointers/Widget.cpp b/ACE/examples/Smart_Pointers/Widget.cpp new file mode 100644 index 00000000000..28d01b54461 --- /dev/null +++ b/ACE/examples/Smart_Pointers/Widget.cpp @@ -0,0 +1,16 @@ +/* -*- C++ -*- */ +//============================================================================= +/** + * @file Widget.cpp + * + * $Id$ + * + * @author Christopher Kohlhoff <chris@kohlhoff.com> + */ +//============================================================================= + +#include "Widget.h" + +Widget::~Widget (void) +{ +} diff --git a/ACE/examples/Smart_Pointers/Widget.h b/ACE/examples/Smart_Pointers/Widget.h new file mode 100644 index 00000000000..a38245ca999 --- /dev/null +++ b/ACE/examples/Smart_Pointers/Widget.h @@ -0,0 +1,40 @@ +/* -*- C++ -*- */ +//============================================================================= +/** + * @file Widget.h + * + * $Id$ + * + * @author Christopher Kohlhoff <chris@kohlhoff.com> + */ +//============================================================================= + +#ifndef WIDGET_H +#define WIDGET_H + +#include "Widget_Part.h" + +/** + * @class Widget + * + * @brief An interface for some high-level application object. + */ +class Widget +{ +public: + /// Destructor. + virtual ~Widget (void); + + /// Add a new part to the widget. The widget takes ownership of the part + /// object. + virtual void add_part (Widget_Part *part) = 0; + + /// Remove a random part from the widget. Ownership of the part is returned + /// to the caller. + virtual Widget_Part *remove_part (void) = 0; + + /// Ask the widget to print information about the parts that it contains. + virtual void list_parts (void) = 0; +}; + +#endif /* WIDGET_H */ diff --git a/ACE/examples/Smart_Pointers/Widget_Factory.cpp b/ACE/examples/Smart_Pointers/Widget_Factory.cpp new file mode 100644 index 00000000000..18fec0c23f4 --- /dev/null +++ b/ACE/examples/Smart_Pointers/Widget_Factory.cpp @@ -0,0 +1,18 @@ +/* -*- C++ -*- */ +//============================================================================= +/** + * @file Widget_Factory.cpp + * + * $Id$ + * + * @author Christopher Kohlhoff <chris@kohlhoff.com> + */ +//============================================================================= + +#include "Widget_Factory.h" +#include "Widget_Impl.h" + +Widget *Widget_Factory::create_widget (void) +{ + return new Widget_Impl; +} diff --git a/ACE/examples/Smart_Pointers/Widget_Factory.h b/ACE/examples/Smart_Pointers/Widget_Factory.h new file mode 100644 index 00000000000..adf0613a3fe --- /dev/null +++ b/ACE/examples/Smart_Pointers/Widget_Factory.h @@ -0,0 +1,30 @@ +/* -*- C++ -*- */ +//============================================================================= +/** + * @file Widget_Factory.h + * + * $Id$ + * + * @author Christopher Kohlhoff <chris@kohlhoff.com> + */ +//============================================================================= + +#ifndef WIDGET_FACTORY_H +#define WIDGET_FACTORY_H + +#include "Widget.h" + +/** + * @class Widget_Factory + * + * @brief Used to create Widget instances. + */ +class Widget_Factory +{ +public: + /// Create an instance of a widget. Ownership of the newly created object is + /// transferred to the caller. + static Widget *create_widget (void); +}; + +#endif /* WIDGET_FACTORY_H */ diff --git a/ACE/examples/Smart_Pointers/Widget_Impl.cpp b/ACE/examples/Smart_Pointers/Widget_Impl.cpp new file mode 100644 index 00000000000..2d3ab404804 --- /dev/null +++ b/ACE/examples/Smart_Pointers/Widget_Impl.cpp @@ -0,0 +1,52 @@ +/* -*- C++ -*- */ +//============================================================================= +/** + * @file Widget_Impl.cpp + * + * $Id$ + * + * @author Christopher Kohlhoff <chris@kohlhoff.com> + */ +//============================================================================= + +#include "Widget_Impl.h" +#include "ace/Log_Msg.h" + +Widget_Impl::Widget_Impl (void) +{ + ACE_DEBUG ((LM_DEBUG, "Widget_Impl constructor\n")); +} + +Widget_Impl::~Widget_Impl (void) +{ + ACE_DEBUG ((LM_DEBUG, "Widget_Impl destructor\n")); +} + +void Widget_Impl::add_part (Widget_Part *part) +{ + // Take ownership of the part object using a ACE_Refcounted_Auto_Ptr. + ACE_Refcounted_Auto_Ptr<Widget_Part, ACE_SYNCH_MUTEX> new_part (part); + + parts_.enqueue_tail (new_part); +} + +Widget_Part *Widget_Impl::remove_part (void) +{ + ACE_Refcounted_Auto_Ptr<Widget_Part, ACE_SYNCH_MUTEX> removed_part; + if (parts_.dequeue_head (removed_part) == -1) + return 0; + + // Ownership of the part object is released and transferred to the caller. + return removed_part.release(); +} + +void Widget_Impl::list_parts (void) +{ + ACE_Unbounded_Queue_Iterator<ACE_Refcounted_Auto_Ptr<Widget_Part, ACE_SYNCH_MUTEX> > iter (parts_); + ACE_Refcounted_Auto_Ptr<Widget_Part, ACE_SYNCH_MUTEX> *current_part; + while (iter.next (current_part)) + { + (*current_part)->print_info (); + iter.advance (); + } +} diff --git a/ACE/examples/Smart_Pointers/Widget_Impl.h b/ACE/examples/Smart_Pointers/Widget_Impl.h new file mode 100644 index 00000000000..4933841f912 --- /dev/null +++ b/ACE/examples/Smart_Pointers/Widget_Impl.h @@ -0,0 +1,68 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file Widget_Impl.h + * + * $Id$ + * + * @author Christopher Kohlhoff <chris@kohlhoff.com> + */ +//============================================================================= + +#ifndef WIDGET_IMPL_H +#define WIDGET_IMPL_H + +#include "Widget.h" +#include "Widget_Part.h" + +#include "ace/Unbounded_Queue.h" +#include "ace/Refcounted_Auto_Ptr.h" +#include "ace/Synch_Traits.h" +#include "ace/Thread_Mutex.h" + +/** + * @class Widget_Impl + * + * @brief An implementation of the Widget interface. + */ +class Widget_Impl : public Widget +{ +public: + /// Constructor. + Widget_Impl (void); + + /// Destructor. + virtual ~Widget_Impl (void); + + /// Add a new part to the widget. The widget takes ownership of the part + /// object. + virtual void add_part (Widget_Part *part); + + /// Remove a random part from the widget. Ownership of the part is returned + /// to the caller. + virtual Widget_Part *remove_part (void); + + /// Ask the widget to print information about the parts that it contains. + virtual void list_parts (void); + +private: + /// The parts which make up this widget. The set actually contains instances + /// of ACE_Refcounted_Auto_Ptr to automatically manage the lifetimes of the + /// constituent parts. + /// + /// Some things to note about the choice of ACE_Refcounted_Auto_Ptr: + /// - We cannot use auto_ptr to manage the objects, since auto_ptr does not + /// support the copying and assignment semantics necessary for storage in + /// a container. + /// - The ACE_Strong_Bound_Ptr reference counted pointer could be used to + /// store objects in a container, however (for reasons of safety) it + /// provides no way to release ownership of the object from the smart + /// pointer. We need to be able to release ownership to implement the + /// remove_part method. + /// - ACE_Refcounted_Ptr can both be stored in containers and allows us to + /// release ownership of the pointer that it contains. + ACE_Unbounded_Queue<ACE_Refcounted_Auto_Ptr<Widget_Part, ACE_SYNCH_MUTEX> > parts_; +}; + +#endif /* WIDGET_IMPL_H */ diff --git a/ACE/examples/Smart_Pointers/Widget_Part.cpp b/ACE/examples/Smart_Pointers/Widget_Part.cpp new file mode 100644 index 00000000000..7a74447cff9 --- /dev/null +++ b/ACE/examples/Smart_Pointers/Widget_Part.cpp @@ -0,0 +1,16 @@ +/* -*- C++ -*- */ +//============================================================================= +/** + * @file Widget_Part.cpp + * + * $Id$ + * + * @author Christopher Kohlhoff <chris@kohlhoff.com> + */ +//============================================================================= + +#include "Widget_Part.h" + +Widget_Part::~Widget_Part (void) +{ +} diff --git a/ACE/examples/Smart_Pointers/Widget_Part.h b/ACE/examples/Smart_Pointers/Widget_Part.h new file mode 100644 index 00000000000..7e1f0b575a9 --- /dev/null +++ b/ACE/examples/Smart_Pointers/Widget_Part.h @@ -0,0 +1,33 @@ +/* -*- C++ -*- */ +//============================================================================= +/** + * @file Widget_Part.h + * + * $Id$ + * + * @author Christopher Kohlhoff <chris@kohlhoff.com> + */ +//============================================================================= + +#ifndef WIDGET_PART_H +#define WIDGET_PART_H + +/** + * @class Widget_Part + * + * @brief An interface for some high-level application object. + */ +class Widget_Part +{ +public: + /// Destructor. + virtual ~Widget_Part (void); + + /// Ask the part to print information about itself. + virtual void print_info (void) = 0; + + /// Ask the part to remove itself from the widget that contains it. + virtual void remove_from_owner (void) = 0; +}; + +#endif /* WIDGET_PART_H */ diff --git a/ACE/examples/Smart_Pointers/Widget_Part_Factory.cpp b/ACE/examples/Smart_Pointers/Widget_Part_Factory.cpp new file mode 100644 index 00000000000..501cdbc745c --- /dev/null +++ b/ACE/examples/Smart_Pointers/Widget_Part_Factory.cpp @@ -0,0 +1,20 @@ +/* -*- C++ -*- */ +//============================================================================= +/** + * @file Widget_Part_Factory.cpp + * + * $Id$ + * + * @author Christopher Kohlhoff <chris@kohlhoff.com> + */ +//============================================================================= + +#include "Widget_Part_Factory.h" +#include "Widget_Part_Impl.h" + +Widget_Part *Widget_Part_Factory::create_widget_part (Widget *owner, + const char* name, + int size) +{ + return new Widget_Part_Impl (owner, name, size); +} diff --git a/ACE/examples/Smart_Pointers/Widget_Part_Factory.h b/ACE/examples/Smart_Pointers/Widget_Part_Factory.h new file mode 100644 index 00000000000..4902ab91c40 --- /dev/null +++ b/ACE/examples/Smart_Pointers/Widget_Part_Factory.h @@ -0,0 +1,31 @@ +/* -*- C++ -*- */ +//============================================================================= +/** + * @file Widget_Part_Factory.h + * + * $Id$ + * + * @author Christopher Kohlhoff <chris@kohlhoff.com> + */ +//============================================================================= + +#ifndef WIDGET_PART_FACTORY_H +#define WIDGET_PART_FACTORY_H + +#include "Widget_Part.h" +#include "Widget.h" + +/** + * @class Widget_Part_Factory + * + * @brief Used to create Widget_Part instances. + */ +class Widget_Part_Factory +{ +public: + /// Create an instance of a widget part. Ownership of the newly created + /// object is transferred to the caller. + static Widget_Part *create_widget_part (Widget *owner, const char *name, int size); +}; + +#endif /* WIDGET_PART_FACTORY_H */ diff --git a/ACE/examples/Smart_Pointers/Widget_Part_Impl.cpp b/ACE/examples/Smart_Pointers/Widget_Part_Impl.cpp new file mode 100644 index 00000000000..0e4e496f180 --- /dev/null +++ b/ACE/examples/Smart_Pointers/Widget_Part_Impl.cpp @@ -0,0 +1,74 @@ +/* -*- C++ -*- */ +//============================================================================= +/** + * @file Widget_Part_Impl.cpp + * + * $Id$ + * + * @author Christopher Kohlhoff <chris@kohlhoff.com> + */ +//============================================================================= + +#include "Widget_Part_Impl.h" +#include "ace/ACE.h" +#include "ace/Log_Msg.h" +#include "ace/Refcounted_Auto_Ptr.h" +#include "ace/Unbounded_Queue.h" +#include "ace/Null_Mutex.h" + +Widget_Part_Impl::Widget_Part_Impl (Widget *owner, const char* name, int size) + : owner_ (owner), + name_ (ACE::strnew (name)), + size_ (size) +{ + ACE_DEBUG ((LM_DEBUG, "Widget_Part_Impl constructor\n")); +} + +Widget_Part_Impl::~Widget_Part_Impl (void) +{ + ACE_DEBUG ((LM_DEBUG, "Widget_Part_Impl destructor\n")); + + delete [] name_; +} + +void Widget_Part_Impl::print_info (void) +{ + ACE_DEBUG ((LM_INFO, "Widget part: name=%s size=%d\n", name_, size_)); +} + +void Widget_Part_Impl::remove_from_owner (void) +{ + // Since we only have a raw pointer to refer to the owner, we have no way of + // checking whether the owner still exists, and if it does guaranteeing that + // it will continue to exist for the duration of this call. This is not an + // issue in this limited example program, but in multithreaded applications + // this function may be called from a different thread to that managing the + // lifetime of the owner object. See the Gadget example for how + // ACE_Strong_Bound_Ptr/ACE_Weak_Bound_Ptr can be used to address the problem. + + // Take all existing parts from the owner and build up a temporary queue. If + // we find ourselves then we won't add ourselves to the queue. We will + // actually store ACE_Refcounted_Auto_Ptr instances in the queue, and since we + // know that there is only one thread involved we can use ACE_Null_Mutex to + // eliminate the locking overhead. + ACE_Unbounded_Queue<ACE_Refcounted_Auto_Ptr<Widget_Part, ACE_Null_Mutex> > parts; + for (;;) + { + ACE_Refcounted_Auto_Ptr<Widget_Part, ACE_Null_Mutex> part (owner_->remove_part ()); + if (part.null ()) + break; + if (part.get () == this) + // Someone else will be responsible for our lifetime. + part.release(); + else + parts.enqueue_tail (part); + } + + // Add the remaining parts back to the gadget. + while (!parts.is_empty ()) + { + ACE_Refcounted_Auto_Ptr<Widget_Part, ACE_Null_Mutex> part; + parts.dequeue_head (part); + owner_->add_part (part.release ()); + } +} diff --git a/ACE/examples/Smart_Pointers/Widget_Part_Impl.h b/ACE/examples/Smart_Pointers/Widget_Part_Impl.h new file mode 100644 index 00000000000..dbb1d4c714c --- /dev/null +++ b/ACE/examples/Smart_Pointers/Widget_Part_Impl.h @@ -0,0 +1,49 @@ +/* -*- C++ -*- */ +//============================================================================= +/** + * @file Widget_Part_Impl.h + * + * $Id$ + * + * @author Christopher Kohlhoff <chris@kohlhoff.com> + */ +//============================================================================= + +#ifndef WIDGET_PART_IMPL_H +#define WIDGET_PART_IMPL_H + +#include "Widget_Part.h" +#include "Widget.h" + +/** + * @class Widget_Part_Impl + * + * @brief An implementation of the Widget_Part interface. + */ +class Widget_Part_Impl : public Widget_Part +{ +public: + /// Constructor. + Widget_Part_Impl (Widget *owner, const char* name, int size); + + /// Destructor. + virtual ~Widget_Part_Impl (void); + + /// Ask the part to print information about itself. + virtual void print_info (void); + + /// Ask the part to remove itself from the widget that contains it. + virtual void remove_from_owner (void); + +private: + /// The widget that contains this part. + Widget *owner_; + + /// The name of this part. + char *name_; + + /// The size of this part. + int size_; +}; + +#endif /* WIDGET_PART_IMPL_H */ diff --git a/ACE/examples/Smart_Pointers/gadget_test.cpp b/ACE/examples/Smart_Pointers/gadget_test.cpp new file mode 100644 index 00000000000..94c17b2a556 --- /dev/null +++ b/ACE/examples/Smart_Pointers/gadget_test.cpp @@ -0,0 +1,52 @@ +/* -*- C++ -*- */ +//============================================================================= +/** + * @file gadget_test.cpp + * + * $Id$ + * + * @author Christopher Kohlhoff <chris@kohlhoff.com> + */ +//============================================================================= + +#include "ace/Auto_Ptr.h" +#include "ace/Refcounted_Auto_Ptr.h" +#include "ace/Unbounded_Queue.h" +#include "Gadget.h" +#include "Gadget_Factory.h" +#include "Gadget_Part.h" +#include "Gadget_Part_Factory.h" + +int ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + ACE_UNUSED_ARG (argc); + ACE_UNUSED_ARG (argv); + + Gadget_var g1 = Gadget_Factory::create_gadget (); + g1->add_part (Gadget_Part_Factory::create_gadget_part (g1, "part1", 1)); + g1->add_part (Gadget_Part_Factory::create_gadget_part (g1, "part2", 2)); + g1->add_part (Gadget_Part_Factory::create_gadget_part (g1, "part3", 3)); + + g1->list_parts (); + + Gadget_Part_var p1 = g1->remove_part (); + p1->print_info (); + + // Oops, we forgot to collect the return value! No worries, the temporary + // Gadget_var returned by the function call will clean it up automatically. + g1->remove_part (); + + g1->list_parts (); + + Gadget_var g2 = Gadget_Factory::create_gadget (); + g2->add_part (Gadget_Part_Factory::create_gadget_part (g2, "part4", 4)); + Gadget_Part_var p2 = Gadget_Part_Factory::create_gadget_part (g2, "part5", 5); + g2->add_part (p2); + p2->remove_from_owner (); + + g2->list_parts (); + + return 0; +} + + diff --git a/ACE/examples/Smart_Pointers/widget_test.cpp b/ACE/examples/Smart_Pointers/widget_test.cpp new file mode 100644 index 00000000000..4fc8b5824a2 --- /dev/null +++ b/ACE/examples/Smart_Pointers/widget_test.cpp @@ -0,0 +1,51 @@ +/* -*- C++ -*- */ +//============================================================================= +/** + * @file widget_test.cpp + * + * $Id$ + * + * @author Christopher Kohlhoff <chris@kohlhoff.com> + */ +//============================================================================= + +#include "ace/Auto_Ptr.h" +#include "ace/Refcounted_Auto_Ptr.h" +#include "ace/Unbounded_Queue.h" +#include "ace/Synch_Traits.h" +#include "ace/Thread_Mutex.h" +#include "ace/Null_Mutex.h" +#include "Widget.h" +#include "Widget_Factory.h" +#include "Widget_Part.h" +#include "Widget_Part_Factory.h" + +int ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + ACE_UNUSED_ARG (argc); + ACE_UNUSED_ARG (argv); + + auto_ptr<Widget> w1 (Widget_Factory::create_widget ()); + w1->add_part (Widget_Part_Factory::create_widget_part (w1.get(), "part1", 1)); + w1->add_part (Widget_Part_Factory::create_widget_part (w1.get(), "part2", 2)); + w1->add_part (Widget_Part_Factory::create_widget_part (w1.get(), "part3", 3)); + + w1->list_parts (); + + auto_ptr<Widget_Part> p1 (w1->remove_part ()); + p1->print_info (); + auto_ptr<Widget_Part> p2 (w1->remove_part ()); + + w1->list_parts (); + + auto_ptr<Widget> w2 (Widget_Factory::create_widget ()); + w2->add_part (Widget_Part_Factory::create_widget_part (w2.get(), "part4", 4)); + Widget_Part *p3 = Widget_Part_Factory::create_widget_part (w2.get(), "part5", 5); + w2->add_part (p3); + p3->remove_from_owner (); + + w2->list_parts (); + + return 0; +} + diff --git a/ACE/examples/Synch/.cvsignore b/ACE/examples/Synch/.cvsignore new file mode 100644 index 00000000000..eea98594a4b --- /dev/null +++ b/ACE/examples/Synch/.cvsignore @@ -0,0 +1 @@ +proc_sema diff --git a/ACE/examples/Synch/Makefile.am b/ACE/examples/Synch/Makefile.am new file mode 100644 index 00000000000..09319f393b3 --- /dev/null +++ b/ACE/examples/Synch/Makefile.am @@ -0,0 +1,38 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +ACE_BUILDDIR = $(top_builddir) +ACE_ROOT = $(top_srcdir) + + +## Makefile.Synch.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS = proc_sema + +proc_sema_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +proc_sema_SOURCES = \ + proc_sema.cpp + +proc_sema_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Clean up template repositories, etc. +clean-local: + -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.* + -rm -f gcctemp.c gcctemp so_locations *.ics + -rm -rf cxx_repository ptrepository ti_files + -rm -rf templateregistry ir.out + -rm -rf ptrepository SunWS_cache Templates.DB diff --git a/ACE/examples/Synch/README b/ACE/examples/Synch/README new file mode 100644 index 00000000000..526120f2744 --- /dev/null +++ b/ACE/examples/Synch/README @@ -0,0 +1,21 @@ +This directory currently only contains one example for testing process +semaphores. + +proc_sema: + This test can be used to test out the named process semaphores +support on your platform. It can be run as either a supplier or a +consumer process. The available options are: + + -c: Make us a consumer. + -s: Make us a supplier. + -x: Remove the semaphore after we're done. + -n: Specify the name of the semaphore. + -i: Number of acquire/release we'll perform. + -d: Delay for # of second before exiting the program + + You can use this test to see how process semaphores work. For +example, run the program as: + + proc_sema -c -i 10 + proc_sema -s -i 3 + proc_sema -s -i 7 diff --git a/ACE/examples/Synch/Synch.mpc b/ACE/examples/Synch/Synch.mpc new file mode 100644 index 00000000000..024e8459803 --- /dev/null +++ b/ACE/examples/Synch/Synch.mpc @@ -0,0 +1,7 @@ +// -*- MPC -*- +// $Id$ + +project : aceexe { + avoids += ace_for_tao + exename = proc_sema +} diff --git a/ACE/examples/Synch/proc_sema.cpp b/ACE/examples/Synch/proc_sema.cpp new file mode 100644 index 00000000000..d9da687ca6a --- /dev/null +++ b/ACE/examples/Synch/proc_sema.cpp @@ -0,0 +1,98 @@ +// $Id$ + +#include "ace/OS_main.h" +#include "ace/Process_Semaphore.h" +#include "ace/Get_Opt.h" +#include "ace/Log_Msg.h" +#include "ace/OS_NS_stdlib.h" +#include "ace/OS_NS_unistd.h" +#include "ace/Synch_Traits.h" + +int producer (ACE_SYNCH_PROCESS_SEMAPHORE &sema, + int iter) +{ + for (int i = iter; i > 0; --i) + { + ACE_DEBUG ((LM_DEBUG, + "Try releasing the semaphore (%d): ", + i)); + + int result = sema.release (); + + ACE_DEBUG ((LM_DEBUG, + "%s", + (result != 0 ? "fail\n" : "succeed\n"))); + } + return 0; +} + +int consumer (ACE_SYNCH_PROCESS_SEMAPHORE &sema, + int iter) +{ + for (int i = iter; i > 0; --i) + { + ACE_DEBUG ((LM_DEBUG, + "Try acquiring the semaphore (%d): ", + i)); + + int result = sema.acquire (); + + ACE_DEBUG ((LM_DEBUG, + "%s", + (result != 0 ? "fail\n" : "succeed\n"))); + } + return 0; +} + +int ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + ACE_Get_Opt getopt (argc, argv, ACE_TEXT ("csn:xi:d:")); + + int is_consumer = 1; // By default, make us a consumer. + int delete_sema = 0; + int iteration = 0; + int exit_delay = 0; + const ACE_TCHAR *sema_name = ACE_TEXT ("Process_Semaphore_Test"); + + int opt; + + while ((opt = getopt ()) != -1) + { + switch (opt) + { + case 'c': // Make us a consumer. + is_consumer = 1; + break; + case 's': // Make us a supplier. + is_consumer = 0; + break; + case 'x': // Remove the semaphore after we're done. + delete_sema = 1; + break; + case 'n': // Specify the name of the semaphore. + sema_name = getopt.opt_arg (); + break; + case 'i': // Number of acquire/release we'll perform. + iteration = ACE_OS::atoi (getopt.opt_arg ()); + break; + case 'd': + exit_delay = ACE_OS::atoi (getopt.opt_arg ()); + break; + default: + return -1; + } + }; + + ACE_SYNCH_PROCESS_SEMAPHORE sema (0, sema_name); + + if (is_consumer != 0) + consumer (sema, iteration); + else + producer (sema, iteration); + + ACE_OS::sleep (exit_delay); + + if (delete_sema != 0) + sema.remove (); + return 0; +} diff --git a/ACE/examples/System_V_IPC/Makefile.am b/ACE/examples/System_V_IPC/Makefile.am new file mode 100644 index 00000000000..23b52ee8b29 --- /dev/null +++ b/ACE/examples/System_V_IPC/Makefile.am @@ -0,0 +1,14 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +SUBDIRS = \ + SV_Message_Queues \ + SV_Semaphores + diff --git a/ACE/examples/System_V_IPC/README b/ACE/examples/System_V_IPC/README new file mode 100644 index 00000000000..c5ebde21a60 --- /dev/null +++ b/ACE/examples/System_V_IPC/README @@ -0,0 +1,13 @@ +This directory contains a number of examples that illustrate how to +use the following ACE library components: + + . SV_Message_Queues + Illustrates the ACE wrappers for System V Message + Queues. + + . SV_Semaphores + Illustrates the ACE wrappers for System V Semaphores. + + . SV_Shared_Memory + Illustrates the ACE wrappers for System V Shared Memory. + diff --git a/ACE/examples/System_V_IPC/SV_Message_Queues/.cvsignore b/ACE/examples/System_V_IPC/SV_Message_Queues/.cvsignore new file mode 100644 index 00000000000..bcdb18d69d8 --- /dev/null +++ b/ACE/examples/System_V_IPC/SV_Message_Queues/.cvsignore @@ -0,0 +1,4 @@ +mqclient +mqserver +tmqclient +tmqserver diff --git a/ACE/examples/System_V_IPC/SV_Message_Queues/MQ_Client.cpp b/ACE/examples/System_V_IPC/SV_Message_Queues/MQ_Client.cpp new file mode 100644 index 00000000000..547e4175121 --- /dev/null +++ b/ACE/examples/System_V_IPC/SV_Message_Queues/MQ_Client.cpp @@ -0,0 +1,55 @@ +// $Id$ + +#include "ace/SV_Message_Queue.h" +#include "test.h" + +// FUZZ: disable check_for_streams_include +#include "ace/streams.h" + +#include "ace/Malloc.h" +#include "ace/OS_NS_stdio.h" +#include "ace/OS_NS_unistd.h" +#include "ace/OS_NS_stdlib.h" + +ACE_RCSID(SV_Message_Queues, MQ_Client, "$Id$") + +#if defined (ACE_HAS_SYSV_IPC) && !defined(ACE_LACKS_SYSV_SHMEM) + +int +main (int, char *[]) +{ + long pid = long (ACE_OS::getpid ()); + ACE_SV_Message_Queue msgque (SRV_KEY); + Message_Block send_msg (SRV_ID, + pid, + ACE_OS::cuserid (static_cast<char *> (0)), + "did you get this?"); + Message_Block recv_msg (pid); + + if (msgque.send (send_msg, send_msg.length ()) < 0) + ACE_OS::perror ("msgque.send"), ACE_OS::exit (1); + + if (msgque.recv (recv_msg, sizeof (Message_Data), recv_msg.type ()) < 0) + ACE_OS::perror ("msgrcv"), ACE_OS::exit (1); + + cout << "a message of length " + << recv_msg.length () + << " received from server " + << recv_msg.pid () + << " (user " + << recv_msg.user () << "): " + << recv_msg.text () << "\n"; + + return 0; +} + +#else + +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_ERROR ((LM_ERROR, + "SYSV IPC, or SYSV SHMEM is not supported on this platform\n")); + return 0; +} +#endif /* ACE_HAS_SYSV_IPC && !ACE_LACKS_SYSV_SHMEM*/ + diff --git a/ACE/examples/System_V_IPC/SV_Message_Queues/MQ_Server.cpp b/ACE/examples/System_V_IPC/SV_Message_Queues/MQ_Server.cpp new file mode 100644 index 00000000000..33761465813 --- /dev/null +++ b/ACE/examples/System_V_IPC/SV_Message_Queues/MQ_Server.cpp @@ -0,0 +1,81 @@ +// $Id$ + +#include "ace/Signal.h" +#include "ace/SV_Message_Queue.h" + +// FUZZ: disable check_for_streams_include +#include "ace/streams.h" + +#include "test.h" +#include "ace/OS_NS_stdio.h" +#include "ace/OS_NS_unistd.h" +#include "ace/OS_NS_stdlib.h" + +ACE_RCSID(SV_Message_Queues, MQ_Server, "$Id$") + +#if defined (ACE_HAS_SYSV_IPC) && !defined(ACE_LACKS_SYSV_SHMEM) + +// Must be global for signal Message... +static ACE_SV_Message_Queue ace_sv_message_queue (SRV_KEY, + ACE_SV_Message_Queue::ACE_CREATE); + +extern "C" void +handler (int) +{ + if (ace_sv_message_queue.remove () < 0) + ACE_OS::perror ("ace_sv_message_queue.close"), ACE_OS::exit (1); + ACE_OS::exit (0); +} + +int +main (int, char *[]) +{ + long pid = long (ACE_OS::getpid ()); + Message_Block recv_msg (SRV_ID); + Message_Block send_msg (0, + pid, + ACE_OS::cuserid (static_cast<char *> (0)), + "I received your message."); + + // Register a signal handler. + ACE_Sig_Action sa ((ACE_SignalHandler) handler, SIGINT); + ACE_UNUSED_ARG (sa); + + for (;;) + { + if (ace_sv_message_queue.recv (recv_msg, + sizeof (Message_Data), + recv_msg.type ()) == -1) + ::perror ("ace_sv_message_queue.recv"), ACE_OS::exit (1); + + cout << "a msg of length " + << recv_msg.length () + << " sent from client " + << recv_msg.pid () + << " (user " + << recv_msg.user () << "): " + << recv_msg.text () << "\n"; + + cout.flush (); + + send_msg.type (recv_msg.pid ()); + + if (ace_sv_message_queue.send (send_msg, + send_msg.length ()) == -1) + ACE_OS::perror ("ace_sv_message_queue.send"), ACE_OS::exit (1); + } + + ACE_NOTREACHED (return 0;) +} + +#else + +#include "ace/Log_Msg.h" + +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_ERROR ((LM_ERROR, + "SYSV IPC, or SYSV SHMEM is not supported on this platform\n")); + return 0; +} +#endif /* ACE_HAS_SYSV_IPC && !ACE_LACKS_SYSV_SHMEM */ diff --git a/ACE/examples/System_V_IPC/SV_Message_Queues/Makefile.am b/ACE/examples/System_V_IPC/SV_Message_Queues/Makefile.am new file mode 100644 index 00000000000..eadb6b8df53 --- /dev/null +++ b/ACE/examples/System_V_IPC/SV_Message_Queues/Makefile.am @@ -0,0 +1,94 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +ACE_BUILDDIR = $(top_builddir) +ACE_ROOT = $(top_srcdir) + +noinst_PROGRAMS = + +## Makefile.SV_Message_Queues_MQ_Client.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS += mqclient + +mqclient_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +mqclient_SOURCES = \ + MQ_Client.cpp \ + test.h + +mqclient_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Makefile.SV_Message_Queues_MQ_Server.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS += mqserver + +mqserver_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +mqserver_SOURCES = \ + MQ_Server.cpp \ + test.h + +mqserver_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Makefile.SV_Message_Queues_TMQ_Client.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS += tmqclient + +tmqclient_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +tmqclient_SOURCES = \ + TMQ_Client.cpp \ + test.h + +tmqclient_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Makefile.SV_Message_Queues_TMQ_Server.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS += tmqserver + +tmqserver_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +tmqserver_SOURCES = \ + TMQ_Server.cpp \ + test.h + +tmqserver_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Clean up template repositories, etc. +clean-local: + -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.* + -rm -f gcctemp.c gcctemp so_locations *.ics + -rm -rf cxx_repository ptrepository ti_files + -rm -rf templateregistry ir.out + -rm -rf ptrepository SunWS_cache Templates.DB diff --git a/ACE/examples/System_V_IPC/SV_Message_Queues/SV_Message_Queues.mpc b/ACE/examples/System_V_IPC/SV_Message_Queues/SV_Message_Queues.mpc new file mode 100644 index 00000000000..62cb7a0a819 --- /dev/null +++ b/ACE/examples/System_V_IPC/SV_Message_Queues/SV_Message_Queues.mpc @@ -0,0 +1,32 @@ +// -*- MPC -*- +// $Id$ + +project(*MQ Client) : aceexe { + avoids += ace_for_tao + exename = mqclient + Source_Files { + MQ_Client.cpp + } +} +project(*MQ Server) : aceexe { + avoids += ace_for_tao + exename = mqserver + Source_Files { + MQ_Server.cpp + } +} +project(*TMQ Client) : aceexe { + avoids += ace_for_tao + exename = tmqclient + Source_Files { + TMQ_Client.cpp + } +} +project(*TMQ Server) : aceexe { + avoids += ace_for_tao + exename = tmqserver + Source_Files { + TMQ_Server.cpp + } +} + diff --git a/ACE/examples/System_V_IPC/SV_Message_Queues/TMQ_Client.cpp b/ACE/examples/System_V_IPC/SV_Message_Queues/TMQ_Client.cpp new file mode 100644 index 00000000000..d48939845d5 --- /dev/null +++ b/ACE/examples/System_V_IPC/SV_Message_Queues/TMQ_Client.cpp @@ -0,0 +1,52 @@ +// $Id$ + +#include "ace/Typed_SV_Message_Queue.h" + +// FUZZ: disable check_for_streams_include +#include "ace/streams.h" + +#include "ace/Log_Msg.h" +#include "test.h" +#include "ace/OS_NS_stdio.h" +#include "ace/OS_NS_unistd.h" + +ACE_RCSID(SV_Message_Queues, TMQ_Client, "$Id$") + +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + long pid = long (ACE_OS::getpid ()); + + ACE_Typed_SV_Message_Queue<Message_Data> msgque (key_t (SRV_KEY)); + + Message_Data msg_data (pid, + ACE_OS::cuserid (static_cast<char *> (0)), + "did you get this?"); + + ACE_Typed_SV_Message<Message_Data> send_msg (msg_data, + SRV_ID, + msg_data.length ()), + recv_msg (pid); + + if (msgque.send (send_msg) < 0) + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), + ACE_TEXT ("msgque.send")), 1); + + if (msgque.recv (recv_msg) < 0) + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), + ACE_TEXT ("msgque.recv")), 1); + + Message_Data &recv_msg_data = recv_msg.data (); + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("a message of length %d") + ACE_TEXT (" received from server %d") + ACE_TEXT (" (user %C): %C\n"), + recv_msg_data.length (), + recv_msg_data.pid (), + recv_msg_data.user (), + recv_msg_data.text ())); + + return 0; +} + diff --git a/ACE/examples/System_V_IPC/SV_Message_Queues/TMQ_Server.cpp b/ACE/examples/System_V_IPC/SV_Message_Queues/TMQ_Server.cpp new file mode 100644 index 00000000000..0da9aeec763 --- /dev/null +++ b/ACE/examples/System_V_IPC/SV_Message_Queues/TMQ_Server.cpp @@ -0,0 +1,78 @@ +// $Id$ + +#include "ace/Signal.h" +#include "ace/Typed_SV_Message_Queue.h" + +#include "test.h" + +// FUZZ: disable check_for_streams_include +#include "ace/streams.h" + +#include "ace/Log_Msg.h" +#include "ace/OS_NS_stdio.h" +#include "ace/OS_NS_stdlib.h" +#include "ace/OS_NS_unistd.h" + +ACE_RCSID(SV_Message_Queues, TMQ_Server, "$Id$") + +#if defined (ACE_HAS_SYSV_IPC) && !defined(ACE_LACKS_SYSV_SHMEM) + +// Must be global for signal Message... +static ACE_Typed_SV_Message_Queue<Message_Data> ace_sv_message_queue + (SRV_KEY, ACE_Typed_SV_Message_Queue<Message_Data>::ACE_CREATE); + +extern "C" void +handler (int) +{ + if (ace_sv_message_queue.remove () < 0) + ACE_ERROR ((LM_ERROR, "%p\n%a", "ace_sv_message_queue.recv", 1)); + ACE_OS::exit (0); +} + +int +main (int, char *[]) +{ + char *username = ACE_OS::cuserid (static_cast<char *> (0)); + Message_Data msg_data ((int) ACE_OS::getpid (), username, "I received your message."); + ACE_Typed_SV_Message<Message_Data> send_msg (msg_data, 0, msg_data.length ()); + ACE_Typed_SV_Message<Message_Data> recv_msg (SRV_ID); + + // Register a signal handler. + ACE_Sig_Action sa ((ACE_SignalHandler) handler, SIGINT); + ACE_UNUSED_ARG (sa); + + for (;;) + { + if (ace_sv_message_queue.recv (recv_msg) == -1) + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "ace_sv_message_queue.recv"), 1); + + Message_Data &recv_msg_data = recv_msg.data (); + + cout << "a msg of length " + << recv_msg_data.length () + << " sent from client " + << recv_msg_data.pid () + << " (user " + << recv_msg_data.user () << "): " + << recv_msg_data.text () << "\n"; + cout.flush (); + + send_msg.type (recv_msg_data.pid ()); + + if (ace_sv_message_queue.send (send_msg) < 0) + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "ace_sv_message_queue.send"), 1); + } + + ACE_NOTREACHED (return 0;) +} + +#else + +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_ERROR ((LM_ERROR, + "SYSV IPC, or SYSV SHMEM is not supported on this platform\n")); + return 0; +} +#endif /* ACE_HAS_SYSV_IPC && !ACE_LACKS_SYSV_SHMEM */ + diff --git a/ACE/examples/System_V_IPC/SV_Message_Queues/test.h b/ACE/examples/System_V_IPC/SV_Message_Queues/test.h new file mode 100644 index 00000000000..f17cf11c63e --- /dev/null +++ b/ACE/examples/System_V_IPC/SV_Message_Queues/test.h @@ -0,0 +1,58 @@ +/* -*- C++ -*- */ +// $Id$ + +#include "ace/OS_NS_string.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/SV_Message.h" + +#define MSGSZ 128 +#define SRV_KEY ACE_DEFAULT_SHM_KEY +#define SRV_ID 1 + +class Message_Data +{ +public: + Message_Data (long p = -1, + const char user[] = "", + const char text[] = ""): pid_ (p) + { + ACE_OS::strncpy (this->username_, user, 9); + ACE_OS::strncpy (this->mtext_, text, MSGSZ); + } + + long pid (void) { return this->pid_; } + void pid (long p) { this->pid_ = p; } + char *user (void) { return this->username_; } + void user (char user[]) { ACE_OS::strncpy (this->username_, user, 9); } + char *text (void) { return this->mtext_; } + void text (char text[]) { ACE_OS::strncpy (this->mtext_, text, MSGSZ); } + int length (void) { return sizeof *this - sizeof this->mtext_ + ACE_OS::strlen (this->mtext_) + 1; } + +protected: + long pid_; + char username_[9]; + char mtext_[MSGSZ]; +}; + +class Message_Block : public ACE_SV_Message, public Message_Data +{ + // = TITLE + // Stores message content. + // = DESCRIPTION + // This may not be 100 percent portable on all C++ compilers since + // it relies on inheritance to be "concatenation." + // +public: + Message_Block (long t, + long p = 0, + const char login[] = "", + const char message[] = "") + : ACE_SV_Message (t), + Message_Data (p, login, message) + {} +}; + diff --git a/ACE/examples/System_V_IPC/SV_Semaphores/.cvsignore b/ACE/examples/System_V_IPC/SV_Semaphores/.cvsignore new file mode 100644 index 00000000000..bb37ee6c9a7 --- /dev/null +++ b/ACE/examples/System_V_IPC/SV_Semaphores/.cvsignore @@ -0,0 +1,2 @@ +sem1 +sem2 diff --git a/ACE/examples/System_V_IPC/SV_Semaphores/Makefile.am b/ACE/examples/System_V_IPC/SV_Semaphores/Makefile.am new file mode 100644 index 00000000000..de9a88952a6 --- /dev/null +++ b/ACE/examples/System_V_IPC/SV_Semaphores/Makefile.am @@ -0,0 +1,56 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +ACE_BUILDDIR = $(top_builddir) +ACE_ROOT = $(top_srcdir) + +noinst_PROGRAMS = + +## Makefile.SV_Semaphores_1.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS += sem1 + +sem1_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +sem1_SOURCES = \ + Semaphores_1.cpp + +sem1_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Makefile.SV_Semaphores_2.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS += sem2 + +sem2_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +sem2_SOURCES = \ + Semaphores_2.cpp + +sem2_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Clean up template repositories, etc. +clean-local: + -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.* + -rm -f gcctemp.c gcctemp so_locations *.ics + -rm -rf cxx_repository ptrepository ti_files + -rm -rf templateregistry ir.out + -rm -rf ptrepository SunWS_cache Templates.DB diff --git a/ACE/examples/System_V_IPC/SV_Semaphores/SV_Semaphores.mpc b/ACE/examples/System_V_IPC/SV_Semaphores/SV_Semaphores.mpc new file mode 100644 index 00000000000..647e4a4cf5a --- /dev/null +++ b/ACE/examples/System_V_IPC/SV_Semaphores/SV_Semaphores.mpc @@ -0,0 +1,17 @@ +// -*- MPC -*- +// $Id$ + +project(*1) : aceexe { + avoids += ace_for_tao + exename = sem1 + Source_Files { + Semaphores_1.cpp + } +} +project(*2) : aceexe { + avoids += ace_for_tao + exename = sem2 + Source_Files { + Semaphores_2.cpp + } +} diff --git a/ACE/examples/System_V_IPC/SV_Semaphores/Semaphores_1.cpp b/ACE/examples/System_V_IPC/SV_Semaphores/Semaphores_1.cpp new file mode 100644 index 00000000000..2331ea772ec --- /dev/null +++ b/ACE/examples/System_V_IPC/SV_Semaphores/Semaphores_1.cpp @@ -0,0 +1,94 @@ +// $Id$ + +#include "ace/SV_Shared_Memory.h" +#include "ace/SV_Semaphore_Simple.h" +#include "ace/SV_Semaphore_Complex.h" +#include "ace/Shared_Memory_Pool.h" +#include "ace/Malloc_T.h" +#include "ace/OS_NS_unistd.h" + + +ACE_RCSID (SV_Semaphores, + Semaphores_1, + "$Id$") + + +#if defined (ACE_HAS_SYSV_IPC) && !defined(ACE_LACKS_SYSV_SHMEM) + +// Shared memory allocator (note that this chews up the +// ACE_DEFAULT_SEM_KEY). +static ACE_Malloc<ACE_SHARED_MEMORY_POOL, ACE_SV_Semaphore_Simple> alloc; + +const int SEM_KEY = ACE_DEFAULT_SEM_KEY + 1; + +static int +parent (char *shm) +{ + char *s = shm; + + ACE_SV_Semaphore_Complex sem (SEM_KEY, ACE_SV_Semaphore_Complex::ACE_CREATE, 0, 2); + + for (char c = 'a'; c <= 'z'; c++) + *s++ = c; + + *s = '\0'; + + if (sem.release (0) == -1) + ACE_ERROR ((LM_ERROR, "%p", "parent sem.release(0)")); + else if (sem.acquire (1) == -1) + ACE_ERROR ((LM_ERROR, "%p", "parent sem.acquire(1)")); + + if (alloc.remove () == -1) + ACE_ERROR ((LM_ERROR, "%p\n", "alloc.remove")); + if (sem.remove () == -1) + ACE_ERROR ((LM_ERROR, "%p\n", "sem.remove")); + return 0; +} + +static int +child (char *shm) +{ + ACE_SV_Semaphore_Complex sem (SEM_KEY, ACE_SV_Semaphore_Complex::ACE_CREATE, 0, 2); + + while (sem.tryacquire (0) == -1) + if (errno == EAGAIN) + ACE_DEBUG ((LM_DEBUG, "spinning in client!\n")); + else + ACE_ERROR_RETURN ((LM_ERROR, "client mutex.tryacquire(0)"), 1); + + for (char *s = (char *) shm; *s != '\0'; s++) + ACE_DEBUG ((LM_DEBUG, "%c", *s)); + + ACE_DEBUG ((LM_DEBUG, "\n")); + + if (sem.release (1) < 0) + ACE_ERROR ((LM_ERROR, "client sem.release(1)")); + return 0; +} + +int +main (int, char *[]) +{ + char *shm = (char *) alloc.malloc (27); + + switch (ACE_OS::fork ()) + { + case -1: + ACE_ERROR_RETURN ((LM_ERROR, "fork failed\n"), -1); + /* NOTREACHED */ + case 0: + // Child. + return child (shm); + default: + return parent (shm); + } +} +#else +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_ERROR ((LM_ERROR, + "SYSV IPC, or SYSV SHMEM is not supported on this platform\n")); + return 0; +} +#endif /* ACE_HAS_SYSV_IPC */ + diff --git a/ACE/examples/System_V_IPC/SV_Semaphores/Semaphores_2.cpp b/ACE/examples/System_V_IPC/SV_Semaphores/Semaphores_2.cpp new file mode 100644 index 00000000000..e0ae9cd2bb5 --- /dev/null +++ b/ACE/examples/System_V_IPC/SV_Semaphores/Semaphores_2.cpp @@ -0,0 +1,110 @@ +// $Id$ + +// Illustrates the use of the ACE_SV_Semaphore_Complex class and the +// ACE_Malloc class using the ACE_Shared_Memory_Pool (which uses +// System V shared memory). Note that it doesn't matter whether the +// parent or the child creates the semaphore since Semaphore_Complex +// will correctly serialize the intialization of the mutex and synch +// objects. + +#include "ace/Malloc_T.h" +#include "ace/Shared_Memory_Pool.h" +#include "ace/SV_Semaphore_Complex.h" +#include "ace/OS_NS_unistd.h" + +ACE_RCSID(SV_Semaphores, Semaphores_2, "$Id$") + +#if defined (ACE_HAS_SYSV_IPC) && !defined(ACE_LACKS_SYSV_SHMEM) + +// Shared memory allocator (note that this chews up the +// ACE_DEFAULT_SEM_KEY). +static ACE_Malloc<ACE_SHARED_MEMORY_POOL, ACE_SV_Semaphore_Simple> my_alloc; + +const int SEM_KEY_1 = ACE_DEFAULT_SEM_KEY + 1; +const int SEM_KEY_2 = ACE_DEFAULT_SEM_KEY + 2; + +static int +parent (char *shm) +{ + char *s = shm; + + // Both semaphores are initially created with a count of 0, i.e., + // they are "locked." + ACE_SV_Semaphore_Complex mutex (SEM_KEY_1, ACE_SV_Semaphore_Complex::ACE_CREATE, 0); + ACE_SV_Semaphore_Complex synch (SEM_KEY_2, ACE_SV_Semaphore_Complex::ACE_CREATE, 0); + + // This is a critical section, which is protected by the mutex + // semaphore. + for (char c = 'a'; c <= 'z'; c++) + *s++ = c; + + *s = '\0'; + + if (mutex.release () == -1) + ACE_ERROR ((LM_ERROR, "%p", "parent mutex.release")); + else if (synch.acquire () == -1) + ACE_ERROR ((LM_ERROR, "%p", "parent synch.acquire")); + + if (my_alloc.remove () == -1) + ACE_ERROR ((LM_ERROR, "%p\n", "my_alloc.remove")); + if (mutex.remove () == -1) + ACE_ERROR ((LM_ERROR, "%p\n", "mutex.remove")); + if (synch.remove () == -1) + ACE_ERROR ((LM_ERROR, "%p\n", "synch.remove")); + return 0; +} + +static int +child (char *shm) +{ + // Both semaphores are initially created with a count of 0, i.e., + // they are "locked." + ACE_SV_Semaphore_Complex mutex (SEM_KEY_1, ACE_SV_Semaphore_Complex::ACE_CREATE, 0); + ACE_SV_Semaphore_Complex synch (SEM_KEY_2, ACE_SV_Semaphore_Complex::ACE_CREATE, 0); + + // Perform "busy waiting" here until we acquire the semaphore. This + // isn't really a good design -- it's just to illustrate that you + // can do non-blocking acquire() calls with the ACE System V + // semaphore wrappers. + while (mutex.tryacquire () == -1) + if (errno == EAGAIN) + ACE_DEBUG ((LM_DEBUG, "spinning in child!\n")); + else + ACE_ERROR_RETURN ((LM_ERROR, "child mutex.tryacquire"), 1); + + for (char *s = (char *) shm; *s != '\0'; s++) + ACE_DEBUG ((LM_DEBUG, "%c", *s)); + + ACE_DEBUG ((LM_DEBUG, "\n")); + + if (synch.release () == -1) + ACE_ERROR_RETURN ((LM_ERROR, "child synch.release"), 1); + return 0; +} + +int +main (int, char *[]) +{ + char *shm = (char *) my_alloc.malloc (27); + + switch (ACE_OS::fork ()) + { + case -1: + ACE_ERROR_RETURN ((LM_ERROR, "fork failed\n"), -1); + /* NOTREACHED */ + case 0: + // Child. + return child (shm); + default: + return parent (shm); + } +} +#else +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_ERROR ((LM_ERROR, + "SYSV IPC, or SYSV SHMEM is not supported on this platform\n")); + return 0; +} +#endif /* ACE_HAS_SYSV_IPC */ + diff --git a/ACE/examples/System_V_IPC/SV_Shared_Memory/SV_Shared_Memory_Test.cpp b/ACE/examples/System_V_IPC/SV_Shared_Memory/SV_Shared_Memory_Test.cpp new file mode 100644 index 00000000000..3a36e395d35 --- /dev/null +++ b/ACE/examples/System_V_IPC/SV_Shared_Memory/SV_Shared_Memory_Test.cpp @@ -0,0 +1,78 @@ +// $Id$ + +#include "ace/SV_Shared_Memory.h" +#include "ace/Log_Msg.h" +#include "SV_Shared_Memory_Test.h" +#include "ace/OS_NS_stdio.h" +#include "ace/OS_NS_stdlib.h" +#include "ace/OS_NS_unistd.h" + +ACE_RCSID(SV_Shared_Memory, SV_Shared_Memory_Test, "$Id$") + +#if defined (ACE_HAS_SYSV_IPC) && !defined(ACE_LACKS_SYSV_SHMEM) + +static void +client (void) +{ + ACE_SV_Shared_Memory shm_client; + + if (shm_client.open_and_attach (SHM_KEY, SHMSZ) == -1) + ACE_OS::perror ("open"), ACE_OS::exit (1); + + for (char *s = (char *) shm_client.get_segment_ptr (); *s != '\0'; s++) + putchar (*s); + + putchar ('\n'); + *(char *) shm_client.get_segment_ptr () = '*'; + ACE_OS::exit (0); +} + +static void +server (void) +{ + ACE_SV_Shared_Memory shm_server; + + if (shm_server.open_and_attach (SHM_KEY, SHMSZ, ACE_SV_Shared_Memory::ACE_CREATE) == -1) + ACE_OS::perror ("open"), ACE_OS::exit (1); + + char *s = (char *) shm_server.get_segment_ptr (); + + for (char c = 'a'; c <= 'z'; c++) + *s++ = c; + + *s = '\0'; + + for (s = (char *) shm_server.get_segment_ptr (); *s != '*'; ) + ACE_OS::sleep (1); + + if (shm_server.remove () < 0) + ACE_OS::perror ("remove"), ACE_OS::exit (1); + ACE_OS::exit (0); +} + +int +main (int, char *argv[]) +{ + switch (ACE_OS::fork ()) + { + case -1: + ACE_OS::perror (argv[0]), ACE_OS::exit (1); + case 0: + ACE_OS::sleep (1); + client (); + default: + server (); + } + return 0; +} + +#else + +int ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_ERROR ((LM_ERROR, + "SYSV IPC, or SYSV SHMEM is not supported on this platform\n")); + return 0; +} +#endif /* ACE_HAS_SYSV_IPC && !ACE_LACKS_SYSV_SHMEM */ + diff --git a/ACE/examples/System_V_IPC/SV_Shared_Memory/SV_Shared_Memory_Test.h b/ACE/examples/System_V_IPC/SV_Shared_Memory/SV_Shared_Memory_Test.h new file mode 100644 index 00000000000..3cfff4672b9 --- /dev/null +++ b/ACE/examples/System_V_IPC/SV_Shared_Memory/SV_Shared_Memory_Test.h @@ -0,0 +1,12 @@ +/* -*- C++ -*- */ +// $Id$ + +#include "ace/config-all.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#define SHMSZ 27 +#define SEM_KEY 1234 +#define SHM_KEY 5678 diff --git a/ACE/examples/TMCast/Makefile.am b/ACE/examples/TMCast/Makefile.am new file mode 100644 index 00000000000..ad8cc650602 --- /dev/null +++ b/ACE/examples/TMCast/Makefile.am @@ -0,0 +1,13 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +SUBDIRS = \ + Member + diff --git a/ACE/examples/TMCast/Member/.cvsignore b/ACE/examples/TMCast/Member/.cvsignore new file mode 100644 index 00000000000..fa6ecc72251 --- /dev/null +++ b/ACE/examples/TMCast/Member/.cvsignore @@ -0,0 +1 @@ +member diff --git a/ACE/examples/TMCast/Member/Makefile.am b/ACE/examples/TMCast/Member/Makefile.am new file mode 100644 index 00000000000..fe970a85ef5 --- /dev/null +++ b/ACE/examples/TMCast/Member/Makefile.am @@ -0,0 +1,45 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +ACE_BUILDDIR = $(top_builddir) +ACE_ROOT = $(top_srcdir) + + +## Makefile.Member.am + +if BUILD_EXCEPTIONS +if BUILD_THREADS +if !BUILD_ACE_FOR_TAO + +noinst_PROGRAMS = member + +member_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) \ + -I$(ACE_ROOT)/protocols + +member_SOURCES = \ + member.cpp + +member_LDADD = \ + $(ACE_BUILDDIR)/protocols/ace/TMCast/libACE_TMCast.la \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO +endif BUILD_THREADS +endif BUILD_EXCEPTIONS + +## Clean up template repositories, etc. +clean-local: + -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.* + -rm -f gcctemp.c gcctemp so_locations *.ics + -rm -rf cxx_repository ptrepository ti_files + -rm -rf templateregistry ir.out + -rm -rf ptrepository SunWS_cache Templates.DB diff --git a/ACE/examples/TMCast/Member/Member.mpc b/ACE/examples/TMCast/Member/Member.mpc new file mode 100644 index 00000000000..29f274f51f3 --- /dev/null +++ b/ACE/examples/TMCast/Member/Member.mpc @@ -0,0 +1,7 @@ +// -*- MPC -*- +// $Id$ + +project: aceexe, tmcast { + exename = member +} + diff --git a/ACE/examples/TMCast/Member/README b/ACE/examples/TMCast/Member/README new file mode 100644 index 00000000000..6a62a107a77 --- /dev/null +++ b/ACE/examples/TMCast/Member/README @@ -0,0 +1,36 @@ +Member example shows how you can build a simple multicast group +using transactional multicast (TMCast). Each member can be either +a sender or a receiver. + +The sender sends small messages to the multicast group with a random +wait period in [0, 1] second range. The receiver is simply receiving +those messages and prints them out. + +To start the sender you can execute something like this: + +$ ./member s sender-1 239.255.0.1:10000 + +Here the first argument ('s') indicates that new member will be +a sender. The second argument ('sender-1') is an id of the new +member (each member of the group should have a unique id). And +the third argument ('239.255.0.1:10000') specifies IPv4 multicast +address and port (you can choose you own). + +To start the receiver you can execute similar command: + +$ ./member r receiver-1 239.255.0.1:10000 + +After you have started both the receiver and the sender you +should see a sequence of messages printed by the receiver. + +Note, since the group can exist with only one member for a +very short period of time you should start first two members +virtually at the same time. See TMCast documentation for more +information about why it behaves this way. + +You may want to add more than one sender to the group if you +want to see how TMCast operates in a totally-ordered mode. + + +-- +Boris Kolpackov <boris@dre.vanderbilt.edu> diff --git a/ACE/examples/TMCast/Member/member.cpp b/ACE/examples/TMCast/Member/member.cpp new file mode 100644 index 00000000000..f89c68564ea --- /dev/null +++ b/ACE/examples/TMCast/Member/member.cpp @@ -0,0 +1,93 @@ +// file : TMCast/Member/member.cpp +// author : Boris Kolpackov <boris@dre.vanderbilt.edu> +// cvs-id : $Id$ + +#include "ace/Log_Msg.h" +#include "ace/Time_Value.h" +#include "ace/OS_NS_stdlib.h" +#include "ace/OS_NS_unistd.h" +#include "ace/OS_NS_stdio.h" +#include "ace/OS_NS_time.h" +#include "ace/OS_NS_string.h" + +#include "ace/TMCast/Group.hpp" + +class Args {}; + +int +ACE_TMAIN (int argc, ACE_TCHAR* argv[]) +{ + int status = 0; + try + { + if (argc < 4) throw Args (); + + bool receiver (true); + + if (argv[1][0] == 'r') receiver = true; + else if (argv[1][0] == 's') receiver = false; + else throw Args (); + + if (!receiver) ACE_OS::srand (ACE_OS::time ()); + + ACE_INET_Addr address (argv[3]); + + ACE_TMCast::Group group (address, ACE_TEXT_ALWAYS_CHAR (argv[2])); + + if (receiver) + { + for (char buffer[256];;) + { + group.recv (buffer, sizeof (buffer)); + + ACE_DEBUG ((LM_DEBUG, "%s\n", buffer)); + } + } + else + { + char buffer[256]; + + for (unsigned long i = 0; i < 1000; i++) + { + // Sleep some random time around 1 sec. + + ACE_UINT64 tmpl = 1000000U; + unsigned long t = + static_cast<unsigned long> (((tmpl * ACE_OS::rand ()) / RAND_MAX)); + + // ACE_DEBUG ((LM_DEBUG, "sleeping for %u\n", t)); + + ACE_OS::sleep (ACE_Time_Value (0, t)); + + ACE_OS::sprintf (buffer, "message # %lu", i); + + try + { + group.send (buffer, ACE_OS::strlen (buffer) + 1); + } + catch (ACE_TMCast::Group::Aborted const&) + { + ACE_ERROR ((LM_ERROR, "%s has been aborted\n", buffer)); + } + } + } + } + catch (Args const&) + { + ACE_ERROR ((LM_ERROR, + "Usage: member {r|s} <id> <IPv4 mcast address>:<port>\n")); + status++; + } + catch (ACE_TMCast::Group::Failed const&) + { + ACE_ERROR ((LM_ERROR, + "Group failure. Perhaps I am alone in the group.\n")); + status++; + } + catch (ACE_TMCast::Group::InsufficienSpace const&) + { + ACE_ERROR ((LM_ERROR, "Insufficient space in receive buffer.\n")); + status++; + } + return status; +} diff --git a/ACE/examples/Threads/.cvsignore b/ACE/examples/Threads/.cvsignore new file mode 100644 index 00000000000..29680be7dcc --- /dev/null +++ b/ACE/examples/Threads/.cvsignore @@ -0,0 +1,22 @@ +auto_event +barrier1 +barrier2 +cancel +future1 +future2 +manual_event +process_mutex +process_semaphore +reader_writer +recursive_mutex +task_five +task_four +task_one +task_three +task_two +thread_manager +thread_pool +thread_specific +token +tss1 +tss2 diff --git a/ACE/examples/Threads/Makefile.am b/ACE/examples/Threads/Makefile.am new file mode 100644 index 00000000000..edd80b72542 --- /dev/null +++ b/ACE/examples/Threads/Makefile.am @@ -0,0 +1,408 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +ACE_BUILDDIR = $(top_builddir) +ACE_ROOT = $(top_srcdir) + + +## Makefile.Threads_Auto_Event.am +noinst_PROGRAMS = auto_event + +auto_event_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +auto_event_SOURCES = \ + auto_event.cpp \ + TSS_Data.h \ + TSS_Obj.h \ + TSS_Task.h \ + thread_specific.h + +auto_event_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Threads_Barrier1.am +noinst_PROGRAMS += barrier1 + +barrier1_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +barrier1_SOURCES = \ + barrier1.cpp \ + TSS_Data.h \ + TSS_Obj.h \ + TSS_Task.h \ + thread_specific.h + +barrier1_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Threads_Barrier2.am +noinst_PROGRAMS += barrier2 + +barrier2_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +barrier2_SOURCES = \ + barrier2.cpp \ + TSS_Data.h \ + TSS_Obj.h \ + TSS_Task.h \ + thread_specific.h + +barrier2_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Threads_Cancel.am +noinst_PROGRAMS += cancel + +cancel_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +cancel_SOURCES = \ + cancel.cpp \ + TSS_Data.h \ + TSS_Obj.h \ + TSS_Task.h \ + thread_specific.h + +cancel_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Threads_Future1.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS += future1 + +future1_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +future1_SOURCES = \ + future1.cpp \ + TSS_Data.h \ + TSS_Obj.h \ + TSS_Task.h \ + thread_specific.h + +future1_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Makefile.Threads_Future2.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS += future2 + +future2_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +future2_SOURCES = \ + future2.cpp \ + TSS_Data.h \ + TSS_Obj.h \ + TSS_Task.h \ + thread_specific.h + +future2_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Makefile.Threads_Manual_Event.am +noinst_PROGRAMS += manual_event + +manual_event_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +manual_event_SOURCES = \ + manual_event.cpp \ + TSS_Data.h \ + TSS_Obj.h \ + TSS_Task.h \ + thread_specific.h + +manual_event_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Threads_Process_Mutex.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS += process_mutex + +process_mutex_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +process_mutex_SOURCES = \ + process_mutex.cpp \ + TSS_Data.h \ + TSS_Obj.h \ + TSS_Task.h \ + thread_specific.h + +process_mutex_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Makefile.Threads_Process_Semaphore.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS += process_semaphore + +process_semaphore_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +process_semaphore_SOURCES = \ + process_semaphore.cpp \ + TSS_Data.h \ + TSS_Obj.h \ + TSS_Task.h \ + thread_specific.h + +process_semaphore_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Makefile.Threads_Reader_Writer.am +noinst_PROGRAMS += reader_writer + +reader_writer_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +reader_writer_SOURCES = \ + reader_writer.cpp \ + TSS_Data.h \ + TSS_Obj.h \ + TSS_Task.h \ + thread_specific.h + +reader_writer_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Threads_Recursive_Mutex.am +noinst_PROGRAMS += recursive_mutex + +recursive_mutex_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +recursive_mutex_SOURCES = \ + recursive_mutex.cpp \ + TSS_Data.h \ + TSS_Obj.h \ + TSS_Task.h \ + thread_specific.h + +recursive_mutex_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Threads_Task_Five.am +noinst_PROGRAMS += task_five + +task_five_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +task_five_SOURCES = \ + task_five.cpp \ + TSS_Data.h \ + TSS_Obj.h \ + TSS_Task.h \ + thread_specific.h + +task_five_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Threads_Task_Four.am +noinst_PROGRAMS += task_four + +task_four_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +task_four_SOURCES = \ + task_four.cpp \ + TSS_Data.h \ + TSS_Obj.h \ + TSS_Task.h \ + thread_specific.h + +task_four_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Threads_Task_One.am +noinst_PROGRAMS += task_one + +task_one_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +task_one_SOURCES = \ + task_one.cpp \ + TSS_Data.h \ + TSS_Obj.h \ + TSS_Task.h \ + thread_specific.h + +task_one_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Threads_Task_Three.am +noinst_PROGRAMS += task_three + +task_three_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +task_three_SOURCES = \ + task_three.cpp \ + TSS_Data.h \ + TSS_Obj.h \ + TSS_Task.h \ + thread_specific.h + +task_three_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Threads_Task_Two.am +noinst_PROGRAMS += task_two + +task_two_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +task_two_SOURCES = \ + task_two.cpp \ + TSS_Data.h \ + TSS_Obj.h \ + TSS_Task.h \ + thread_specific.h + +task_two_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Threads_Thread_Manager.am +noinst_PROGRAMS += thread_manager + +thread_manager_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +thread_manager_SOURCES = \ + thread_manager.cpp \ + TSS_Data.h \ + TSS_Obj.h \ + TSS_Task.h \ + thread_specific.h + +thread_manager_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Threads_Thread_Pool.am +noinst_PROGRAMS += thread_pool + +thread_pool_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +thread_pool_SOURCES = \ + thread_pool.cpp \ + TSS_Data.h \ + TSS_Obj.h \ + TSS_Task.h \ + thread_specific.h + +thread_pool_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Threads_Thread_Specific.am +noinst_PROGRAMS += thread_specific + +thread_specific_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +thread_specific_SOURCES = \ + thread_specific.cpp \ + thread_specific.h + +thread_specific_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Threads_Token.am +noinst_PROGRAMS += token + +token_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +token_SOURCES = \ + token.cpp \ + TSS_Data.h \ + TSS_Obj.h \ + TSS_Task.h \ + thread_specific.h + +token_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Threads_Tss1.am +noinst_PROGRAMS += tss1 + +tss1_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +tss1_SOURCES = \ + tss1.cpp \ + TSS_Data.h \ + TSS_Obj.h \ + TSS_Task.h \ + thread_specific.h + +tss1_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Threads_Tss2.am +noinst_PROGRAMS += tss2 + +tss2_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +tss2_SOURCES = \ + tss2.cpp \ + TSS_Data.h \ + TSS_Obj.h \ + TSS_Task.h \ + thread_specific.h + +tss2_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Clean up template repositories, etc. +clean-local: + -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.* + -rm -f gcctemp.c gcctemp so_locations *.ics + -rm -rf cxx_repository ptrepository ti_files + -rm -rf templateregistry ir.out + -rm -rf ptrepository SunWS_cache Templates.DB diff --git a/ACE/examples/Threads/TSS_Data.h b/ACE/examples/Threads/TSS_Data.h new file mode 100644 index 00000000000..3c9dfcfe28c --- /dev/null +++ b/ACE/examples/Threads/TSS_Data.h @@ -0,0 +1,40 @@ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// examples +// +// = FILENAME +// TSS_Data.cpp +// +// = AUTHOR +// Prashant Jain and Doug Schmidt +// +// ============================================================================ + +#include "ace/Singleton.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Synch_Traits.h" + +class TSS_Data + // = TITLE + // Data that is stored in thread-specific storage. +{ +public: + void *data (void) { return this->data_; } + void data (void *v) { this->data_ = v; } + +private: + // = data_ will be thread-specific data so it doesn't need a lock. + void *data_; +}; + +typedef ACE_TSS_Singleton<TSS_Data, ACE_SYNCH_MUTEX> TSS_DATA; + + + diff --git a/ACE/examples/Threads/TSS_Obj.h b/ACE/examples/Threads/TSS_Obj.h new file mode 100644 index 00000000000..7dc4e469851 --- /dev/null +++ b/ACE/examples/Threads/TSS_Obj.h @@ -0,0 +1,39 @@ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// tests +// +// = FILENAME +// TSS_Test.cpp +// +// = DESCRIPTION +// This program tests various features of ACE_Thread and the +// thread-specific storage variant of <ACE_SingletonEx>. +// +// = AUTHOR +// Prashant Jain and Doug Schmidt +// +// ============================================================================ + +#include "ace/Atomic_Op.h" +#include "ace/Synch_Traits.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +class TSS_Obj + // = TITLE + // This object is stored in thread-specific storage. +{ +public: + TSS_Obj (void); + ~TSS_Obj (void); + +private: + + static ACE_Atomic_Op<ACE_SYNCH_MUTEX, int> count_; +}; + diff --git a/ACE/examples/Threads/TSS_Task.h b/ACE/examples/Threads/TSS_Task.h new file mode 100644 index 00000000000..0612f0c46a9 --- /dev/null +++ b/ACE/examples/Threads/TSS_Task.h @@ -0,0 +1,43 @@ +/* -*- C++ -*- */ + +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// tests +// +// = FILENAME +// TSS_Task.h +// +// = AUTHOR +// Prashant Jain and Doug Schmidt +// +// ============================================================================ + +#include "ace/config-all.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Token.h" +#include "ace/Atomic_Op.h" + +class Test_Task +{ +public: + + Test_Task (void); + ~Test_Task (void); + + int open (void *arg); + + static void *svc (void *arg); + + static ACE_Atomic_Op<ACE_Token, int> wait_count_; + static ACE_Atomic_Op<ACE_Token, int> max_count_; + +private: + static ACE_Atomic_Op<ACE_Token, int> count_; +}; diff --git a/ACE/examples/Threads/Threads.mpc b/ACE/examples/Threads/Threads.mpc new file mode 100644 index 00000000000..2c57feda243 --- /dev/null +++ b/ACE/examples/Threads/Threads.mpc @@ -0,0 +1,139 @@ +// -*- MPC -*- +// $Id$ + +project(*auto_event) : aceexe { + exename = auto_event + Source_Files { + auto_event.cpp + } +} +project(*barrier1) : aceexe { + exename = barrier1 + Source_Files { + barrier1.cpp + } +} +project(*barrier2) : aceexe { + exename = barrier2 + Source_Files { + barrier2.cpp + } +} +project(*cancel) : aceexe { + exename = cancel + Source_Files { + cancel.cpp + } +} +project(*future1) : aceexe { + avoids += ace_for_tao + exename = future1 + Source_Files { + future1.cpp + } +} +project(*future2) : aceexe { + avoids += ace_for_tao + exename = future2 + Source_Files { + future2.cpp + } +} +project(*manual_event) : aceexe { + exename = manual_event + Source_Files { + manual_event.cpp + } +} +project(*process_mutex) : aceexe { + avoids += ace_for_tao + exename = process_mutex + Source_Files { + process_mutex.cpp + } +} +project(*process_semaphore) : aceexe { + avoids += ace_for_tao + exename = process_semaphore + Source_Files { + process_semaphore.cpp + } +} +project(*reader_writer) : aceexe { + exename = reader_writer + Source_Files { + reader_writer.cpp + } +} +project(*recursive_mutex) : aceexe { + exename = recursive_mutex + Source_Files { + recursive_mutex.cpp + } +} +project(*task_five) : aceexe { + exename = task_five + Source_Files { + task_five.cpp + } +} +project(*task_four) : aceexe { + exename = task_four + Source_Files { + task_four.cpp + } +} +project(*task_three) : aceexe { + exename = task_three + Source_Files { + task_three.cpp + } +} +project(*task_two) : aceexe { + exename = task_two + Source_Files { + task_two.cpp + } +} +project(*task_one) : aceexe { + exename = task_one + Source_Files { + task_one.cpp + } +} +project(*thread_manager) : aceexe { + exename = thread_manager + Source_Files { + thread_manager.cpp + } +} +project(*thread_pool) : aceexe { + exename = thread_pool + Source_Files { + thread_pool.cpp + } +} +project(*thread_specific) : aceexe { + exename = thread_specific + Source_Files { + thread_specific.cpp + } +} +project(*token) : aceexe { + exename = token + Source_Files { + token.cpp + } +} +project(*tss1) : aceexe { + exename = tss1 + Source_Files { + tss1.cpp + } +} +project(*tss2) : aceexe { + exename = tss2 + Source_Files { + tss2.cpp + } +} diff --git a/ACE/examples/Threads/auto_event.cpp b/ACE/examples/Threads/auto_event.cpp new file mode 100644 index 00000000000..e568ffe84d1 --- /dev/null +++ b/ACE/examples/Threads/auto_event.cpp @@ -0,0 +1,120 @@ +// $Id$ + +// This test shows the use of an ACE_Auto_Event as a signaling +// mechanism. Two threads are created (one a reader, the other a +// writer). The reader waits till the writer has completed +// calculations. Upon waking up the reader prints the data calculated +// by the writer. The writer thread calculates the value and signals +// the reader when the calculation completes. + +#include "ace/OS_NS_unistd.h" +#include "ace/OS_main.h" +#include "ace/Service_Config.h" +#include "ace/Auto_Event.h" +#include "ace/Singleton.h" +#include "ace/Thread_Manager.h" + +ACE_RCSID(Threads, auto_event, "$Id$") + +#if defined (ACE_HAS_THREADS) +// Shared event between reader and writer. The ACE_Thread_Mutex is +// necessary to make sure that only one ACE_Auto_Event is created. +// The default constructor for ACE_Auto_Event sets it initially into +// the non-signaled state. + +typedef ACE_Singleton <ACE_Auto_Event, ACE_Thread_Mutex> EVENT; + +// work time for writer +static int work_time; + +// Reader thread. +static void * +reader (void *arg) +{ + // Shared data via a reference. + int& data = *(int *) arg; + + // Wait for writer to complete. + + ACE_DEBUG ((LM_DEBUG, "(%t) reader: waiting...... \n")); + + if (EVENT::instance ()->wait () == -1) + { + ACE_ERROR ((LM_ERROR, "thread wait failed")); + ACE_OS::exit (0); + } + + // Read shared data. + ACE_DEBUG ((LM_DEBUG, "(%t) reader: value of data is: %d \n", data)); + + return 0; +} + +// Writer thread. +static void * +writer (void *arg) +{ + int& data = *(int *) arg; + + // Calculate (work). + ACE_DEBUG ((LM_DEBUG, "(%t) writer: working for %d secs\n", work_time)); + ACE_OS::sleep (work_time); + + // Write shared data. + data = 42; + + // Wake up reader. + ACE_DEBUG ((LM_DEBUG, "(%t) writer: calculation complete, waking reader\n")); + + if (EVENT::instance ()->signal () == -1) + { + ACE_ERROR ((LM_ERROR, "thread signal failed")); + ACE_OS::exit (0); + } + + return 0; +} + +int +ACE_TMAIN (int argc, ACE_TCHAR **argv) +{ + // Shared data: set by writer, read by reader. + int data; + + // Work time for writer. + work_time = argc == 2 ? ACE_OS::atoi (argv[1]) : 5; + + // threads manager + ACE_Thread_Manager& tm = *ACE_Thread_Manager::instance (); + + // Create reader thread. + if (tm.spawn ((ACE_THR_FUNC) reader, (void *) &data) == -1) + ACE_ERROR_RETURN ((LM_ERROR, "thread create for reader failed"), -1); + + // Create writer thread. + if (tm.spawn ((ACE_THR_FUNC) writer, (void *) &data) == -1) + ACE_ERROR_RETURN ((LM_ERROR, "thread create for writer failed"), -1); + + // Wait for both. + if (tm.wait () == -1) + ACE_ERROR_RETURN ((LM_ERROR, "thread wait failed"), -1); + else + ACE_DEBUG ((LM_ERROR, "graceful exit\n")); + + return 0; +} + +#if defined (ACE_HAS_EXPLICIT_STATIC_TEMPLATE_MEMBER_INSTANTIATION) +template ACE_Singleton<ACE_Auto_Event, ACE_Thread_Mutex> * + ACE_Singleton<ACE_Auto_Event, ACE_Thread_Mutex>::singleton_; +#endif /* ACE_HAS_EXPLICIT_STATIC_TEMPLATE_MEMBER_INSTANTIATION */ + + +#else +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_ERROR ((LM_ERROR, "threads not supported on this platform\n")); + return 0; +} +#endif /* ACE_HAS_THREADS */ diff --git a/ACE/examples/Threads/barrier1.cpp b/ACE/examples/Threads/barrier1.cpp new file mode 100644 index 00000000000..4d3762b1eb6 --- /dev/null +++ b/ACE/examples/Threads/barrier1.cpp @@ -0,0 +1,83 @@ +// $Id$ + +// This test program illustrates how the ACE barrier synchronization +// mechanisms work. + +#include "ace/OS_main.h" +#include "ace/Barrier.h" +#include "ace/Thread_Manager.h" +#include "ace/Service_Config.h" + +ACE_RCSID(Threads, barrier1, "$Id$") + +#if defined (ACE_HAS_THREADS) + +struct Tester_Args + // = TITLE + // These arguments are passed into each test thread. +{ + Tester_Args (ACE_Barrier &tb, int i) + : tester_barrier_ (tb), + n_iterations_ (i) {} + + ACE_Barrier &tester_barrier_; + // Reference to the tester barrier. This controls each miteration of + // the tester function running in every thread. + + int n_iterations_; + // Number of iterations to run. +}; + +// Iterate <n_iterations> time printing off a message and "waiting" +// for all other threads to complete this iteration. + +static void * +tester (Tester_Args *args) +{ + for (int iterations = 1; + iterations <= args->n_iterations_; + iterations++) + { + ACE_DEBUG ((LM_DEBUG, "(%t) in iteration %d\n", iterations)); + + // Block until all other threads have waited, then continue. + args->tester_barrier_.wait (); + } + + return 0; +} + +// Default number of threads to spawn. +static const int DEFAULT_ITERATIONS = 5; + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + ACE_Service_Config daemon (argv[0]); + + int n_threads = argc > 1 ? ACE_OS::atoi (argv[1]) : ACE_DEFAULT_THREADS; + int n_iterations = argc > 2 ? ACE_OS::atoi (argv[2]) : DEFAULT_ITERATIONS; + + ACE_Barrier tester_barrier (n_threads); + + Tester_Args args (tester_barrier, n_iterations); + + if (ACE_Thread_Manager::instance ()->spawn_n + (int(n_threads), ACE_THR_FUNC (tester), + (void *) &args, THR_NEW_LWP | THR_DETACHED) == -1) + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "spawn_n"), 1); + + // Wait for all the threads to reach their exit point. + ACE_Thread_Manager::instance ()->wait (); + + ACE_DEBUG ((LM_DEBUG, "(%t) done\n")); + return 0; +} +#else +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_ERROR ((LM_ERROR, "threads not supported on this platform\n")); + return 0; +} +#endif /* ACE_HAS_THREADS */ diff --git a/ACE/examples/Threads/barrier2.cpp b/ACE/examples/Threads/barrier2.cpp new file mode 100644 index 00000000000..cd322b82856 --- /dev/null +++ b/ACE/examples/Threads/barrier2.cpp @@ -0,0 +1,316 @@ +// $Id$ + +// This test program illustrates how the ACE task workers/barrier +// synchronization mechanisms work in conjunction with the ACE_Task +// and the ACE_Thread_Manager. The manual flag not set simulates user +// input, if set input comes from stdin until RETURN only is entered +// which stops all workers via a message block of length 0. This is an +// alernative shutdown of workers compared to queue deactivate. The +// delay_put flag simulates a delay between the shutdown puts. All +// should work with this flag disabled! The BARRIER_TYPE is supposed +// to enable/disable barrier sync on each svc a worker has done. + +#include "ace/OS_NS_string.h" +#include "ace/OS_NS_unistd.h" +#include "ace/OS_main.h" +#include "ace/Task.h" +#include "ace/Service_Config.h" + +ACE_RCSID(Threads, barrier2, "$Id$") + +#if defined (ACE_HAS_THREADS) + +#include "ace/Null_Barrier.h" +#define BARRIER_TYPE ACE_Null_Barrier + +template <class BARRIER> +class Worker_Task : public ACE_Task<ACE_MT_SYNCH> +{ +public: + Worker_Task (ACE_Thread_Manager *thr_mgr, + int n_threads, + int inp_serialize = 1); + + virtual int producer (void); + // produce input for workers + + virtual int input (ACE_Message_Block *mb); + // Fill one message block via a certain input strategy. + + virtual int output (ACE_Message_Block *mb); + // Forward one message block via a certain output strategy to the + // next task if any. + + virtual int service (ACE_Message_Block *mb, int iter); + // Perform one message block dependant service. + +private: + virtual int put (ACE_Message_Block *mb, ACE_Time_Value *tv=0); + + virtual int svc (void); + // Iterate <n_iterations> time printing off a message and "waiting" + // for all other threads to complete this iteration. + + // = Not needed for this test. + virtual int open (void *) { return 0; } + virtual int close (u_long) + { + ACE_DEBUG ((LM_DEBUG, + "(%t) in close of worker\n")); + return 0; + } + + int nt_; + // Number of worker threads to run. + + int inp_serialize_; + + BARRIER barrier_; +}; + +template <class BARRIER> +Worker_Task<BARRIER>::Worker_Task (ACE_Thread_Manager *thr_mgr, + int n_threads, + int inp_serialize) + : ACE_Task<ACE_MT_SYNCH> (thr_mgr), + barrier_ (n_threads) +{ + nt_ = n_threads; + + // Create worker threads. + inp_serialize_ = inp_serialize; + + // Use the task's message queue for serialization (default) or run + // service in the context of the caller thread. + + if (nt_ > 0 && inp_serialize == 1) + if (this->activate (THR_NEW_LWP, n_threads) == -1) + ACE_ERROR ((LM_ERROR, + "%p\n", + "activate failed")); +} + +// Simply enqueue the Message_Block into the end of the queue. + +template <class BARRIER> int +Worker_Task<BARRIER>::put (ACE_Message_Block *mb, + ACE_Time_Value *tv) +{ + int result; + + if (this->inp_serialize_) + result = this->putq (mb, tv); + else + { + static int iter = 0; + result = this->service (mb, iter++); + + if (this->output (mb) < 0) + ACE_DEBUG ((LM_DEBUG, + "(%t) output not connected!\n")); + + mb->release (); + } + return result; +} + +template <class BARRIER> int +Worker_Task<BARRIER>::service (ACE_Message_Block *mb, + int iter) +{ + size_t length = mb->length (); + + if (length > 0) + { + ACE_DEBUG ((LM_DEBUG, + "(%t) in iteration %d len=%d text got:\n", + iter, + length)); + ACE_OS::write (ACE_STDOUT, + mb->rd_ptr (), + length); + ACE_DEBUG ((LM_DEBUG, + "\n")); + } + return 0; +} + +// Iterate <n_iterations> time printing off a message and "waiting" +// for all other threads to complete this iteration. + +template <class BARRIER> int +Worker_Task<BARRIER>::svc (void) +{ + // Note that the <ACE_Task::svc_run> method automatically adds us to + // the Thread_Manager when the thread begins. + + // Keep looping, reading a message out of the queue, until we get a + // message with a length == 0, which signals us to quit. + + for (int iter = 1; ;iter++) + { + ACE_Message_Block *mb = 0; + + int result = this->getq (mb); + + if (result == -1) + { + ACE_ERROR ((LM_ERROR, + "(%t) in iteration %d\n", + "error waiting for message in iteration", + iter)); + break; + } + + size_t length = mb->length (); + this->service (mb,iter); + + if (length == 0) + { + ACE_DEBUG ((LM_DEBUG, + "(%t) in iteration %d got quit, exit!\n", + iter)); + mb->release (); + break; + } + + this->barrier_.wait (); + this->output (mb); + + mb->release (); + } + + // Note that the <ACE_Task::svc_run> method automatically removes us + // from the Thread_Manager when the thread exits. + + return 0; +} + +template <class BARRIER> int +Worker_Task<BARRIER>::producer (void) +{ + // Keep reading stdin, until we reach EOF. + + for (;;) + { + // Allocate a new message. + ACE_Message_Block *mb; + + ACE_NEW_RETURN (mb, + ACE_Message_Block (BUFSIZ), + -1); + + if (this->input (mb) == -1) + return -1; + } + + ACE_NOTREACHED (return 0); +} + +template <class BARRIER> int +Worker_Task<BARRIER>::output (ACE_Message_Block *mb) +{ + return this->put_next (mb); +} + +template <class BARRIER> int +Worker_Task<BARRIER>::input (ACE_Message_Block *mb) +{ + ACE_Message_Block *mb1; + +#if !defined (manual) + static int l = 0; + char str[] = "kalle"; + ACE_OS::strcpy (mb->rd_ptr (), str); + + size_t n = ACE_OS::strlen (str); + + if (l == 1000) + n = 1; + l++; + + if (l == 0 || (l % 100 == 0)) + ACE_OS::sleep (5); + if (n <= 1) +#else + ACE_DEBUG ((LM_DEBUG, + "(%t) press chars and enter to put a new message into task queue ...\n")); + n = ACE_OS::read (ACE_STDIN, + mb->rd_ptr (), + mb->size ()); + if (n <= 1) +#endif /* manual */ + { + // Send a shutdown message to the waiting threads and exit. + // cout << "\nvor loop, dump of task msg queue:\n" << endl; + // this->msg_queue ()->dump (); + + for (int i = 0; i < nt_; i++) + { + ACE_DEBUG ((LM_DEBUG, + "(%t) eof, sending block for thread=%d\n", + i + 1)); + + ACE_NEW_RETURN (mb1, + ACE_Message_Block (2), + -1); + mb1->length (0); + + if (this->put (mb1) == -1) + ACE_ERROR ((LM_ERROR, + "(%t) %p\n", + "put")); +#if defined (delay_put) + // this sleep helps to shutdown correctly -> was an error! + ACE_OS::sleep (1); +#endif /* delay_put */ + } + return -1; + } + else + { + // Send a normal message to the waiting threads and continue + // producing. + mb->wr_ptr (n); + + if (this->put (mb) == -1) + ACE_ERROR ((LM_ERROR, + "(%t) %p\n", + "put")); + } + return 0; +} + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + int n_threads = argc > 1 ? ACE_OS::atoi (argv[1]) : ACE_DEFAULT_THREADS; + + ACE_DEBUG ((LM_DEBUG, + "(%t) worker threads running=%d\n", + n_threads)); + + Worker_Task<BARRIER_TYPE> worker_task (ACE_Thread_Manager::instance (), + /* n_threads */ 0, + 0); + worker_task.producer (); + + // Wait for all the threads to reach their exit point. + ACE_DEBUG ((LM_DEBUG, + "(%t) waiting with thread manager ...\n")); + + ACE_Thread_Manager::instance ()->wait (); + + ACE_DEBUG ((LM_DEBUG, + "(%t) done correct!\n")); + return 0; +} + +#else +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_ERROR ((LM_ERROR, "threads not supported on this platform\n")); + return 0; +} +#endif /* ACE_HAS_THREADS */ diff --git a/ACE/examples/Threads/cancel.cpp b/ACE/examples/Threads/cancel.cpp new file mode 100644 index 00000000000..f10bb822580 --- /dev/null +++ b/ACE/examples/Threads/cancel.cpp @@ -0,0 +1,86 @@ +// $Id$ + +// Test out the cooperative thread cancellation mechanisms provided by +// the ACE_Thread_Manager. + +#include "ace/OS_NS_unistd.h" +#include "ace/OS_main.h" +#include "ace/Service_Config.h" +#include "ace/Thread_Manager.h" + +ACE_RCSID(Threads, cancel, "$Id$") + +#if defined (ACE_HAS_THREADS) + +static void * +#if ACE_SIZEOF_VOID_P==8 && ACE_SIZEOF_INT<ACE_SIZEOF_VOID_P +worker (long iterations) +{ + for (long i = 0; i < iterations; i++) +#else +worker (int iterations) +{ + for (int i = 0; i < iterations; i++) +#endif + { + if ((i % 10) == 0 + && (ACE_Thread_Manager::instance ()->testcancel (ACE_Thread::self ()) != 0)) + { + ACE_DEBUG ((LM_DEBUG, "(%t) has been cancelled before iteration!\n", i)); + break; + } + } + + return 0; +} + +static const int DEFAULT_THREADS = ACE_DEFAULT_THREADS; +static const int DEFAULT_ITERATIONS = 100000; + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + ACE_Service_Config daemon; + + daemon.open (argv[0]); + + int n_threads = argc > 1 ? ACE_OS::atoi (argv[1]) : DEFAULT_THREADS; +#if ACE_SIZEOF_VOID_P==8 && ACE_SIZEOF_INT<ACE_SIZEOF_VOID_P + long n_iterations = (long)( argc > 2 ? ACE_OS::atoi (argv[2]) : DEFAULT_ITERATIONS ); +#else + int n_iterations = argc > 2 ? ACE_OS::atoi (argv[2]) : DEFAULT_ITERATIONS; +#endif + + ACE_Thread_Manager *thr_mgr = ACE_Thread_Manager::instance (); + + int grp_id = thr_mgr->spawn_n (n_threads, ACE_THR_FUNC (worker), + (void *) n_iterations, + THR_NEW_LWP | THR_DETACHED); + + // Wait for 2 seconds and then suspend every thread in the group. + ACE_OS::sleep (2); + thr_mgr->suspend_grp (grp_id); + + // Wait for 2 more seconds and then resume every thread in the + // group. + ACE_OS::sleep (ACE_Time_Value (2)); + thr_mgr->resume_grp (grp_id); + + // Wait for 2 more seconds and then send a SIGINT to every thread in + // the group. + ACE_OS::sleep (ACE_Time_Value (2)); + thr_mgr->kill_grp (grp_id, SIGINT); + + // Wait for 2 more seconds and then exit (which should kill all the + // threads)! + ACE_OS::sleep (ACE_Time_Value (2)); + + return 0; +} +#else +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_ERROR_RETURN ((LM_ERROR, "threads not supported on this platform\n"), -1); +} +#endif /* ACE_HAS_THREADS */ diff --git a/ACE/examples/Threads/future1.cpp b/ACE/examples/Threads/future1.cpp new file mode 100644 index 00000000000..7b95e549431 --- /dev/null +++ b/ACE/examples/Threads/future1.cpp @@ -0,0 +1,404 @@ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// tests +// +// = FILENAME +// Test_Future.cpp +// +// = DESCRIPTION +// This example tests the ACE Future. +// +// = AUTHOR +// Andres Kruse <Andres.Kruse@cern.ch> and Douglas C. Schmidt +// <schmidt@cs.wustl.edu> +// +// ============================================================================ + +#include "ace/OS_NS_string.h" +#include "ace/OS_NS_unistd.h" +#include "ace/OS_main.h" +#include "ace/ACE.h" +#include "ace/Task.h" +#include "ace/Thread_Mutex.h" +#include "ace/Message_Queue.h" +#include "ace/Future.h" +#include "ace/Method_Request.h" +#include "ace/Activation_Queue.h" +#include "ace/Auto_Ptr.h" +#include "ace/Atomic_Op.h" + +ACE_RCSID(Threads, future1, "$Id$") + +#if defined (ACE_HAS_THREADS) + +typedef ACE_Atomic_Op<ACE_Thread_Mutex, int> ATOMIC_INT; + +// a counter for the tasks.. +static ATOMIC_INT task_count (0); + +// a counter for the futures.. +static ATOMIC_INT future_count (0); +static ATOMIC_INT future_no (0); + +// a counter for the capsules.. +static ATOMIC_INT capsule_count (0); +static ATOMIC_INT capsule_no (0); + +// a counter for the method objects... +static ATOMIC_INT methodobject_count (0); +static ATOMIC_INT methodobject_no (0); + +class Scheduler : public ACE_Task_Base + // = TITLE + // Active Object Scheduler. +{ + friend class Method_RequestWork; +public: + Scheduler (const char *, Scheduler * = 0); + virtual ~Scheduler (void); + + virtual int open (void *args = 0); + virtual int close (u_long flags = 0); + virtual int svc (void); + + ACE_Future<u_long> work (u_long param, int count = 1); + ACE_Future<const char*> name (void); + void end (void); + + u_long work_i (u_long, int); + const char *name_i (void); + +private: + char *name_; + ACE_Activation_Queue activation_queue_; + Scheduler *scheduler_; +}; + +class Method_Request_work : public ACE_Method_Request + // = TITLE + // Reification of the <work> method. +{ +public: + Method_Request_work (Scheduler *, u_long, int, ACE_Future<u_long> &); + virtual ~Method_Request_work (void); + virtual int call (void); + +private: + Scheduler *scheduler_; + u_long param_; + int count_; + ACE_Future<u_long> future_result_; +}; + +Method_Request_work::Method_Request_work (Scheduler* new_Scheduler, + u_long new_param, + int new_count, + ACE_Future<u_long> &new_result) + : scheduler_ (new_Scheduler), + param_ (new_param), + count_ (new_count), + future_result_ (new_result) +{ + ACE_DEBUG ((LM_DEBUG, + "(%t) Method_Request_work created\n")); +} + +Method_Request_work::~Method_Request_work (void) +{ + ACE_DEBUG ((LM_DEBUG, "(%t) Method_Request_work will be deleted.\n")); +} + + +int +Method_Request_work::call (void) +{ + return this->future_result_.set (this->scheduler_->work_i (this->param_, this->count_)); +} + +class Method_Request_name : public ACE_Method_Request + // = TITLE + // Reification of the <name> method. +{ +public: + Method_Request_name (Scheduler *, ACE_Future<const char*> &); + virtual ~Method_Request_name (void); + virtual int call (void); + +private: + Scheduler *scheduler_; + ACE_Future<const char *> future_result_; +}; + +Method_Request_name::Method_Request_name (Scheduler *new_scheduler, + ACE_Future<const char *> &new_result) + : scheduler_ (new_scheduler), + future_result_ (new_result) +{ + ACE_DEBUG ((LM_DEBUG, + "(%t) Method_Request_name created\n")); +} + +Method_Request_name::~Method_Request_name (void) +{ + ACE_DEBUG ((LM_DEBUG, + "(%t) Method_Request_name will be deleted.\n")); +} + +int +Method_Request_name::call (void) +{ + return future_result_.set (scheduler_->name_i ()); +} + +class Method_Request_end : public ACE_Method_Request + // = TITLE + // Reification of the <end> method. +{ +public: + Method_Request_end (Scheduler *new_scheduler): scheduler_ (new_scheduler) {} + virtual ~Method_Request_end (void) {} + virtual int call (void) { return -1; } + +private: + Scheduler *scheduler_; + // Keep track of our scheduler. +}; + +// Constructor. +Scheduler::Scheduler (const char *newname, + Scheduler *new_scheduler) +{ + ACE_NEW (this->name_, char[ACE_OS::strlen (newname) + 1]); + ACE_OS::strcpy (this->name_, newname); + this->scheduler_ = new_scheduler; + ACE_DEBUG ((LM_DEBUG, "(%t) Scheduler %s created\n", this->name_)); +} + +// Destructor +Scheduler::~Scheduler (void) +{ + ACE_DEBUG ((LM_DEBUG, "(%t) Scheduler %s will be destroyed\n", this->name_)); + delete [] this->name_; +} + +// open +int +Scheduler::open (void *) +{ + task_count++; + ACE_DEBUG ((LM_DEBUG, "(%t) Scheduler %s open\n", this->name_)); + return this->activate (THR_BOUND); +} + +// close +int +Scheduler::close (u_long) +{ + ACE_DEBUG ((LM_DEBUG, "(%t) Scheduler %s close\n", this->name_)); + task_count--; + return 0; +} + +// service.. +int +Scheduler::svc (void) +{ + for (;;) + { + // Dequeue the next method object (we use an auto pointer in + // case an exception is thrown in the <call>). + auto_ptr<ACE_Method_Request> mo (this->activation_queue_.dequeue ()); + + ACE_DEBUG ((LM_DEBUG, "(%t) calling method object\n")); + // Call it. + if (mo->call () == -1) + break; + // Destructor automatically deletes it. + } + + /* NOTREACHED */ + return 0; +} + +void +Scheduler::end (void) +{ + this->activation_queue_.enqueue (new Method_Request_end (this)); +} + + +// Here's where the Work takes place. +u_long +Scheduler::work_i (u_long param, + int count) +{ + ACE_UNUSED_ARG (count); + + return ACE::is_prime (param, 2, param / 2); +} + +const char * +Scheduler::name_i (void) +{ + char *the_name; + + ACE_NEW_RETURN (the_name, char[ACE_OS::strlen (this->name_) + 1], 0); + ACE_OS::strcpy (the_name, this->name_); + + return the_name; +} + +ACE_Future<const char *> +Scheduler::name (void) +{ + if (this->scheduler_) + // Delegate to the Scheduler. + return this->scheduler_->name (); + else + { + ACE_Future<const char*> new_future; + + // @@ What happens if new fails here? + this->activation_queue_.enqueue + (new Method_Request_name (this, new_future)); + + return new_future; + } +} + +ACE_Future<u_long> +Scheduler::work (u_long newparam, + int newcount) +{ + if (this->scheduler_) { + return this->scheduler_->work (newparam, newcount); + } + else { + ACE_Future<u_long> new_future; + + this->activation_queue_.enqueue + (new Method_Request_work (this, newparam, newcount, new_future)); + return new_future; + } +} + +// @@ These values should be set by the command line options! + +// Total number of loops. +static size_t n_loops = 100; + +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + Scheduler *andres, *peter, *helmut, *matias; + + // Create active objects.. + // @@ Should "open" be subsumed within the constructor of + // Scheduler()? + ACE_NEW_RETURN (andres, Scheduler ("andres"), -1); + andres->open (); + ACE_NEW_RETURN (peter, Scheduler ("peter"), -1); + peter->open (); + ACE_NEW_RETURN (helmut, Scheduler ("helmut"), -1); + helmut->open (); + + // Matias passes all asynchronous method calls on to Andres... + ACE_NEW_RETURN (matias, Scheduler ("matias", andres), -1); + matias->open (); + + for (size_t i = 0; i < n_loops; i++) + { + { + ACE_Future<u_long> fresulta, fresultb, fresultc, fresultd, fresulte; + ACE_Future<const char *> fname; + + ACE_DEBUG ((LM_DEBUG, "(%t) going to do a non-blocking call\n")); + + fresulta = andres->work (9013); + fresultb = peter->work (9013); + fresultc = helmut->work (9013); + fresultd = matias->work (9013); + fname = andres->name (); + + // see if the result is available... + if (fresulta.ready ()) + ACE_DEBUG ((LM_DEBUG, "(%t) wow.. work is ready.....\n")); + + ACE_DEBUG ((LM_DEBUG, "(%t) non-blocking call done... now blocking...\n")); + + // Save the result of fresulta. + + fresulte = fresulta; + + if (i % 3 == 0) + { + // Every 3rd time... disconnect the futures... + // but "fresulte" should still contain the result... + fresulta.cancel (10); + fresultb.cancel (20); + fresultc.cancel (30); + fresultd.cancel (40); + } + + u_long resulta = 0, resultb = 0, resultc = 0, resultd = 0, resulte = 0; + + fresulta.get (resulta); + fresultb.get (resultb); + fresultc.get (resultc); + fresultd.get (resultd); + fresulte.get (resulte); + + ACE_DEBUG ((LM_DEBUG, "(%t) result a %u\n", (u_int) resulte)); + ACE_DEBUG ((LM_DEBUG, "(%t) result b %u\n", (u_int) resulta)); + ACE_DEBUG ((LM_DEBUG, "(%t) result c %u\n", (u_int) resultb)); + ACE_DEBUG ((LM_DEBUG, "(%t) result d %u\n", (u_int) resultc)); + ACE_DEBUG ((LM_DEBUG, "(%t) result e %u\n", (u_int) resultd)); + + const char *name = 0; + + fname.get (name); + + ACE_DEBUG ((LM_DEBUG, "(%t) name %s\n", name)); + delete [] (char *) name; + } + + ACE_DEBUG ((LM_DEBUG, + "(%t) task_count %d future_count %d capsule_count %d methodobject_count %d\n", + task_count.value (), + future_count.value (), + capsule_count.value (), + methodobject_count.value ())); + } + + // Close things down. + andres->end (); + peter->end (); + helmut->end (); + matias->end (); + + ACE_OS::sleep (2); + + ACE_DEBUG ((LM_DEBUG, + "(%t) task_count %d future_count %d capsule_count %d methodobject_count %d\n", + task_count.value (), + future_count.value (), + capsule_count.value (), + methodobject_count.value ())); + + ACE_DEBUG ((LM_DEBUG,"(%t) th' that's all folks!\n")); + + ACE_OS::sleep (5); + return 0; +} + +#else +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_ERROR ((LM_ERROR, "threads not supported on this platform\n")); + return 0; +} +#endif /* ACE_HAS_THREADS */ diff --git a/ACE/examples/Threads/future2.cpp b/ACE/examples/Threads/future2.cpp new file mode 100644 index 00000000000..4bb9519ca28 --- /dev/null +++ b/ACE/examples/Threads/future2.cpp @@ -0,0 +1,525 @@ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// tests +// +// = FILENAME +// Test_Future.cpp +// +// = DESCRIPTION +// This example tests the ACE Future. +// +// = AUTHOR +// Andres Kruse <Andres.Kruse@cern.ch> and Douglas C. Schmidt +// <schmidt@cs.wustl.edu> +// +// Modification History +// Aug. 96; A.Kruse; dev. +// Aug. 96; D.Schmidt; complete workover +// 08/27/96; A.Kruse; - the friends of Scheduler are "Method_Request_name" +// and "Method_Request_work". +// - make the methods "work_i" and "name_i" private +// 09/2/96; D.Schmidt; Integrate with new ACE_Future API and rearrange +// the tests so they are more modular. +// ============================================================================ + +#include "ace/OS_NS_string.h" +#include "ace/OS_NS_sys_time.h" +#include "ace/OS_NS_unistd.h" +#include "ace/OS_main.h" +#include "ace/ACE.h" +#include "ace/Task.h" +#include "ace/Message_Queue.h" +#include "ace/Future.h" +#include "ace/Method_Request.h" +#include "ace/Activation_Queue.h" +#include "ace/Auto_Ptr.h" +#include "ace/Atomic_Op.h" + +ACE_RCSID(Threads, future2, "$Id$") +#if defined (ACE_HAS_THREADS) + +typedef ACE_Atomic_Op<ACE_Thread_Mutex, int> ATOMIC_INT; + +// a counter for the tasks.. +static ATOMIC_INT scheduler_open_count (0); + +// forward declarations +class Method_Request_work; +class Method_Request_name; + +class Scheduler : public ACE_Task_Base + // = TITLE + // Active Object Scheduler. +{ + // Every method object has to be able to access the private methods. + + friend class Method_Request_work; + friend class Method_Request_name; + friend class Method_Request_end; +public: + + Scheduler (const char *, Scheduler * = 0); + virtual ~Scheduler (void); + + virtual int open (void *args = 0); + // The method that is used to start the active object. + + // = Here are the methods exported by the class. They return an + // <ACE_Future>. + ACE_Future<u_long> work (u_long param, int count = 1); + ACE_Future<char*> name (void); + void end (void); + +private: + virtual int close (u_long flags = 0); + // Should not be accessible from outside... (use end () instead). + + virtual int svc (void); + // Here the actual servicing of all requests is happening.. + + // = Implementation methods. + u_long work_i (u_long, int); + char *name_i (void); + + char *name_; + ACE_Activation_Queue activation_queue_; + Scheduler *scheduler_; +}; + +class Method_Request_work : public ACE_Method_Request + // = TITLE + // Reification of the <work> method. +{ +public: + Method_Request_work (Scheduler *, u_long, int, ACE_Future<u_long> &); + virtual ~Method_Request_work (void); + virtual int call (void); + +private: + Scheduler *scheduler_; + u_long param_; + int count_; + ACE_Future<u_long> future_result_; +}; + +Method_Request_work::Method_Request_work (Scheduler* new_Scheduler, + u_long new_param, + int new_count, + ACE_Future<u_long> &new_result) + : scheduler_ (new_Scheduler), + param_ (new_param), + count_ (new_count), + future_result_ (new_result) +{ +} + +Method_Request_work::~Method_Request_work (void) +{ +} + +int +Method_Request_work::call (void) +{ + return this->future_result_.set (this->scheduler_->work_i (this->param_, this->count_)); +} + +class Method_Request_name : public ACE_Method_Request + // = TITLE + // Reification of the <name> method. +{ +public: + Method_Request_name (Scheduler *, ACE_Future<char*> &); + virtual ~Method_Request_name (void); + virtual int call (void); + +private: + Scheduler *scheduler_; + ACE_Future<char*> future_result_; +}; + + +Method_Request_name::Method_Request_name (Scheduler *new_scheduler, + ACE_Future<char*> &new_result) + : scheduler_ (new_scheduler), + future_result_ (new_result) +{ + ACE_DEBUG ((LM_DEBUG, + " (%t) Method_Request_name created\n")); +} + +Method_Request_name::~Method_Request_name (void) +{ + ACE_DEBUG ((LM_DEBUG, + " (%t) Method_Request_name will be deleted.\n")); +} + +int +Method_Request_name::call (void) +{ + return future_result_.set (scheduler_->name_i ()); +} + +class Method_Request_end : public ACE_Method_Request + // = TITLE + // Reification of the <end> method. +{ +public: + Method_Request_end (Scheduler *new_Scheduler): scheduler_ (new_Scheduler) {} + virtual ~Method_Request_end (void) {} + virtual int call (void) { return -1; } + +private: + Scheduler *scheduler_; + // Keep track of our scheduler. +}; + +// constructor +Scheduler::Scheduler (const char *newname, Scheduler *new_Scheduler) +{ + ACE_NEW (this->name_, char[ACE_OS::strlen (newname) + 1]); + ACE_OS::strcpy ((char *) this->name_, newname); + this->scheduler_ = new_Scheduler; + ACE_DEBUG ((LM_DEBUG, " (%t) Scheduler %s created\n", this->name_)); +} + +// Destructor +Scheduler::~Scheduler (void) +{ + ACE_DEBUG ((LM_DEBUG, " (%t) Scheduler %s will be destroyed\n", this->name_)); +} + +int +Scheduler::open (void *) +{ + scheduler_open_count++; + ACE_DEBUG ((LM_DEBUG, " (%t) Scheduler %s open\n", this->name_)); + return this->activate (THR_BOUND); +} + +int +Scheduler::close (u_long) +{ + ACE_DEBUG ((LM_DEBUG, " (%t) Scheduler %s close\n", this->name_)); + scheduler_open_count--; + return 0; +} + +int +Scheduler::svc (void) +{ + // Main event loop for this active object. + for (;;) + { + // Dequeue the next method object (we use an auto pointer in + // case an exception is thrown in the <call>). + auto_ptr<ACE_Method_Request> mo (this->activation_queue_.dequeue ()); + + ACE_DEBUG ((LM_DEBUG, " (%t) calling method object\n")); + // Call it. + if (mo->call () == -1) + break; + // Smart pointer destructor automatically deletes mo. + } + + /* NOTREACHED */ + return 0; +} + +void +Scheduler::end (void) +{ + this->activation_queue_.enqueue (new Method_Request_end (this)); +} + +// Here's where the Work takes place. +u_long +Scheduler::work_i (u_long param, + int count) +{ + ACE_UNUSED_ARG (count); + + return ACE::is_prime (param, 2, param / 2); +} + +char * +Scheduler::name_i (void) +{ + char *the_name; + + ACE_NEW_RETURN (the_name, char[ACE_OS::strlen (this->name_) + 1], 0); + ACE_OS::strcpy (the_name, this->name_); + + return the_name; +} + +ACE_Future<char *> +Scheduler::name (void) +{ + if (this->scheduler_) + // Delegate to the other scheduler + return this->scheduler_->name (); + else + { + ACE_Future<char*> new_future; + + if (this->thr_count () == 0) + { + // This scheduler is inactive... so we execute the user + // request right away... + + auto_ptr<ACE_Method_Request> mo (new Method_Request_name (this, new_future)); + + mo->call (); + // Smart pointer destructor automatically deletes mo. + } + else + // @@ What happens if new fails here? + this->activation_queue_.enqueue + (new Method_Request_name (this, new_future)); + + return new_future; + } +} + +ACE_Future<u_long> +Scheduler::work (u_long newparam, int newcount) +{ + if (this->scheduler_) + return this->scheduler_->work (newparam, newcount); + else + { + ACE_Future<u_long> new_future; + + if (this->thr_count () == 0) + { + auto_ptr<ACE_Method_Request> mo + (new Method_Request_work (this, newparam, newcount, new_future)); + mo->call (); + // Smart pointer destructor automatically deletes it. + } + else + this->activation_queue_.enqueue + (new Method_Request_work (this, newparam, newcount, new_future)); + + return new_future; + } +} + +static int +determine_iterations (void) +{ + int n_iterations; + + ACE_DEBUG ((LM_DEBUG," (%t) determining the number of iterations...\n")); + Scheduler *worker_a; + + ACE_NEW_RETURN (worker_a, Scheduler ("worker A"), -1); + + ACE_Time_Value tstart (ACE_OS::gettimeofday ()); + ACE_Time_Value tend (ACE_OS::gettimeofday ()); + + // Determine the number of iterations... we want so many that the + // work () takes about 1 second... + + for (n_iterations = 1; + (tend.sec () - tstart.sec ()) < 1; + n_iterations *= 2) + { + tstart = ACE_OS::gettimeofday (); + + worker_a->work (9013, n_iterations); + + tend = ACE_OS::gettimeofday (); + } + + ACE_DEBUG ((LM_DEBUG," (%t) n_iterations %d\n", + (int) n_iterations)); + + worker_a->end (); + // @@ Can we safely delete worker_a here? + return n_iterations; +} + +static void +test_active_object (int n_iterations) +{ + ACE_UNUSED_ARG (n_iterations); + + ACE_DEBUG ((LM_DEBUG," (%t) testing active object pattern...\n")); + // A simple example for the use of the active object pattern and + // futures to return values from an active object. + + Scheduler *worker_a; + Scheduler *worker_b; + Scheduler *worker_c; + + ACE_NEW (worker_a, Scheduler ("worker A")); + ACE_NEW (worker_b, Scheduler ("worker B")); + // Have worker_c delegate his work to worker_a. + ACE_NEW (worker_c, Scheduler ("worker C", worker_a)); + + // loop 0: + // test the Schedulers when they are not active. + // now the method objects will be created but since + // there is no active thread they will also be + // immediately executed, in the "main" thread. + // loop 1: + // do the same test but with the schedulers + // activated + for (int i = 0; i < 2; i++) + { + if (i == 1) + { + worker_a->open (); + worker_b->open (); + worker_c->open (); + } + + ACE_Future<u_long> fresulta = worker_a->work (9013); + ACE_Future<u_long> fresultb = worker_b->work (9013); + ACE_Future<u_long> fresultc = worker_c->work (9013); + + if (i == 0) + { + if (!fresulta.ready ()) + ACE_DEBUG ((LM_DEBUG," (%t) ERROR: worker A is should be ready!!!\n")); + if (!fresultb.ready ()) + ACE_DEBUG ((LM_DEBUG," (%t) ERROR: worker B is should be ready!!!\n")); + if (!fresultc.ready ()) + ACE_DEBUG ((LM_DEBUG," (%t) ERROR: worker C is should be ready!!!\n")); + } + + // When the workers are active we will block here until the + // results are available. + + u_long resulta = fresulta; + u_long resultb = fresultb; + u_long resultc = fresultc; + + ACE_Future<char *> fnamea = worker_a->name (); + ACE_Future<char *> fnameb = worker_b->name (); + ACE_Future<char *> fnamec = worker_c->name (); + + char *namea = fnamea; + char *nameb = fnameb; + char *namec = fnamec; + + ACE_DEBUG ((LM_DEBUG, " (%t) result from %s %u\n", + namea, (u_int) resulta)); + ACE_DEBUG ((LM_DEBUG, " (%t) result from %s %u\n", + nameb, (u_int) resultb)); + ACE_DEBUG ((LM_DEBUG, " (%t) result from %s %u\n", + namec, (u_int) resultc)); + } + + ACE_DEBUG ((LM_DEBUG, " (%t) scheduler_open_count %d before end ()\n", + scheduler_open_count.value ())); + + worker_a->end (); + worker_b->end (); + worker_c->end (); + + ACE_DEBUG ((LM_DEBUG, " (%t) scheduler_open_count %d immediately after end ()\n", + scheduler_open_count.value ())); + + ACE_OS::sleep (2); + + ACE_DEBUG ((LM_DEBUG, " (%t) scheduler_open_count %d after waiting\n", + scheduler_open_count.value ())); + // @@ Can we safely delete worker_a, worker_b, and worker_c? +} + +static void +test_cancellation (int n_iterations) +{ + ACE_DEBUG ((LM_DEBUG," (%t) testing cancellation of a future...\n")); + + // Now test the cancelling a future. + + Scheduler *worker_a; + ACE_NEW (worker_a, Scheduler ("worker A")); + worker_a->open (); + + ACE_Future<u_long> fresulta = worker_a->work (9013, n_iterations); + + // save the result by copying the future + ACE_Future<u_long> fresultb = fresulta; + + // now we cancel the first future.. but the + // calculation will still go on... + fresulta.cancel (10); + + if (!fresulta.ready ()) + ACE_DEBUG ((LM_DEBUG," (%t) ERROR: future A is should be ready!!!\n")); + + u_long resulta = fresulta; + + ACE_DEBUG ((LM_DEBUG, " (%t) cancelled result %u\n", (u_int) resulta)); + + if (resulta != 10) + ACE_DEBUG ((LM_DEBUG, " (%t) cancelled result should be 10!!\n", resulta)); + + resulta = fresultb; + + ACE_DEBUG ((LM_DEBUG, " (%t) true result %u\n", (u_int) resulta)); + + worker_a->end (); + // @@ Can we safely delete worker_a here? +} + +static void +test_timeout (int n_iterations) +{ + ACE_DEBUG ((LM_DEBUG," (%t) testing timeout on waiting for the result...\n")); + Scheduler *worker_a; + ACE_NEW (worker_a, Scheduler ("worker A")); + worker_a->open (); + + ACE_Future<u_long> fresulta = worker_a->work (9013, 2 * n_iterations); + + // Should immediately return... and we should see an error... + ACE_Time_Value *delay; + ACE_NEW (delay, ACE_Time_Value (1)); + + u_long resulta = 0; + fresulta.get (resulta, delay); + + if (fresulta.ready ()) + ACE_DEBUG ((LM_DEBUG," (%t) ERROR: future A is should not be ready!!!\n")); + else + ACE_DEBUG ((LM_DEBUG," (%t) timed out on future A\n")); + + // now we wait until we are done... + fresulta.get (resulta); + ACE_DEBUG ((LM_DEBUG, " (%t) result %u\n", (u_int) resulta)); + + worker_a->end (); + // @@ Can we safely delete worker_a here? +} + +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + int n_iterations = determine_iterations (); + + test_active_object (n_iterations); + test_cancellation (n_iterations); + test_timeout (n_iterations); + + ACE_DEBUG ((LM_DEBUG," (%t) that's all folks!\n")); + + ACE_OS::sleep (5); + return 0; +} + +#else +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_ERROR ((LM_ERROR, "threads not supported on this platform\n")); + return 0; +} +#endif /* ACE_HAS_THREADS */ diff --git a/ACE/examples/Threads/manual_event.cpp b/ACE/examples/Threads/manual_event.cpp new file mode 100644 index 00000000000..c168c384191 --- /dev/null +++ b/ACE/examples/Threads/manual_event.cpp @@ -0,0 +1,114 @@ +// $Id$ + +// The test shows the use of an ACE_Manual_Event to create a +// Pseudo_Barrier. Multiple threads are created which do the +// following: +// +// 1. work +// 2. synch with other threads +// 3. more work +// +// ACE_Manual_Event is use to synch with other +// threads. ACE_Manual_Event::signal() is used for broadcasting. + +#include "ace/OS_NS_unistd.h" +#include "ace/OS_main.h" +#include "ace/Service_Config.h" +#include "ace/Thread_Mutex.h" +#include "ace/Manual_Event.h" +#include "ace/Thread_Manager.h" +#include "ace/Atomic_Op.h" + +ACE_RCSID(Threads, manual_event, "$Id$") + +#if defined (ACE_HAS_THREADS) +static ACE_Atomic_Op <ACE_Thread_Mutex, int> amount_of_work = 0; + +class Pseudo_Barrier + // = TITLE + // A barrier class using ACE manual-reset events. + // + // = DESCRIPTION + // This is *not* a real barrier. + // Pseudo_Barrier is more like a ``one shot'' barrier. + // All waiters after the Nth waiter are allowed to go. + // The barrier does not reset after the Nth waiter. + // For an example of a real barrier, please see class ACE_Barrier. +{ +public: + Pseudo_Barrier (u_long count); + + int wait (void); + +private: + ACE_Atomic_Op <ACE_Thread_Mutex, int> counter_; + ACE_Manual_Event event_; +}; + +Pseudo_Barrier::Pseudo_Barrier (u_long count) + : counter_ (count) +{ +} + +int +Pseudo_Barrier::wait (void) +{ + if (--this->counter_ == 0) + return this->event_.signal (); + else + return this->event_.wait (); +} + +static void * +worker (void *arg) +{ + Pseudo_Barrier &thread_barrier = *(Pseudo_Barrier *) arg; + + // work + ACE_DEBUG ((LM_DEBUG, "(%t) working (%d secs)\n", ++::amount_of_work)); + ACE_OS::sleep (::amount_of_work.value ()); + + // synch with everybody else + ACE_DEBUG ((LM_DEBUG, "(%t) waiting to synch with others \n")); + thread_barrier.wait (); + + // more work + ACE_DEBUG ((LM_DEBUG, "(%t) more work (%d secs)\n", ++::amount_of_work)); + ACE_OS::sleep (::amount_of_work.value ()); + + ACE_DEBUG ((LM_DEBUG, "(%t) dying \n")); + + return 0; +} + +int +ACE_TMAIN (int argc, ACE_TCHAR **argv) +{ + int n_threads = argc == 2 ? ACE_OS::atoi (argv[1]) : 5; + + ACE_Thread_Manager &tm = *ACE_Thread_Manager::instance (); + + // synch object shared by all threads + Pseudo_Barrier thread_barrier (n_threads); + + // create workers + if (tm.spawn_n (n_threads, (ACE_THR_FUNC) worker, &thread_barrier) == -1) + ACE_ERROR_RETURN ((LM_ERROR, "thread creates for worker failed"), -1); + + // wait for all workers to exit + if (tm.wait () == -1) + ACE_ERROR_RETURN ((LM_ERROR, "thread wait failed"), -1); + else + ACE_DEBUG ((LM_ERROR, "graceful exit\n")); + + return 0; +} + +#else +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_ERROR ((LM_ERROR, "threads not supported on this platform\n")); + return 0; +} +#endif /* ACE_HAS_THREADS */ diff --git a/ACE/examples/Threads/process_manager.cpp b/ACE/examples/Threads/process_manager.cpp new file mode 100644 index 00000000000..b8c2455b469 --- /dev/null +++ b/ACE/examples/Threads/process_manager.cpp @@ -0,0 +1,296 @@ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// examples/Threads/ +// +// = FILENAME +// process_manager.cpp +// +// = DESCRIPTION +// Test out the mechanisms provided by the ACE_Process_Manager. +// Using the global ACE_Process_Manager::instance(), we first spawn +// some processes (re-invoke this program, and plain-old-fork on +// systems that support it), and try the wait() functions. +// +// Then, we register the Process_Manager with +// ACE_Reactor::instance() and spawn more processes, counting on the +// autoreap to clean up. +// +// Specific-pid and generic exit-handler functions are also tested. +// +// = AUTHOR +// Douglas C. Schmidt <schmidt@cs.wustl.edu> and +// Dave Madden <dhm@mersenne.com> +// +// ============================================================================ + +#include "ace/OS_NS_unistd.h" +#include "ace/OS_main.h" +#include "ace/Service_Config.h" +#include "ace/Thread_Manager.h" +#include "ace/Process_Manager.h" +#include "ace/Get_Opt.h" + +ACE_RCSID(Threads, process_manager, "$Id$") + +class ExitHandler : public ACE_Event_Handler +{ +public: + ExitHandler (const char *name); + + virtual ~ExitHandler (void); + virtual int handle_exit (ACE_Process *proc); + virtual int handle_timeout (const ACE_Time_Value &tv, + const void *arg = 0); + virtual int handle_close (ACE_HANDLE handle, + ACE_Reactor_Mask close_mask); + // Called when object is removed from the <ACE_Reactor>. +private: + const char *name_; +}; + +ExitHandler::ExitHandler (const char *name) + : ACE_Event_Handler (), + name_ (name) +{ +} + +ExitHandler::~ExitHandler (void) +{ + ACE_DEBUG ((LM_DEBUG, + "(%P|%t@%T) ExitHandler \"%s\" destroyed\n", + name_)); +} + +int +ExitHandler::handle_exit (ACE_Process *proc) +{ + ACE_DEBUG ((LM_DEBUG, + "(%P|%t@%T) ExitHandler \"%s\" handle_exit for pid %d status %d\n", + name_, + proc->getpid (), + proc->exit_code ())); + return 0; +} + +int +ExitHandler::handle_timeout(const ACE_Time_Value &, + const void *) +{ + static int tick_tock = 0; + + ACE_DEBUG ((LM_DEBUG, + "(%P|%t@%T) \"%s\" %s\n", + name_, + ACE_ODD (tick_tock) ? "Tock" : "Tick")); + tick_tock++; + return 0; +} + +int +ExitHandler::handle_close (ACE_HANDLE, + ACE_Reactor_Mask) +{ + ACE_DEBUG ((LM_DEBUG, + "(%P|%t@%T) ExitHandler \"%s\" handle_close\n", + name_)); + delete this; + return 0; +} + +// Spin furiously <iterations> times, pausing every 100 cycles to +// print a message and sleep for a few seconds. + +static void +worker (size_t iterations) +{ + for (size_t i = 0; + i <= iterations; + i++) + if (i && (i % 100) == 0) + { + ACE_DEBUG ((LM_DEBUG, + "(%P|%t@%T) worker spinning furiously... (%u)\n", + i)); + ACE_OS::sleep (1); + } + + ACE_DEBUG ((LM_DEBUG, + "(%P|%t@%T) worker finished\n")); +} + +static int n_iterations = 500; +static int child = 0; +static int exit_code = 0; + +// Parse the command-line arguments and set options. +static void +parse_args (int argc, ACE_TCHAR *argv[]) +{ + ACE_Get_Opt get_opt (argc, argv, ACE_TEXT("i:e:cu")); + + int c; + + while ((c = get_opt ()) != -1) + switch (c) + { + case 'i': + n_iterations = ACE_OS::atoi (get_opt.opt_arg ()); + break; + case 'e': + exit_code = ACE_OS::atoi (get_opt.opt_arg ()); + break; + case 'c': + child = 1; + break; + case 'u': + default: + ACE_DEBUG ((LM_DEBUG, "usage:\n" + "-p <processes>\n" + "-i <iterations>\n")); + break; + } +} + +// Use ACE_Process_Manager::instance() to spawn another copy of this +// process. + +static pid_t +respawn_self (const ACE_TCHAR *myname, + int iter, + int exit_code) +{ + ACE_Process_Options options; + options.command_line ("%s -c -i %d -e %d", + myname, + iter, + exit_code); + return ACE_Process_Manager::instance ()->spawn (options); +} + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + ACE_Service_Config daemon; + + daemon.open (argv[0]); + + parse_args (argc, argv); + + if (child) + { + worker (n_iterations); + + ACE_OS::exit (exit_code); + } + + ACE_DEBUG ((LM_DEBUG, + "(%P|%t@%T) Process_Manager test. Expect output from" + "2 or 3 processes...\n")); + + ACE_Process_Manager::instance ()->register_handler + (new ExitHandler ("default")); + + pid_t pid1 = respawn_self (argv[0], + n_iterations, + 111); + pid_t pid2 = respawn_self (argv[0], + n_iterations + 500, + 222); + +#if !defined (ACE_WIN32) + pid_t pid3 = ACE_OS::fork (); + + if (!pid3) + { + worker (n_iterations); + return 999; + } +#endif /* ACE_WIN32 */ + + ACE_Process_Manager::instance ()->register_handler (new ExitHandler ("specific"), + pid2); + + if (pid1 == ACE_INVALID_PID || pid2 == ACE_INVALID_PID) + ACE_ERROR_RETURN ((LM_ERROR, + "(%P|%t) %p\n", + "start_n"), + 1); + + ACE_DEBUG ((LM_DEBUG, + "(%P|%t@%T) Test parent waiting (synchronously, " + "up to 6 seconds) for children...\n")); + + int result = + ACE_Process_Manager::instance ()->wait (ACE_Time_Value (6)); + + ACE_DEBUG ((LM_DEBUG, + "(%P|%t@%T) Test parent: %d processes left\n", + result)); + + if (result > 0) + { + ACE_DEBUG ((LM_DEBUG, + "(%P|%t@%T) Test parent waiting (synchronously, " + "indefinitely) for remaining children...\n")); + result = + ACE_Process_Manager::instance ()->wait (); + ACE_DEBUG ((LM_DEBUG, + "(%P|%t@%T) Test parent finished waiting: %d\n", + result)); + } + + ACE_DEBUG ((LM_DEBUG, + "(%P|%t@%T) Test parent: try auto-reap functions\n")); + + ACE_Process_Manager::instance ()->open (ACE_Process_Manager::DEFAULT_SIZE, + ACE_Reactor::instance ()); + + pid1 = respawn_self (argv[0], + n_iterations + 200, + 333 ); + pid2 = respawn_self (argv[0], + n_iterations + 500, + 444); + +#if !defined (ACE_WIN32) + pid3 = ACE_OS::fork (); + + if (!pid3) + { + worker (n_iterations); + return 888; + } +#endif /* ACE_WIN32 */ + + ExitHandler *main_thread_work = 0; + ACE_NEW_RETURN (main_thread_work, + ExitHandler ("main thread worker"), + 1); + + ACE_Reactor::instance ()->schedule_timer (main_thread_work, + 0, + ACE_Time_Value (2), + ACE_Time_Value (1, 500000)); + ACE_DEBUG ((LM_DEBUG, + "(%P|%t@%T) Test parent: expect several Processes " + "to be auto-detected over the next 30 seconds.\n" + "The main thread will do some other work, too.\n" )); + + ACE_Time_Value briefly (30); + + result = ACE_Reactor::run_event_loop (briefly); + + ACE_DEBUG ((LM_DEBUG, + "(%P|%t@%T) Test parent: finished (%d) %d.%d. Close" + "Process_Manager...\n", + result, + briefly.sec (), + briefly.usec ())); + + ACE_Process_Manager::instance ()->close (); + + return 0; +} diff --git a/ACE/examples/Threads/process_mutex.cpp b/ACE/examples/Threads/process_mutex.cpp new file mode 100644 index 00000000000..bbb03c08d0b --- /dev/null +++ b/ACE/examples/Threads/process_mutex.cpp @@ -0,0 +1,75 @@ +// $Id$ + +// This program tests ACE_Process_Mutexes. To run it, open 3 or 4 +// windows and run this program in each window... + +#include "ace/OS_main.h" +#include "ace/OS_NS_unistd.h" +#include "ace/Thread_Mutex.h" +#include "ace/Signal.h" +#include "ace/Log_Msg.h" +#include "ace/Process_Mutex.h" + +ACE_RCSID(Threads, process_mutex, "$Id$") + +#if defined (ACE_HAS_THREADS) + +static sig_atomic_t done; + +extern "C" void +handler (int) +{ + done = 1; +} + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + const ACE_TCHAR *name = argc > 1 ? argv[1] : ACE_TEXT("hello"); + int iterations = argc > 2 ? ACE_OS::atoi (argv[2]) : 100; + + ACE_Process_Mutex pm (name); + + // Register a signal handler. + ACE_Sig_Action sa ((ACE_SignalHandler) handler, SIGINT); + ACE_UNUSED_ARG (sa); + + for (int i = 0; i < iterations && !done; i++) + { + ACE_DEBUG ((LM_DEBUG, "(%P|%t) = acquiring\n")); + if (pm.acquire () == -1) + ACE_DEBUG ((LM_DEBUG, "(%P|%t) = %p\n", "acquire failed")); + else + ACE_DEBUG ((LM_DEBUG, "(%P|%t) = acquired\n")); + + ACE_OS::sleep (3); + + if (pm.release () == -1) + ACE_DEBUG ((LM_DEBUG, "(%P|%t) = %p\n", "release failed")); + else + ACE_DEBUG ((LM_DEBUG, "(%P|%t) = released\n")); + + if (pm.tryacquire () == -1) + ACE_DEBUG ((LM_DEBUG, "(%P|%t) = %p\n", "tryacquire failed")); + else + ACE_DEBUG ((LM_DEBUG, "(%P|%t) = tryacquire\n")); + + if (pm.release () == -1) + ACE_DEBUG ((LM_DEBUG, "(%P|%t) = %p\n", "release failed")); + else + ACE_DEBUG ((LM_DEBUG, "(%P|%t) = released\n")); + } + + if (argc > 2) + pm.remove (); + return 0; +} +#else +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_ERROR_RETURN ((LM_ERROR, + "ACE doesn't support support threads on this platform (yet)\n"), + -1); +} +#endif /* ACE_HAS_THREADS */ diff --git a/ACE/examples/Threads/process_semaphore.cpp b/ACE/examples/Threads/process_semaphore.cpp new file mode 100644 index 00000000000..e7adbb6a3ac --- /dev/null +++ b/ACE/examples/Threads/process_semaphore.cpp @@ -0,0 +1,63 @@ +// $Id$ + +// This program tests ACE_Process_Semaphore. To run it, open 3 or 4 +// windows and run this program in each window... + +#include "ace/OS_main.h" +#include "ace/OS_NS_unistd.h" +#include "ace/Signal.h" +#include "ace/Log_Msg.h" +#include "ace/Process_Semaphore.h" +#include "ace/OS_NS_stdlib.h" + +ACE_RCSID(Threads, process_semaphore, "$Id$") + +static sig_atomic_t done; + +extern "C" void +handler (int) +{ + done = 1; +} + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + const ACE_TCHAR *name = argc == 1 ? ACE_TEXT("hello") : argv[1]; + int iterations = argc > 2 ? ACE_OS::atoi (argv[2]) : 100; + + ACE_Process_Semaphore pm (1, name); + + ACE_Sig_Action sa ((ACE_SignalHandler) handler, SIGINT); + ACE_UNUSED_ARG (sa); + + for (int i = 0; i < iterations && !done; i++) + { + ACE_DEBUG ((LM_DEBUG, "(%P|%t) = acquiring\n")); + if (pm.acquire () == -1) + ACE_DEBUG ((LM_DEBUG, "(%P|%t) = %p\n", "acquire failed")); + else + ACE_DEBUG ((LM_DEBUG, "(%P|%t) = acquired\n")); + + ACE_OS::sleep (3); + + if (pm.release () == -1) + ACE_DEBUG ((LM_DEBUG, "(%P|%t) = %p\n", "release failed")); + else + ACE_DEBUG ((LM_DEBUG, "(%P|%t) = released\n")); + + if (pm.tryacquire () == -1) + ACE_DEBUG ((LM_DEBUG, "(%P|%t) = %p\n", "tryacquire failed")); + else + ACE_DEBUG ((LM_DEBUG, "(%P|%t) = tryacquire\n")); + + if (pm.release () == -1) + ACE_DEBUG ((LM_DEBUG, "(%P|%t) = %p\n", "release failed")); + else + ACE_DEBUG ((LM_DEBUG, "(%P|%t) = released\n")); + } + + if (argc > 2) + pm.remove (); + return 0; +} diff --git a/ACE/examples/Threads/reader_writer.cpp b/ACE/examples/Threads/reader_writer.cpp new file mode 100644 index 00000000000..5344ba4d5b4 --- /dev/null +++ b/ACE/examples/Threads/reader_writer.cpp @@ -0,0 +1,188 @@ +// $Id$ + +// This test program verifies the functionality of the ACE_OS +// implementation of readers/writer locks on Win32 and Posix pthreads. + +#include "ace/OS_main.h" +#include "ace/Thread.h" +#include "ace/Thread_Manager.h" +#include "ace/Get_Opt.h" +#include "ace/Atomic_Op.h" + +ACE_RCSID(Threads, reader_writer, "$Id$") + +#if defined (ACE_HAS_THREADS) + +#include "ace/Guard_T.h" +#include "ace/RW_Mutex.h" + +// Default number of iterations. +static int n_iterations = 1000; + +// Default number of loops. +static int n_loops = 100; + +// Default number of readers. +static int n_readers = 6; + +// Default number of writers. +static int n_writers = 2; + +// Thread id of last writer. +static ACE_thread_t shared_thr_id; + +// Lock for shared_thr_id. +static ACE_RW_Mutex rw_mutex; + +// Count of the number of readers and writers. +ACE_Atomic_Op<ACE_Thread_Mutex, int> current_readers, current_writers; + +// Thread manager +static ACE_Thread_Manager thr_mgr; + +// Explain usage and exit. +static void +print_usage_and_die (void) +{ + ACE_DEBUG ((LM_DEBUG, + "usage: %n [-r n_readers] [-w n_writers] [-n iteration_count]\n")); + ACE_OS::exit (1); +} + +// Parse the command-line arguments and set options. +static void +parse_args (int argc, ACE_TCHAR *argv[]) +{ + ACE_Get_Opt get_opt (argc, argv, ACE_TEXT("r:w:n:l:")); + + int c; + + while ((c = get_opt ()) != -1) + switch (c) + { + case 'r': + n_readers = ACE_OS::atoi (get_opt.opt_arg ()); + break; + case 'w': + n_writers = ACE_OS::atoi (get_opt.opt_arg ()); + break; + case 'n': + n_iterations = ACE_OS::atoi (get_opt.opt_arg ()); + break; + case 'l': + n_loops = ACE_OS::atoi (get_opt.opt_arg ()); + break; + default: + print_usage_and_die (); + break; + } +} + +// Iterate <n_iterations> each time checking that nobody modifies the +// data while we have a read lock. + +static void * +reader (void *) +{ + ACE_DEBUG ((LM_DEBUG, "(%t) reader starting\n")); + + for (int iterations = 1; + iterations <= n_iterations; iterations++) + { + ACE_Read_Guard<ACE_RW_Mutex> g(rw_mutex); + + ++current_readers; + + if (current_writers > 0) + ACE_DEBUG ((LM_DEBUG, "(%t) writers found!!!\n")); + + ACE_thread_t thr_id = shared_thr_id; + + for (int loop = 1; loop <= n_loops; loop++) + { + ACE_Thread::yield(); + + if (ACE_OS::thr_equal (shared_thr_id, thr_id) == 0) + ACE_DEBUG ((LM_DEBUG, + "(%t) somebody changed %d to %d\n", + thr_id, shared_thr_id)); + } + + --current_readers; + + ACE_Thread::yield (); + } + return 0; +} + +// Iterate <n_iterations> each time modifying the global data +// and checking that nobody steps on it while we can write it. + +static void * +writer (void *) +{ + ACE_DEBUG ((LM_DEBUG, "(%t) writer starting\n")); + + for (int iterations = 1; + iterations <= n_iterations; + iterations++) + { + ACE_Write_Guard<ACE_RW_Mutex> g(rw_mutex); + + ++current_writers; + + if (current_writers > 1) + ACE_DEBUG ((LM_DEBUG, "(%t) other writers found!!!\n")); + + if (current_readers > 0) + ACE_DEBUG ((LM_DEBUG, "(%t) readers found!!!\n")); + + ACE_thread_t self = ACE_Thread::self (); + shared_thr_id = self; + + for (int loop = 1; loop <= n_loops; loop++) + { + ACE_Thread::yield(); + + if (ACE_OS::thr_equal (shared_thr_id, self) == 0) + ACE_DEBUG ((LM_DEBUG, "(%t) somebody wrote on my data %d\n", + shared_thr_id)); + } + + --current_writers; + + ACE_Thread::yield (); + } + return 0; +} + +// Spawn off threads. + +int ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + ACE_LOG_MSG->open (argv[0]); + parse_args (argc, argv); + + current_readers = 0; // Possibly already done + current_writers = 0; // Possibly already done + + ACE_DEBUG ((LM_DEBUG, "(%t) main thread starting\n")); + + if (thr_mgr.spawn_n (n_readers, (ACE_THR_FUNC) reader, 0, THR_NEW_LWP) == -1 || + thr_mgr.spawn_n (n_writers, (ACE_THR_FUNC) writer, 0, THR_NEW_LWP) == -1) + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "spawn_n"), 1); + + thr_mgr.wait (); + + ACE_DEBUG ((LM_DEBUG, "(%t) exiting main thread\n")); + return 0; +} + +#else +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_ERROR ((LM_ERROR, "threads not supported on this platform\n")); + return 0; +} +#endif /* ACE_HAS_THREADS */ diff --git a/ACE/examples/Threads/recursive_mutex.cpp b/ACE/examples/Threads/recursive_mutex.cpp new file mode 100644 index 00000000000..3c915682d90 --- /dev/null +++ b/ACE/examples/Threads/recursive_mutex.cpp @@ -0,0 +1,113 @@ +// $Id$ + +// This test program verifies the functionality of the ACE_OS +// implementation of recursive mutexes on Win32 and Posix pthreads. + +#include "ace/OS_main.h" +#include "ace/Service_Config.h" +#include "ace/Thread_Manager.h" +#include "ace/Get_Opt.h" + +ACE_RCSID(Threads, recursive_mutex, "$Id$") + +#if defined (ACE_HAS_THREADS) + +#include "ace/Guard_T.h" +#include "ace/Recursive_Thread_Mutex.h" + +// Total number of iterations. +static size_t n_iterations = 1000; +static size_t n_threads = 4; + +// Explain usage and exit. +static void +print_usage_and_die (void) +{ + ACE_DEBUG ((LM_DEBUG, + "usage: %n [-t n_threads] [-n iteration_count]\n")); + ACE_OS::exit (1); +} + +// Parse the command-line arguments and set options. + +static void +parse_args (int argc, ACE_TCHAR *argv[]) +{ + ACE_Get_Opt get_opt (argc, argv, ACE_TEXT("n:t:")); + + int c; + + while ((c = get_opt ()) != -1) + switch (c) + { + case 'n': + n_iterations = ACE_OS::atoi (get_opt.opt_arg ()); + break; + case 't': + n_threads = ACE_OS::atoi (get_opt.opt_arg ()); + break; + default: + print_usage_and_die (); + break; + } +} + +static void +recursive_worker (size_t nesting_level, + ACE_Recursive_Thread_Mutex *rm) +{ + if (nesting_level < n_iterations) + { + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) = trying to acquire, nesting = %d, thread id = %u\n", + rm->get_nesting_level (), rm->get_thread_id ())); + { + // This illustrates the use of the ACE_Guard<LOCK> with an + // ACE_Recursive_Thread_Mutex. + ACE_GUARD (ACE_Recursive_Thread_Mutex, ace_mon, *rm); + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) = acquired, nesting = %d, thread id = %u\n", + rm->get_nesting_level (), rm->get_thread_id ())); + + recursive_worker (nesting_level + 1, rm); + } + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) = released, nesting = %d, thread id = %u\n", + rm->get_nesting_level (), rm->get_thread_id ())); + } +} + +static void * +worker (void *arg) +{ + ACE_Recursive_Thread_Mutex *rm + = (ACE_Recursive_Thread_Mutex *) arg; + + recursive_worker (0, rm); + return 0; +} + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + ACE_Service_Config daemon (argv[0]); + + parse_args (argc, argv); + ACE_Recursive_Thread_Mutex rm; + + ACE_Thread_Manager::instance ()->spawn_n (n_threads, + ACE_THR_FUNC (worker), + (void *) &rm); + + ACE_Thread_Manager::instance ()->wait (); + return 0; +} +#else +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_ERROR_RETURN ((LM_ERROR, + "ACE doesn't support support process mutexes on this platform (yet)\n"), + -1); +} +#endif /* ACE_WIN32 */ diff --git a/ACE/examples/Threads/task_five.cpp b/ACE/examples/Threads/task_five.cpp new file mode 100644 index 00000000000..8f96ee3420e --- /dev/null +++ b/ACE/examples/Threads/task_five.cpp @@ -0,0 +1,177 @@ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// examples/Threads/ +// +// = FILENAME +// task_five.cpp +// +// = DESCRIPTION +// Stress testing thread creation and thread cancellation using +// ACE_Task. +// +// = AUTHOR +// Author: Detlef Becker <Detlef.Becker@med.siemens.de> +// +// ============================================================================ + + +#include "ace/OS_main.h" +#include "ace/Thread_Manager.h" +#include "ace/Task.h" +#include "ace/OS_NS_unistd.h" + +ACE_RCSID(Threads, task_five, "$Id$") + +static const int DEFAULT_TASKS = 100; +static const int DEFAULT_ITERATIONS = 10; + +// Default stack size +static size_t default_stack_size = +#if defined (ACE_WIN32) + 0; +#else + 8192; +#endif /* ACE_WIN32 */ + u_int loop_count = 0; + u_int error_count = 0; + +class Test_Task : public ACE_Task<ACE_SYNCH> +{ +public: + Test_Task (ACE_Thread_Manager * = ACE_Thread_Manager::instance ()); + ~Test_Task (void) {}; + + int open (void * = 0); + int svc (void); + int close (u_long); + int shutdown (void); + int synch (void); +}; + +Test_Task::Test_Task (ACE_Thread_Manager *thrmgr) + : ACE_Task<ACE_SYNCH> (thrmgr) +{ +} + +int +Test_Task::open (void *) +{ + return this->activate (0, + 1, + 0, + ACE_DEFAULT_THREAD_PRIORITY, + -1, + 0, + 0, + 0, + &default_stack_size); +} + +int +Test_Task::svc (void) +{ + while (thr_mgr_->testcancel (ACE_OS::thr_self ()) == 0) + // Sleep for 350 msecs. + ACE_OS::sleep (ACE_Time_Value (0, 350000)); + + return 0; +} + +int +Test_Task::close (u_long) +{ + ACE_DEBUG ((LM_DEBUG, "(%t) closing down\n")); + return 0; +} + +int +Test_Task::shutdown (void) +{ + return thr_mgr_->cancel_grp (grp_id_); +} + +int +Test_Task::synch (void) +{ + return thr_mgr_->wait_grp (grp_id_); +} + +static void +work (ACE_Thread_Manager *thr_mgr, + int n_tasks, + size_t stack_size) +{ + ACE_UNUSED_ARG (stack_size); + + int i; + Test_Task *task_array; + + ACE_NEW (task_array, + Test_Task[n_tasks]); + + ACE_DEBUG ((LM_DEBUG, + "Opening Tasks, loop count = %d, error count = %d\n", + loop_count, + error_count)); + + for (i = 0; + i < n_tasks; + i++) + task_array[i].open (); + + ACE_OS::sleep (1); + + ACE_DEBUG ((LM_DEBUG, + "Cancelling Tasks, loop count = %d, error count = %d\n", + loop_count, + error_count)); + + for (i = 0; i < n_tasks; i++) + task_array[i].shutdown (); + + ACE_DEBUG ((LM_DEBUG, + "Synching Tasks, loop count = %d, error count = %d\n", + loop_count, + error_count)); + + for (i = 0; + + i < n_tasks; i++) + if (-1 == task_array[i].synch ()) + { + ACE_ERROR ((LM_ERROR, + "Error in synch! loop count = %d, error count = %d\n", + loop_count, + error_count)); + error_count++; + } + + ACE_DEBUG ((LM_DEBUG, + "thr_mgr->wait ();! loop count = %d, error count = %d\n", + loop_count, + error_count)); + + // Wait for all the threads to finish. + thr_mgr->wait (); + + delete [] task_array; + loop_count++; +} + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + size_t stack_size = argc > 1 ? ACE_OS::atoi (argv[1]) : default_stack_size; + const int n_tasks = argc > 2 ? ACE_OS::atoi (argv[2]) : DEFAULT_TASKS; + u_int iterations = argc > 3 ? ACE_OS::atoi (argv[3]) : DEFAULT_ITERATIONS; + + for (u_int i = 0; i < iterations; i++) + work (ACE_Thread_Manager::instance (), + n_tasks, + stack_size); + + return 0; +} diff --git a/ACE/examples/Threads/task_four.cpp b/ACE/examples/Threads/task_four.cpp new file mode 100644 index 00000000000..31610d56537 --- /dev/null +++ b/ACE/examples/Threads/task_four.cpp @@ -0,0 +1,307 @@ +// $Id$ + +// The following test was written by Hamutal Yanay & Ari Erev's +// (Ari_Erev@comverse.com). +// +// This test program test enhancements to the thread_manager and task +// classes. The purpose of these enhancements was to allow the +// thread_manager to recognize the concept of an ACE_Task and to be +// able to group ACE_Tasks in groups. +// +// There are two main ACE_Tasks in this sample: +// +// Invoker_Task - is run from main (). It's purpose is to run a number of +// ACE_Tasks of type Worker_Task. The number can be specified +// on the command line. +// After starting the tasks, the Invoker_Task groups all the tasks +// in one group and then uses the +// num_tasks_in_group () to find out if the real number of tasks +// that are now running (should be the same as the number of tasks +// started). +// It also, suspends and resumes all the threads in the group to +// test the suspend_grp () and resume_grp () methods. +// Then it waits for all the tasks to end. +// +// Worker_Task - ACE_Tasks that are started by the Invoker_Task. +// Each Worker_Task can start a number of threads. +// The Worker_Task threads perform some work (iteration). The number +// of the iterations can be specified on the command line. +// +// The command line syntax is: +// +// test_task [num_tasks] [num_threads] [num_iterations] + +#include "ace/OS_NS_unistd.h" +#include "ace/OS_main.h" +#include "ace/Task.h" +#include "ace/Service_Config.h" + +ACE_RCSID(Threads, task_four, "$Id$") + +#if defined (ACE_HAS_THREADS) + +#include "ace/Task.h" + +class Invoker_Task : public ACE_Task<ACE_MT_SYNCH> +{ +public: + Invoker_Task (ACE_Thread_Manager *thr_mgr, + size_t n_tasks, + size_t n_threads, + size_t n_iterations); + virtual int svc (void); + // creats <n_tasks> and wait for them to finish + +private: + size_t n_tasks_; + // Number of tasks to start. + size_t n_threads_; + // Number of threads per task. + size_t n_iterations_; + // Number of iterations per thread. +}; + +class Worker_Task : public ACE_Task<ACE_MT_SYNCH> +{ +public: + Worker_Task (ACE_Thread_Manager *thr_mgr, + size_t n_threads, + size_t n_iterations); + virtual int svc (void); + // Does a small work... + virtual int open (void * = NULL); + +private: + static size_t workers_count_; + size_t index_; + size_t n_threads_; + size_t n_iterations_; + + // = Not needed for this test. + virtual int close (u_long); + virtual int put (ACE_Message_Block *, ACE_Time_Value *) { return 0; } +}; + +size_t Worker_Task::workers_count_ = 1; + +int +Worker_Task::close (u_long) +{ + ACE_DEBUG ((LM_DEBUG, + "(%t) closing task %d\n", + this->index_)); + delete this; + return 0; +} + +Worker_Task::Worker_Task (ACE_Thread_Manager *thr_mgr, + size_t n_threads, + size_t n_iterations) + : ACE_Task<ACE_MT_SYNCH> (thr_mgr), + index_ (Worker_Task::workers_count_++), + n_threads_ (n_threads), + n_iterations_ (n_iterations) +{ +} + +int +Worker_Task::open (void *) +{ + // Create the pool of worker threads. + return this->activate (THR_NEW_LWP, + n_threads_, + 0, + -1, + -1, + this); +} + +int +Worker_Task::svc (void) +{ + ACE_DEBUG ((LM_DEBUG, + " (%t) in worker %d\n", + index_)); + + for (size_t iterations = 1; + iterations <= this->n_iterations_; + iterations++) + { + ACE_DEBUG ((LM_DEBUG, + " (%t) in iteration %d\n", + iterations)); + ACE_OS::sleep (0); + } + + ACE_DEBUG ((LM_DEBUG, + " (%t) worker %d ends\n", + index_)); + + return 0; +} + +Invoker_Task::Invoker_Task (ACE_Thread_Manager *thr_mgr, + size_t n_tasks, + size_t n_threads, + size_t n_iterations) + : ACE_Task<ACE_MT_SYNCH> (thr_mgr), + n_tasks_ (n_tasks), + n_threads_ (n_threads), + n_iterations_ (n_iterations) +{ + // Create a single worker thread. + if (this->activate (THR_NEW_LWP, + 1, + 0, + -1, + -1, + this) == -1) + ACE_ERROR ((LM_ERROR, + "%p\n", + "activate failed")); +} + +// Iterate <n_iterations> time printing off a message and "waiting" +// for all other threads to complete this iteration. + +int +Invoker_Task::svc (void) +{ + // Note that the ACE_Task::svc_run () method automatically adds us + // to the Thread_Manager when the thread begins. + + ACE_Thread_Manager *thr_mgr = + ACE_Thread_Manager::instance (); + Worker_Task **worker_task = 0; + + ACE_NEW_RETURN (worker_task, + Worker_Task *[n_tasks_], + -1); + size_t task = 0; + + for (task = 0; + task < this->n_tasks_; + task++) + { + ACE_DEBUG ((LM_DEBUG, + " (%t) in task %d\n", + task + 1)); + + ACE_NEW_RETURN (worker_task[task], + Worker_Task (thr_mgr, + n_threads_, + n_iterations_), + -1); + + if (worker_task[task]->open () == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "open failed"), + -1); + } + + // Set all tasks to be one group + ACE_DEBUG ((LM_DEBUG, + " (%t) setting tasks group id\n")); + + for (task = 0; + task < this->n_tasks_; + task++) + if (thr_mgr->set_grp (worker_task[task], + 1) == -1) + ACE_ERROR ((LM_DEBUG, + " (%t) %p\n", + "set_grp")); + + size_t n_tasks = + thr_mgr->num_tasks_in_group (1); + ACE_DEBUG ((LM_DEBUG, + "Number of tasks in group 1: %d\n", + n_tasks)) ; + + // Wait for 1 second and then suspend every thread in the group. + ACE_OS::sleep (1); + ACE_DEBUG ((LM_DEBUG, + " (%t) suspending group\n")); + + if (thr_mgr->suspend_grp (1) == -1) + ACE_ERROR ((LM_DEBUG, + " (%t) %p\n", + "suspend_grp")); + + // Wait for 3 more second and then resume every thread in the group. + ACE_OS::sleep (ACE_Time_Value (2)); + + ACE_DEBUG ((LM_DEBUG, + " (%t) resuming group\n")); + + if (thr_mgr->resume_grp (1) == -1) + ACE_ERROR ((LM_DEBUG, + " (%t) %p\n", + "resume_grp")); + + // Wait for all the tasks to reach their exit point. + thr_mgr->wait (); + + // Note that the ACE_Task::svc_run () method automatically removes + // us from the Thread_Manager when the thread exits. + return 0; +} + +// Default number of tasks and iterations. +static const size_t DEFAULT_TASKS = 4; +static const size_t DEFAULT_ITERATIONS = 5; + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + size_t n_tasks = argc > 1 ? ACE_OS::atoi (argv[1]) : DEFAULT_TASKS; + size_t n_threads = argc > 2 ? ACE_OS::atoi (argv[2]) : ACE_DEFAULT_THREADS; + size_t n_iterations = argc > 3 ? ACE_OS::atoi (argv[3]) : DEFAULT_ITERATIONS; + + // Since ACE_Thread_Manager can only wait for all threads, we'll + // have special manager for the Invoker_Task. + ACE_Thread_Manager invoker_manager; + + Invoker_Task invoker (&invoker_manager, + n_tasks, + n_threads, + n_iterations); + + // Wait for 1 second and then suspend the invoker task + ACE_OS::sleep (1); + ACE_DEBUG ((LM_DEBUG, + " (%t) suspending invoker task\n")); + + if (invoker_manager.suspend_task (&invoker) == -1) + ACE_ERROR ((LM_DEBUG, + " (%t) %p\n", + "suspend_task")); + + // Wait for 3 more second and then resume the invoker task. + ACE_OS::sleep (ACE_Time_Value (3)); + + ACE_DEBUG ((LM_DEBUG, + " (%t) resuming invoker task\n")); + + if (invoker_manager.resume_task (&invoker) == -1) + ACE_ERROR ((LM_DEBUG, + " (%t) %p\n", + "resume_task")); + + // Wait for all the threads to reach their exit point. + invoker_manager.wait (); + + ACE_DEBUG ((LM_DEBUG, + " (%t) done\n")); + return 0; +} +#else +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_ERROR ((LM_ERROR, + "threads not supported on this platform\n")); + return 0; +} +#endif /* ACE_HAS_THREADS */ diff --git a/ACE/examples/Threads/task_one.cpp b/ACE/examples/Threads/task_one.cpp new file mode 100644 index 00000000000..ea4fd71dcf8 --- /dev/null +++ b/ACE/examples/Threads/task_one.cpp @@ -0,0 +1,102 @@ +// $Id$ + +// This test program illustrates how the ACE barrier synchronization +// mechanisms work in conjunction with the ACE_Task and the +// ACE_Thread_Manager. It is instructive to compare this with the +// test_barrier.cpp test to see how they differ. + +#include "ace/OS_main.h" +#include "ace/Task.h" +#include "ace/Service_Config.h" + +ACE_RCSID(Threads, task_one, "$Id$") + +#if defined (ACE_HAS_THREADS) + +#include "ace/Task.h" +#include "ace/Barrier.h" + +class Barrier_Task : public ACE_Task<ACE_MT_SYNCH> +{ +public: + Barrier_Task (ACE_Thread_Manager *thr_mgr, + int n_threads, + int n_iterations); + + virtual int svc (void); + // Iterate <n_iterations> time printing off a message and "waiting" + // for all other threads to complete this iteration. + +private: + ACE_Barrier barrier_; + // Reference to the tester barrier. This controls each + // iteration of the tester function running in every thread. + + int n_iterations_; + // Number of iterations to run. +}; + +Barrier_Task::Barrier_Task (ACE_Thread_Manager *thr_mgr, + int n_threads, + int n_iterations) + : ACE_Task<ACE_MT_SYNCH> (thr_mgr), + barrier_ (n_threads), + n_iterations_ (n_iterations) +{ + // Create worker threads. + if (this->activate (THR_NEW_LWP, n_threads) == -1) + ACE_ERROR ((LM_ERROR, "%p\n", "activate failed")); +} + +// Iterate <n_iterations> time printing off a message and "waiting" +// for all other threads to complete this iteration. + +int +Barrier_Task::svc (void) +{ + // Note that the ACE_Task::svc_run() method automatically adds us to + // the Thread_Manager when the thread begins. + + for (int iterations = 1; + iterations <= this->n_iterations_; + iterations++) + { + ACE_DEBUG ((LM_DEBUG, "(%t) in iteration %d\n", iterations)); + + // Block until all other threads have waited, then continue. + this->barrier_.wait (); + } + + // Note that the ACE_Task::svc_run() method automatically removes us + // from the Thread_Manager when the thread exits. + + return 0; +} + +// Default number of threads to spawn. +static const int DEFAULT_ITERATIONS = 5; + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + int n_threads = argc > 1 ? ACE_OS::atoi (argv[1]) : ACE_DEFAULT_THREADS; + int n_iterations = argc > 2 ? ACE_OS::atoi (argv[2]) : DEFAULT_ITERATIONS; + + Barrier_Task barrier_task (ACE_Thread_Manager::instance (), + n_threads, + n_iterations); + + // Wait for all the threads to reach their exit point. + ACE_Thread_Manager::instance ()->wait (); + + ACE_DEBUG ((LM_DEBUG, "(%t) done\n")); + return 0; +} +#else +int +main (int, char *[]) +{ + ACE_ERROR ((LM_ERROR, "threads not supported on this platform\n")); + return 0; +} +#endif /* ACE_HAS_THREADS */ diff --git a/ACE/examples/Threads/task_three.cpp b/ACE/examples/Threads/task_three.cpp new file mode 100644 index 00000000000..03f6e816572 --- /dev/null +++ b/ACE/examples/Threads/task_three.cpp @@ -0,0 +1,268 @@ +// $Id$ + +// Exercise more tests for the <ACE_Task>s. This also shows off some +// Interesting uses of the <ACE_Log_Msg>'s ability to print to +// ostreams. BTW, make sure that you set the out_stream in *every* +// thread that you want to have write to the output file, i.e.: +// +// if (out_stream) +// { +// ACE_LOG_MSG->set_flags (ACE_Log_Msg::OSTREAM); +// ACE_LOG_MSG->msg_ostream (out_stream); +// } + +#include "ace/OS_NS_unistd.h" +#include "ace/OS_NS_stdio.h" +#include "ace/OS_main.h" +#include "ace/Reactor.h" +#include "ace/Service_Config.h" +#include "ace/Task.h" + +// FUZZ: disable check_for_streams_include +#include "ace/streams.h" + +#include "ace/Signal.h" + +ACE_RCSID(Threads, task_three, "$Id$") + +#if defined (ACE_HAS_THREADS) + +static ACE_OSTREAM_TYPE *out_stream = 0; +static sig_atomic_t done = 0; +static const size_t NUM_INVOCATIONS = 100; +static const size_t TASK_COUNT = 130; + +class Test_Task : public ACE_Task<ACE_MT_SYNCH> +{ +public: + Test_Task (void); + ~Test_Task (void); + + virtual int open (void *args = 0); + virtual int close (u_long flags = 0); + virtual int svc (void); + + virtual int handle_input (ACE_HANDLE fd); + + ACE_Reactor *r_; + size_t handled_; + static size_t current_count_; + static size_t done_cnt_; +}; + +size_t Test_Task::current_count_ = 0; +size_t Test_Task::done_cnt_ = 0; + +static ACE_Thread_Mutex Lock; + +Test_Task::Test_Task (void) +{ + ACE_GUARD (ACE_Thread_Mutex, ace_mon, Lock); + + this->handled_ = 0; + Test_Task::current_count_++; + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("Test_Task constructed, current_count_ = %d\n"), + Test_Task::current_count_)); +} + +Test_Task::~Test_Task (void) +{ + ACE_GUARD (ACE_Thread_Mutex, ace_mon, Lock); + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("Test_Task destroyed, current_count_ = %d\n"), + Test_Task::current_count_)); +} + +int +Test_Task::open (void *args) +{ + r_ = reinterpret_cast <ACE_Reactor *> (args); + return ACE_Task<ACE_MT_SYNCH>::activate (THR_NEW_LWP); +} + +int +Test_Task::close (u_long) +{ + ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, Lock, -1); + + Test_Task::current_count_--; + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("Test_Task::close () current_count_ = %d.\n"), + Test_Task::current_count_)); + return 0; +} + +int +Test_Task::svc (void) +{ + // Every thread must register the same stream to write to file. + if (out_stream) + { + ACE_LOG_MSG->set_flags (ACE_Log_Msg::OSTREAM); + ACE_LOG_MSG->msg_ostream (out_stream); + } + + for (size_t index = 0; index < NUM_INVOCATIONS; index++) + { + ACE_OS::thr_yield (); + + if (r_->notify (this, ACE_Event_Handler::READ_MASK) == -1) + { + ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, Lock, -1); + + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("Test_Task: error %p!\n"), + ACE_TEXT ("notifying reactor")), + 0); + } + } + + ACE_DEBUG ((LM_DEBUG, ACE_TEXT (" (%t) returning from svc ()\n"))); + return 0; +} + +int +Test_Task::handle_input (ACE_HANDLE) +{ + this->handled_++; + + if (this->handled_ == NUM_INVOCATIONS) + { + ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, Lock, -1); + Test_Task::done_cnt_++; + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT (" (%t) Test_Task: handle_input done_cnt_ = %d.\n"), + Test_Task::done_cnt_)); + } + + ACE_OS::thr_yield (); + return -1; +} + +static void * +dispatch (void *arg) +{ + // every thread must register the same stream to write to file + if (out_stream) + { + ACE_LOG_MSG->set_flags (ACE_Log_Msg::OSTREAM); + ACE_LOG_MSG->msg_ostream (out_stream); + } + + ACE_DEBUG ((LM_DEBUG, ACE_TEXT (" (%t) Dispatcher Thread started!\n"))); + ACE_Reactor *r = reinterpret_cast <ACE_Reactor *> (arg); + int result; + + r->owner (ACE_OS::thr_self ()); + + while (1) + { + result = r->handle_events (); + + if (result <= 0) + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("Dispatch: handle_events (): %d"), + result)); + } + + ACE_NOTREACHED (return 0); +} + +extern "C" void +handler (int) +{ + done = 1; +} + +int +ACE_TMAIN (int argc, ACE_TCHAR **) +{ + if (argc > 1) + { + // Send output to file. +#if !defined (ACE_LACKS_IOSTREAM_TOTALLY) + ACE_NEW_RETURN (out_stream, + ofstream ("test_task_three.out", + ios::trunc|ios::out), + -1); +#else + if ((out_stream = ACE_OS::fopen ("test_task_three.out", "w")) == NULL) + return -1; +#endif + ACE_LOG_MSG->set_flags (ACE_Log_Msg::OSTREAM); + ACE_LOG_MSG->msg_ostream (out_stream); + } + + // Register a signal handler. + ACE_Sig_Action sa ((ACE_SignalHandler) handler, SIGINT); + ACE_UNUSED_ARG (sa); + + ACE_Reactor *reactor1 = ACE_Reactor::instance (); + ACE_Reactor *reactor2 = new ACE_Reactor (); + + Test_Task t1[TASK_COUNT]; + Test_Task t2[TASK_COUNT]; + + ACE_Thread::spawn (ACE_THR_FUNC (dispatch), + reactor2); + + reactor1->owner (ACE_OS::thr_self ()); + + for (size_t index = 0; index < TASK_COUNT; index++) + { + t1[index].open (reactor1); + t2[index].open (reactor2); + } + + ACE_OS::sleep (3); + + while (done == 0) + { + ACE_Time_Value timeout (2); + + if (reactor1->handle_events (timeout) <= 0) + { + if (errno == ETIME) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("no activity within 2 seconds, shutting down\n"))); + break; + } + else + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("%p error handling events\n"), + ACE_TEXT ("main"))); + } + } + + if (argc > 1) + { +#if !defined (ACE_LACKS_IOSTREAM_TOTALLY) + *out_stream << flush; + delete out_stream; +#else + ACE_OS::fflush(out_stream); + ACE_OS::fclose(out_stream); +#endif + ACE_LOG_MSG->clr_flags (ACE_Log_Msg::OSTREAM); + ACE_LOG_MSG->msg_ostream (0); + } + + // Bail out here so that we don't call the destructors for the tasks.. + ACE_OS::exit (0); + /* NOTREACHED */ + + return 0; +} + +#else +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("threads not supported on this platform\n"))); + return 0; +} +#endif /* ACE_HAS_THREADS */ diff --git a/ACE/examples/Threads/task_two.cpp b/ACE/examples/Threads/task_two.cpp new file mode 100644 index 00000000000..7243ac5b1c3 --- /dev/null +++ b/ACE/examples/Threads/task_two.cpp @@ -0,0 +1,147 @@ +// $Id$ + +// Exercise more tests for the ACE Tasks. This test can spawn off +// zillions of tasks and then wait for them using both polling and the +// ACE Thread Manager. + +#include "ace/OS_main.h" +#include "ace/Task.h" + +#include "ace/Service_Config.h" +#include "ace/Atomic_Op.h" + +ACE_RCSID(Threads, task_two, "$Id$") + +#if defined (ACE_HAS_THREADS) + +typedef ACE_Atomic_Op<ACE_Thread_Mutex, int> ATOMIC_INT; + +static int zero = 0; +static ATOMIC_INT task_count (zero); +static ATOMIC_INT max_count (zero); +static ATOMIC_INT wait_count (zero); + +static int n_threads = 0; + +// Default number of tasks. +static const int default_threads = ACE_DEFAULT_THREADS; + +// Default number of times to run the test. +static const int default_iterations = 1000; + +class Task_Test : public ACE_Task<ACE_MT_SYNCH> +{ +public: + virtual int open (void *args = 0); + virtual int close (u_long flags = 0); + virtual int svc (void); + +private: + static ACE_Thread_Mutex lock_; +}; + +ACE_Thread_Mutex Task_Test::lock_; + +int +Task_Test::open (void *) +{ + ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, Task_Test::lock_, -1); + + task_count++; + ACE_DEBUG ((LM_DEBUG, "(%t) creating Task_Test, task count = %d\n", + task_count.value ())); + + return this->activate (THR_BOUND); +} + +int +Task_Test::close (u_long) +{ + ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, Task_Test::lock_, -1); + + task_count--; + ACE_DEBUG ((LM_DEBUG, "(%t) destroying Task_Test, task count = %d\n", + task_count.value ())); + wait_count--; + return 0; +} + +int +Task_Test::svc (void) +{ + wait_count++; + max_count++; + + ACE_DEBUG ((LM_DEBUG, "(%t) svc: waiting\n")); + + for (;;) + if (max_count >= n_threads) + break; + else + ACE_Thread::yield (); + + ACE_DEBUG ((LM_DEBUG, "(%t) svc: finished waiting\n")); + return 0; +} + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + n_threads = argc > 1 ? ACE_OS::atoi (argv[1]) : default_threads; + int n_iterations = argc > 2 ? ACE_OS::atoi (argv[2]) : default_iterations; + + Task_Test **task_array = new Task_Test *[n_threads]; + + for (int i = 1; i <= n_iterations; i++) + { + ACE_DEBUG ((LM_DEBUG, "(%t) iteration = %d, max_count %d\n", + i, max_count.value ())); + max_count = 0; + + ACE_DEBUG ((LM_DEBUG, "(%t) starting %d task%s\n", + n_threads, n_threads == 1 ? "" : "s")); + + // Launch the new tasks. + for (int j = 0; j < n_threads; j++) + { + task_array[j] = new Task_Test; + // Activate the task, i.e., make it an active object. + task_array[j]->open (); + } + + // Wait for initialization to kick in. + while (max_count == 0) + ACE_Thread::yield (); + + ACE_DEBUG ((LM_DEBUG, "(%t) waiting for threads to finish\n")); + + // Wait for the threads to finish this iteration. + while (max_count != n_threads && wait_count != 0) + ACE_Thread::yield (); + + ACE_DEBUG ((LM_DEBUG, + "(%t) iteration %d finished, max_count %d, wait_count %d, waiting for tasks to exit\n", + i, max_count.value (), wait_count.value ())); + + // Wait for all the tasks to exit. + ACE_Thread_Manager::instance ()->wait (); + + // Delete the existing tasks. + for (int k = 0; k < n_threads; k++) + delete task_array[k]; + } + + delete [] task_array; + + ACE_DEBUG ((LM_DEBUG, "(%t) shutting down the test\n")); + return 0; +} + +#else +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_ERROR ((LM_ERROR, "threads not supported on this platform\n")); + return 0; +} +#endif /* ACE_HAS_THREADS */ diff --git a/ACE/examples/Threads/thread_manager.cpp b/ACE/examples/Threads/thread_manager.cpp new file mode 100644 index 00000000000..e6f12f6c939 --- /dev/null +++ b/ACE/examples/Threads/thread_manager.cpp @@ -0,0 +1,108 @@ +// $Id$ + +// Test out the group management mechanisms provided by the +// ACE_Thread_Manager, including the group signal handling, group +// suspension and resumption, and cooperative thread cancellation +// mechanisms. + +#include "ace/OS_NS_unistd.h" +#include "ace/OS_main.h" +#include "ace/Service_Config.h" +#include "ace/Thread_Manager.h" +#include "ace/Signal.h" + +ACE_RCSID(Threads, thread_manager, "$Id$") + +#if defined (ACE_HAS_THREADS) + +extern "C" void +handler (int signum) +{ + ACE_DEBUG ((LM_DEBUG, "(%t) received signal %d\n", signum)); +} + +static void * +worker (int iterations) +{ + for (int i = 0; i < iterations; i++) + { + if ((i % 1000) == 0) + { + ACE_DEBUG ((LM_DEBUG, + "(%t) checking cancellation before iteration %d!\n", + i)); + + if (ACE_Thread_Manager::instance ()->testcancel (ACE_Thread::self ()) != 0) + { + ACE_DEBUG ((LM_DEBUG, + "(%t) has been cancelled before iteration %d!\n", + i)); + break; + } + } + } + + // Destructor removes thread from Thread_Manager. + return 0; +} + +static const int DEFAULT_THREADS = ACE_DEFAULT_THREADS; +static const int DEFAULT_ITERATIONS = 100000; + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + ACE_Service_Config daemon; + + daemon.open (argv[0]); + + // Register a signal handler. + ACE_Sig_Action sa ((ACE_SignalHandler) handler, SIGINT); + ACE_UNUSED_ARG (sa); + + int n_threads = argc > 1 ? ACE_OS::atoi (argv[1]) : DEFAULT_THREADS; + int n_iterations = argc > 2 ? ACE_OS::atoi (argv[2]) : DEFAULT_ITERATIONS; + + ACE_Thread_Manager *thr_mgr = ACE_Thread_Manager::instance (); + + int grp_id = thr_mgr->spawn_n (n_threads, ACE_THR_FUNC (worker), + reinterpret_cast<void *> (n_iterations), + THR_NEW_LWP | THR_DETACHED); + + // Wait for 1 second and then suspend every thread in the group. + ACE_OS::sleep (1); + ACE_DEBUG ((LM_DEBUG, "(%t) suspending group\n")); + if (thr_mgr->suspend_grp (grp_id) == -1) + ACE_ERROR ((LM_DEBUG, "(%t) %p\n", "suspend_grp")); + + // Wait for 1 more second and then resume every thread in the + // group. + ACE_OS::sleep (ACE_Time_Value (1)); + ACE_DEBUG ((LM_DEBUG, "(%t) resuming group\n")); + if (thr_mgr->resume_grp (grp_id) == -1) + ACE_ERROR ((LM_DEBUG, "(%t) %p\n", "resume_grp")); + + // Wait for 1 more second and then send a SIGINT to every thread in + // the group. + ACE_OS::sleep (ACE_Time_Value (1)); + ACE_DEBUG ((LM_DEBUG, "(%t) signaling group\n")); + if (thr_mgr->kill_grp (grp_id, SIGINT) == -1) + ACE_ERROR ((LM_DEBUG, "(%t) %p\n", "kill_grp")); + + // Wait for 1 more second and then cancel all the threads. + ACE_OS::sleep (ACE_Time_Value (1)); + ACE_DEBUG ((LM_DEBUG, "(%t) cancelling group\n")); + if (thr_mgr->cancel_grp (grp_id) == -1) + ACE_ERROR ((LM_DEBUG, "(%t) %p\n", "cancel_grp")); + + // Perform a barrier wait until all the threads have shut down. + thr_mgr->wait (); + return 0; +} +#else +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_ERROR_RETURN ((LM_ERROR, "threads not supported on this platform\n"), -1); +} +#endif /* ACE_HAS_THREADS */ diff --git a/ACE/examples/Threads/thread_pool.cpp b/ACE/examples/Threads/thread_pool.cpp new file mode 100644 index 00000000000..cab0699f428 --- /dev/null +++ b/ACE/examples/Threads/thread_pool.cpp @@ -0,0 +1,268 @@ +// $Id$ + +// This test program illustrates how the <ACE_Task> synchronization +// mechanisms work in conjunction with the <ACE_Thread_Manager>. If +// the <manual> flag is set input comes from stdin until the user +// enters a return -- otherwise, the input is generated automatically. +// All worker threads shutdown when they receive a message block of +// length 0. +// +// This code is original based on a test program written by Karlheinz +// Dorn <Karlheinz.Dorn@med.siemens.de>. It was modified to utilize +// more ACE features by Doug Schmidt <schmidt@cs.wustl.edu>. + +#include "ace/OS_NS_stdio.h" +#include "ace/OS_NS_string.h" +#include "ace/OS_NS_unistd.h" +#include "ace/OS_main.h" +#include "ace/Task.h" +#include "ace/Service_Config.h" + +ACE_RCSID(Threads, thread_pool, "$Id$") + +#if defined (ACE_HAS_THREADS) + +// Default number of iterations to run the test. +static int n_iterations = 100; + +// Controls whether the input is generated "manually" or automatically. +static int manual = 0; + +class Thread_Pool : public ACE_Task<ACE_MT_SYNCH> +{ + // = TITLE + // Defines a thread pool abstraction based on the <ACE_Task>. +public: + Thread_Pool (ACE_Thread_Manager *thr_mgr, + int n_threads); + // Constructor activates <n_threads> in the thread pool. + + ~Thread_Pool (void); + // Destructor... + + virtual int svc (void); + // Iterate <n_iterations> time printing off a message and "waiting" + // for all other threads to complete this iteration. + + virtual int put (ACE_Message_Block *mb, + ACE_Time_Value *tv = 0); + // This allows the producer to pass messages to the <Thread_Pool>. + +private: + virtual int close (u_long); + // Close hook. +}; + +int +Thread_Pool::close (u_long) +{ + ACE_DEBUG ((LM_DEBUG, + "(%t) worker thread closing down\n")); + return 0; +} + +Thread_Pool::Thread_Pool (ACE_Thread_Manager *thr_mgr, + int n_threads) + : ACE_Task<ACE_MT_SYNCH> (thr_mgr) +{ + // Create the pool of worker threads. + if (this->activate (THR_NEW_LWP, + n_threads) == -1) + ACE_ERROR ((LM_ERROR, + "%p\n", + "activate failed")); +} + +Thread_Pool::~Thread_Pool (void) +{ +} + +// Simply enqueue the Message_Block into the end of the queue. + +int +Thread_Pool::put (ACE_Message_Block *mb, + ACE_Time_Value *tv) +{ + return this->putq (mb, tv); +} + +// Iterate <n_iterations> time printing off a message and "waiting" +// for all other threads to complete this iteration. + +int +Thread_Pool::svc (void) +{ + // Note that the <ACE_Task::svc_run> method automatically adds us to + // the Thread_Manager when the thread begins. + + int count = 1; + + // Keep looping, reading a message out of the queue, until we get a + // message with a length == 0, which signals us to quit. + + for (;; count++) + { + ACE_Message_Block *mb; + + ACE_DEBUG ((LM_DEBUG, + "(%t) in iteration %d before getq ()\n", + count)); + + if (this->getq (mb) == -1) + { + ACE_ERROR ((LM_ERROR, + "(%t) in iteration %d, got result -1, exiting\n", + count)); + break; + } + + size_t length = mb->length (); + + if (length > 0) + ACE_DEBUG ((LM_DEBUG, + "(%t) in iteration %d, length = %d, text = \"%*s\"\n", + count, + length, + length - 1, + mb->rd_ptr ())); + + // We're responsible for deallocating this. + mb->release (); + + if (length == 0) + { + ACE_DEBUG ((LM_DEBUG, + "(%t) in iteration %d, got NULL message, exiting\n", + count)); + break; + } + } + + // Note that the <ACE_Task::svc_run> method automatically removes us + // from the <ACE_Thread_Manager> when the thread exits. + return 0; +} + +static void +producer (Thread_Pool &thread_pool) +{ + ACE_DEBUG ((LM_DEBUG, + "(%t) producer start, generating data for the <Thread_Pool>\n")); + // thread_pool.dump (); + + for (int n; ;) + { + // Allocate a new message. + ACE_Message_Block *mb = 0; + ACE_NEW (mb, + ACE_Message_Block (BUFSIZ)); + + if (manual) + { + ACE_DEBUG ((LM_DEBUG, + "(%t) enter a new message for the task pool...")); + n = ACE_OS::read (ACE_STDIN, + mb->rd_ptr (), + mb->size ()); + } + else + { + static int count = 0; + + ACE_OS::sprintf (mb->rd_ptr (), + "%d\n", + count); + n = ACE_OS::strlen (mb->rd_ptr ()); + + if (count == n_iterations) + n = 1; // Indicate that we need to shut down. + else + count++; + + if (count == 0 || (count % 20 == 0)) + ACE_OS::sleep (1); + } + + if (n > 1) + { + // Send a normal message to the waiting threads and continue + // producing. + mb->wr_ptr (n); + + // Pass the message to the Thread_Pool. + if (thread_pool.put (mb) == -1) + ACE_ERROR ((LM_ERROR, + " (%t) %p\n", + "put")); + } + else + { + ACE_DEBUG ((LM_DEBUG, + "\n(%t) start loop, dump of task:\n")); + // thread_pool.dump (); + + // Send a shutdown message to the waiting threads and exit. + for (size_t i = thread_pool.thr_count (); i > 0; i--) + { + ACE_DEBUG ((LM_DEBUG, + "(%t) EOF, enqueueing NULL block for thread = %d\n", + i)); + + // Enqueue a NULL message to flag each consumer to + // shutdown. + ACE_Message_Block *mb = 0; + ACE_NEW (mb, + ACE_Message_Block); + if (thread_pool.put (mb) == -1) + ACE_ERROR ((LM_ERROR, + " (%t) %p\n", + "put")); + } + + ACE_DEBUG ((LM_DEBUG, + "\n(%t) end loop\n")); + // thread_pool.dump (); + break; + } + } +} + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + int n_threads = argc > 1 ? ACE_OS::atoi (argv[1]) : ACE_DEFAULT_THREADS; + n_iterations = argc > 2 ? ACE_OS::atoi (argv[2]) : n_iterations; + manual = argc > 3 ? 1 : 0; + + ACE_DEBUG ((LM_DEBUG, + "(%t) argc = %d, threads = %d\n", + argc, + n_threads)); + + // Create the worker tasks. + Thread_Pool thread_pool (ACE_Thread_Manager::instance (), + n_threads); + + // Create work for the worker tasks to process in their own threads. + producer (thread_pool); + + ACE_DEBUG ((LM_DEBUG, + "(%t) waiting for threads to exit in Thread_Pool destructor...\n")); + // Wait for all the threads to reach their exit point. + if (thread_pool.wait () == -1) + ACE_ERROR_RETURN ((LM_ERROR, "(%t) wait() failed\n"), + 1); + + ACE_DEBUG ((LM_DEBUG, + "(%t) destroying worker tasks and exiting...\n")); + return 0; +} +#else +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_ERROR ((LM_ERROR, + "threads not supported on this platform\n")); + return 0; +} +#endif /* ACE_HAS_THREADS */ diff --git a/ACE/examples/Threads/thread_specific.cpp b/ACE/examples/Threads/thread_specific.cpp new file mode 100644 index 00000000000..04cb3d94627 --- /dev/null +++ b/ACE/examples/Threads/thread_specific.cpp @@ -0,0 +1,228 @@ +// $Id$ + +#include "ace/OS_NS_stdio.h" +#include "ace/OS_NS_unistd.h" +#include "ace/OS_main.h" +#include "ace/Service_Config.h" +#include "ace/Thread_Manager.h" +#include "ace/Signal.h" + +ACE_RCSID(Threads, thread_specific, "$Id$") + +#if defined (ACE_HAS_THREADS) + +#include "thread_specific.h" + +// Static variables. +ACE_MT (ACE_Thread_Mutex Errno::lock_); +int Errno::flags_; + +// This is our thread-specific error handler... +static ACE_TSS<Errno> tss_error; + +// Serializes output via cout. +static ACE_SYNCH_MUTEX printf_lock; + +#if defined (ACE_HAS_THREADS) +typedef ACE_TSS_Guard<ACE_Thread_Mutex> GUARD; +#else +typedef ACE_Guard<ACE_Null_Mutex> GUARD; +#endif /* ACE_HAS_THREADS */ + +extern "C" void +cleanup (void *ptr) +{ + ACE_DEBUG ((LM_DEBUG, + "(%t) in cleanup, ptr = %x\n", + ptr)); + + delete reinterpret_cast<char *> (ptr); +} + +// This worker function is the entry point for each thread. + +static void * +worker (void *c) +{ + // Cast the arg to a long, first, because a pointer is the same size + // as a long on all current ACE platforms. + int count = (int) (long) c; + + ACE_thread_key_t key = ACE_OS::NULL_key; + int *ip = 0; + + // Make one key that will be available when the thread exits so that + // we'll have something to cleanup! + + if (ACE_Thread::keycreate (&key, cleanup) == -1) + ACE_ERROR ((LM_ERROR, + "(%t) %p\n", + "ACE_Thread::keycreate")); + + ACE_NEW_RETURN (ip, + int, + 0); + + if (ACE_Thread::setspecific (key, (void *) ip) == -1) + ACE_ERROR ((LM_ERROR, + "(%t) %p\n", + "ACE_Thread::setspecific")); + + for (int i = 0; i < count; i++) + { + if (ACE_Thread::keycreate (&key, cleanup) == -1) + ACE_ERROR ((LM_ERROR, + "(%t) %p\n", + "ACE_Thread::keycreate")); + + ACE_NEW_RETURN (ip, + int, + 0); + + ACE_DEBUG ((LM_DEBUG, + "(%t) in worker 1, key = %d, ip = %x\n", + key, + ip)); + + if (ACE_Thread::setspecific (key, (void *) ip) == -1) + ACE_ERROR ((LM_ERROR, + "(%t) %p\n", + "ACE_Thread::setspecific")); + + if (ACE_Thread::getspecific (key, (void **) &ip) == -1) + ACE_ERROR ((LM_ERROR, + "(%t) %p\n", + "ACE_Thread::setspecific")); + + if (ACE_Thread::setspecific (key, (void *) 0) == -1) + ACE_ERROR ((LM_ERROR, + "(%t) %p\n", + "ACE_Thread::setspecific")); + delete ip; + + if (ACE_Thread::keyfree (key) == -1) + ACE_ERROR ((LM_ERROR, + "(%t) %p\n", + "ACE_Thread::keyfree")); + + // Cause an error. + ACE_OS::read (ACE_INVALID_HANDLE, 0, 0); + + // The following two lines set the thread-specific state. + tss_error->error (errno); + tss_error->line (__LINE__); + + // This sets the static state (note how C++ makes it easy to do + // both). + tss_error->flags (count); + + { + ACE_hthread_t handle; + ACE_Thread::self (handle); + + // Use the guard to serialize access to printf... + ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, printf_lock, 0); + +#if defined(linux) || defined(__OpenBSD__) + // @@ Normally the platform specific way to print a thread ID + // is encapsulated in Log_Msg.cpp, but for this small example + // we cannot (or do not want to) use ACE_Log_Msg. + ACE_OS::printf ("(%lu)", (unsigned long)handle); +#else + ACE_OS::printf ("(%u)", handle); +#endif /* ! linux */ + ACE_OS::printf (" errno = %d, lineno = %d, flags = %d\n", + tss_error->error (), + tss_error->line (), + tss_error->flags ()); + } + key = ACE_OS::NULL_key; + + if (ACE_Thread::keycreate (&key, cleanup) == -1) + ACE_ERROR ((LM_ERROR, + "(%t) %p\n", + "ACE_Thread::keycreate")); + + ACE_NEW_RETURN (ip, + int, + 0); + + ACE_DEBUG ((LM_DEBUG, + "(%t) in worker 2, key = %d, ip = %x\n", + key, + ip)); + + if (ACE_Thread::setspecific (key, (void *) ip) == -1) + ACE_ERROR ((LM_ERROR, + "(%t) %p\n", + "ACE_Thread::setspecific")); + + if (ACE_Thread::getspecific (key, (void **) &ip) == -1) + ACE_ERROR ((LM_ERROR, + "(%t) %p\n", + "ACE_Thread::setspecific")); + + if (ACE_Thread::setspecific (key, (void *) 0) == -1) + ACE_ERROR ((LM_ERROR, + "(%t) %p\n", + "ACE_Thread::setspecific")); + delete ip; + + if (ACE_Thread::keyfree (key) == -1) + ACE_ERROR ((LM_ERROR, + "(%t) %p\n", + "ACE_Thread::keyfree")); + } + + ACE_DEBUG ((LM_DEBUG, + "(%t) exiting\n")); + return 0; +} + +extern "C" void +handler (int signum) +{ + ACE_DEBUG ((LM_DEBUG, + "signal = %S\n", signum)); + ACE_Thread_Manager::instance ()->exit (0); +} + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + // The Service_Config must be the first object defined in main... + ACE_Service_Config daemon (argv[0]); + + int threads = argc > 1 ? ACE_OS::atoi (argv[1]) : 4; + int count = argc > 2 ? ACE_OS::atoi (argv[2]) : 10000; + + // Register a signal handler. + ACE_Sig_Action sa ((ACE_SignalHandler) (handler), SIGINT); + ACE_UNUSED_ARG (sa); + +#if defined (ACE_HAS_THREADS) + if (ACE_Thread_Manager::instance ()->spawn_n (threads, + ACE_THR_FUNC (&worker), + reinterpret_cast<void *> (count), + THR_BOUND | THR_DETACHED) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "ACE_Thread_Manager::spawn_n"), + -1); + + ACE_Thread_Manager::instance ()->wait (); +#else + worker ((void *) count); +#endif /* ACE_HAS_THREADS */ + return 0; +} + +#else +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_ERROR_RETURN ((LM_ERROR, + "ACE doesn't support support threads on this platform (yet)\n"), + -1); +} +#endif /* ACE_HAS_THREADS */ diff --git a/ACE/examples/Threads/thread_specific.h b/ACE/examples/Threads/thread_specific.h new file mode 100644 index 00000000000..1ae48ee114f --- /dev/null +++ b/ACE/examples/Threads/thread_specific.h @@ -0,0 +1,53 @@ +// $Id$ + +#ifndef ACE_THREAD_SPECIFIC_H + +#include "ace/Guard_T.h" +#include "ace/Thread_Mutex.h" + +// Define a class that will be stored in thread-specific data. Note +// that as far as this class is concerned it's just a regular C++ +// class. The ACE_TSS wrapper transparently ensures that objects of +// this class will be placed in thread-specific storage. All calls on +// ACE_TSS::operator->() are delegated to the appropriate method in +// the Errno class. + +class Errno +{ +public: + int error (void) { return this->errno_; } + void error (int i) { this->errno_ = i; } + + int line (void) { return this->lineno_; } + void line (int l) { this->lineno_ = l; } + + // Errno::flags_ is a static variable, so we've got to protect it + // with a mutex since it isn't kept in thread-specific storage. + int flags (void) + { + ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, Errno::lock_, -1); + + return Errno::flags_; + } + + void flags (int f) + { + ACE_GUARD (ACE_Thread_Mutex, ace_mon, Errno::lock_); + + Errno::flags_ = f; + } + +private: + // = errno_ and lineno_ will be thread-specific data so they don't + // need a lock. + int errno_; + int lineno_; + + static int flags_; +#if defined (ACE_HAS_THREADS) + // flags_ needs a lock. + static ACE_Thread_Mutex lock_; +#endif /* ACE_HAS_THREADS */ +}; + +#endif /* ACE_THREAD_SPECIFIC_H */ diff --git a/ACE/examples/Threads/token.cpp b/ACE/examples/Threads/token.cpp new file mode 100644 index 00000000000..bbda579369b --- /dev/null +++ b/ACE/examples/Threads/token.cpp @@ -0,0 +1,78 @@ +// $Id$ + +// Test out the ACE Token class. + +#include "ace/OS_main.h" +#include "ace/Token.h" +#include "ace/Task.h" +#include "ace/OS_NS_time.h" + +ACE_RCSID(Threads, token, "$Id$") + +#if defined (ACE_HAS_THREADS) + +class My_Task : public ACE_Task<ACE_MT_SYNCH> +{ +public: + My_Task (int n); + virtual int svc (void); + + static void sleep_hook (void *); + +private: + ACE_Token token_; +}; + +My_Task::My_Task (int n) +{ + // Make this Task into an Active Object. + this->activate (THR_BOUND | THR_DETACHED, n); + + // Wait for all the threads to exit. + this->thr_mgr ()->wait (); +} + +void +My_Task::sleep_hook (void *) +{ + ACE_DEBUG ((LM_ERROR, "(%u) blocking, My_Task::sleep_hook () called\n", + ACE_Thread::self())) ; +} + +// Test out the behavior of the ACE_Token class. + +int +My_Task::svc (void) +{ + for (size_t i = 0; i < 100; i++) + { + // Wait for up to 1 millisecond past the current time to get the token. + ACE_Time_Value timeout (ACE_OS::time (0), 1000); + + if (this->token_.acquire (&My_Task::sleep_hook, 0, &timeout) == 1) + { + this->token_.acquire (); + this->token_.renew (); + this->token_.release (); + this->token_.release (); + } + else + ACE_Thread::yield (); + } + return 0; +} + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + My_Task tasks (argc > 1 ? ACE_OS::atoi (argv[1]) : 4); + + return 0; +} +#else +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_ERROR_RETURN ((LM_ERROR, "your platform doesn't support threads\n"), -1); +} +#endif /* */ diff --git a/ACE/examples/Threads/tss1.cpp b/ACE/examples/Threads/tss1.cpp new file mode 100644 index 00000000000..783d4dc5b7a --- /dev/null +++ b/ACE/examples/Threads/tss1.cpp @@ -0,0 +1,157 @@ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// tests +// +// = FILENAME +// TSS_Test.cpp +// +// = DESCRIPTION +// This program tests thread specific storage of data. The ACE_TSS +// wrapper transparently ensures that the objects of this class +// will be placed in thread-specific storage. All calls on +// ACE_TSS::operator->() are delegated to the appropriate method +// in the Errno class. Note that each thread of control has its +// own unique TSS object. +// +// = AUTHOR +// Detlef Becker <Detlef.Becker@med.siemens.de> +// +// ============================================================================ + +#include "ace/OS_main.h" +#include "ace/Service_Config.h" +#include "ace/Task.h" + +ACE_RCSID(Threads, tss1, "$Id$") + +#if defined (ACE_HAS_THREADS) + +#include "thread_specific.h" + +// (Sun C++ 4.2 with -O3 won't link if the following is not const.) +static const int iterations = 100; + +// Static variables. +ACE_MT (ACE_Thread_Mutex Errno::lock_); +int Errno::flags_; + +// This is our thread-specific error handler... +// (Sun C++ 4.2 with -O3 won't link if the following is static.) +ACE_TSS<Errno> TSS_Error; + +#if defined (ACE_HAS_THREADS) + typedef ACE_TSS_Guard<ACE_Thread_Mutex> GUARD; +#else + typedef ACE_Guard<ACE_Null_Mutex> GUARD; +#endif /* ACE_HAS_THREADS */ + +// Keeps track of whether Tester::close () has started. +// (Sun C++ 4.2 with -O3 won't link if the following is static.) +int close_started = 0; + +template <ACE_SYNCH_DECL> +class Tester: public ACE_Task<ACE_SYNCH_USE> +{ +public: + Tester (void) {} + ~Tester (void) {} + + virtual int svc (void); + + virtual int open (void *args = 0); + // Activate the thread. + + virtual int close (u_long args = 0); +}; + +template <ACE_SYNCH_DECL> int +Tester<ACE_SYNCH_USE>::svc (void) +{ + ACE_DEBUG ((LM_DEBUG, + "(%t) svc: setting error code to 1\n")); + TSS_Error->error (1); + + for (int i = 0; i < iterations; i++) + // Print out every tenth iteration. + if ((i % 10) == 1) + ACE_DEBUG ((LM_DEBUG, + "(%t) error = %d\n", + TSS_Error->error ())); + this->close (); + + return 0; +} + +template <ACE_SYNCH_DECL> int +Tester<ACE_SYNCH_USE>::open (void *) +{ + // Make this an Active Object. + return this->activate (); +} + +template <ACE_SYNCH_DECL> +int Tester<ACE_SYNCH_USE>::close (u_long) +{ + ACE_DEBUG ((LM_DEBUG, + "(%t) close running\n")); + close_started = 1; + ACE_DEBUG ((LM_DEBUG, + "(%t) close: setting error code to 7\n")); + TSS_Error->error (7); + ACE_DEBUG ((LM_DEBUG, + "(%t) close: error = %d\n", + TSS_Error->error ())); + //close_started = 0; + return 0; +} + +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + Tester<ACE_MT_SYNCH> tester; + + ACE_DEBUG ((LM_DEBUG, + "(%t) main: setting error code to 3\n")); + TSS_Error->error (3); + ACE_DEBUG ((LM_DEBUG, + "(%t) main: error = %d\n", + TSS_Error->error ())); + + // Spawn off a thread and make test an Active Object. + tester.open (); + + // Keep looping until <Tester::close> is called. + for (int i = 0; !close_started; i++) { + // while (!close_started) + if ((i % 100) == 0) { + ACE_DEBUG ((LM_DEBUG, + "(%t) error = %d\n", + TSS_Error->error ())); + } + } + ACE_DEBUG ((LM_DEBUG, + "(%t) main: setting error code to 4\n")); + TSS_Error->error (4); + ACE_DEBUG ((LM_DEBUG, + "(%t) main: error = %d\n", + TSS_Error->error ())); + + // Keep looping until <Tester::close> finishes. + while (close_started != 0) + ACE_DEBUG ((LM_DEBUG, + "(%t) error = %d\n", + TSS_Error->error ())); + return 0; +} +#else +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_ERROR_RETURN ((LM_ERROR, + "ACE doesn't support support threads on this platform (yet)\n"), + -1); +} +#endif /* ACE_HAS_THREADS */ diff --git a/ACE/examples/Threads/tss2.cpp b/ACE/examples/Threads/tss2.cpp new file mode 100644 index 00000000000..0c7fb9ac3ee --- /dev/null +++ b/ACE/examples/Threads/tss2.cpp @@ -0,0 +1,190 @@ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// tests +// +// = FILENAME +// TSS_Test.cpp +// +// = DESCRIPTION +// This program tests various features of ACE_Thread and the +// thread-specific storage variant of <ACE_Singleton>. +// +// = AUTHOR +// Prashant Jain and Doug Schmidt +// +// ============================================================================ + +#include "ace/OS_main.h" +#include "ace/Thread.h" +#include "ace/Log_Msg.h" +#include "ace/Atomic_Op.h" +#include "TSS_Data.h" +#include "TSS_Obj.h" +#include "TSS_Task.h" + +ACE_RCSID(Threads, tss2, "$Id$") + +#if defined (ACE_HAS_THREADS) + +const int MAX_TASKS = 4; +const int MAX_ITERATIONS = 10; + +ACE_Atomic_Op<ACE_Token, int> Test_Task::count_ (0); +ACE_Atomic_Op<ACE_Token, int> Test_Task::wait_count_ (0); +ACE_Atomic_Op<ACE_Token, int> Test_Task::max_count_ (0); +int num_tasks = 0; + +// ACE synchronization object. +static ACE_Token token; + +ACE_Atomic_Op<ACE_Thread_Mutex, int> TSS_Obj::count_ = 0; + +TSS_Obj::TSS_Obj (void) +{ + TSS_Obj::count_++; + ACE_DEBUG ((LM_DEBUG, "(%t) TSS_Obj+: %d\n", TSS_Obj::count_.value ())); +} + +TSS_Obj::~TSS_Obj (void) +{ + TSS_Obj::count_--; + ACE_DEBUG ((LM_DEBUG, "(%t) TSS_Obj-: %d\n", TSS_Obj::count_.value ())); +} + +Test_Task::Test_Task (void) +{ + Test_Task::count_++; + ACE_DEBUG ((LM_DEBUG, + "(%t) Test_Task+: %d\n", Test_Task::count_.value ())); +} + +Test_Task::~Test_Task (void) +{ + Test_Task::count_--; + + ACE_DEBUG ((LM_DEBUG, + "(%t) Test_Task-: %d\n", Test_Task::count_.value ())); + Test_Task::wait_count_--; +} + +void * +Test_Task::svc (void *arg) +{ + // When the thread exits this thread-specific object will be deleted + // automatically. + ACE_TSS<TSS_Obj> tss (new TSS_Obj); + + TSS_DATA::instance ()->data (arg); + + Test_Task::wait_count_++; + Test_Task::max_count_++; + + ACE_DEBUG ((LM_DEBUG, "(%t) svc: waiting (data = %u)\n", + arg)); + + // Do a bunch of set operations on the TSS data just to make sure + // that it's truly in TSS (it it weren't, the assertion would fail). + + while (Test_Task::max_count_ < num_tasks) + { + TSS_DATA::instance ()->data (arg); + ACE_Thread::yield (); + } + + ACE_DEBUG ((LM_DEBUG, "(%t) svc: waiting finished (data = %u)\n", + arg)); + +#if 0 + ACE_ASSERT (TSS_DATA::instance ()->data () == arg); +#endif + + delete (Test_Task *) arg; + + return 0; +} + +int +Test_Task::open (void *arg) +{ + if (ACE_Thread::spawn ((ACE_THR_FUNC) Test_Task::svc, arg) == -1) + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "ACE_Thread::spawn"), 0); + + return 0; +} + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + num_tasks = argc > 1 ? ACE_OS::atoi (argv[1]) : MAX_TASKS; + + Test_Task **task_arr = 0; + + ACE_NEW_RETURN (task_arr, Test_Task *[num_tasks], -1); + + for (int i = 0; i < MAX_ITERATIONS; i++) + { + ACE_DEBUG ((LM_DEBUG, + "(%t) ********* iteration %d **********\n" + "Test_Task::max_count_ %d\n", + i, + Test_Task::max_count_.value ())); + Test_Task::max_count_ = 0; + + for (int j = 0; j < num_tasks; j++) + { + ACE_NEW_RETURN (task_arr[j], Test_Task, -1); + task_arr[j]->open (task_arr[j]); + } + + ACE_DEBUG ((LM_DEBUG, "(%t) waiting for first thread started\n")); + + for (;;) + { + ACE_Thread::yield (); + + if (Test_Task::max_count_ != 0 ) + break; + } + + ACE_DEBUG ((LM_DEBUG, "(%t) First thread started\n" + "Waiting for all threads finished\n")); + + for (;;) + { + if (!(Test_Task::max_count_ == num_tasks + && Test_Task::wait_count_ == 0)) + { + ACE_Thread::yield (); + continue; + } + ACE_DEBUG ((LM_DEBUG, + "(%t) Test_Task::max_count_ = %d," + " Test_Task::wait_count_ = %d", + Test_Task::max_count_.value (), + Test_Task::wait_count_.value ())); + break; + } + + ACE_DEBUG ((LM_DEBUG, "(%t) all threads finished\n")); + } + + return 0; +} + +#if defined (ACE_HAS_EXPLICIT_STATIC_TEMPLATE_MEMBER_INSTANTIATION) +template ACE_TSS_Singleton<TSS_Data, ACE_SYNCH_MUTEX> * + ACE_TSS_Singleton<TSS_Data, ACE_SYNCH_MUTEX>::singleton_; +#endif /* ACE_HAS_EXPLICIT_STATIC_TEMPLATE_MEMBER_INSTANTIATION */ + +#else + +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_ERROR ((LM_ERROR, "threads not supported on this platform\n")); + return 0; +} +#endif /* ACE_HAS_THREADS */ diff --git a/ACE/examples/Threads/wfmo.cpp b/ACE/examples/Threads/wfmo.cpp new file mode 100644 index 00000000000..bfd451444b1 --- /dev/null +++ b/ACE/examples/Threads/wfmo.cpp @@ -0,0 +1,132 @@ +// $Id$ + +// This test program illustrates that the Win32 +// <WaitForMultipleObjects> function can be called in multiple +// threads, all of which wait on the same set of HANDLEs. Note that +// the dispatching of the threads should be relatively "fair" (i.e., +// everyone gets a chance to process the various HANDLEs as they +// become active). Thanks to Ari Erev <Ari_Erev@comverse.com> for +// suggesting this and providing the initial code. + +#include "ace/Task.h" +#include "ace/OS_NS_unistd.h" +#include "ace/OS_main.h" + +ACE_RCSID(Threads, wfmo, "$Id$") + +#if defined (ACE_WIN32) + +// Number of threads. +static const int THREAD_COUNT = 5; + +// Number of iterations. +static const int MAX_ITERATIONS = 100; + +class WFMO_Test : public ACE_Task <ACE_NULL_SYNCH> +{ +public: + virtual int open (void *); + virtual int svc (void); + + // Use two handles here.. + ACE_sema_t sema_handles_[2]; + int semaphore_count_; +}; + +static WFMO_Test wfmo_test; + +int +WFMO_Test::open (void *arg) +{ + int thread_count = int (arg); + int result = this->activate (0, thread_count); + + ACE_ASSERT (result != -1); + return 0; +} + +int +WFMO_Test::svc (void) +{ + while(1) + { + int result = ::WaitForMultipleObjects (2, this->sema_handles_, + FALSE, INFINITE); + if (result == WAIT_OBJECT_0) + { + // Signal the other semaphore just to see if we can get + // another thread to wakeup. + result = ACE_OS::sema_post (&sema_handles_[1]); + ACE_ASSERT (result != -1); + } + else if (result == WAIT_OBJECT_0 + 1) + ; + else + { + ACE_ERROR ((LM_ERROR, "Error in WaitForMultipleObejcts\n")); + ACE_OS::exit (0); + } + + // semaphore_count_ will be displayed by the "main" thread. + // It's value must be 2. Note that although this is a shared + // resource it's not protected via a mutex because the ++ + // operation on Intel is atomic. + + semaphore_count_++; + ACE_DEBUG ((LM_DEBUG, + "(%t) thread has been signaled.\n")); + + // Yield this thread so that the other one(s) have a chance to + // run. + ACE_OS::thr_yield (); + } + + return 0; +} + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + int thread_count = THREAD_COUNT; + + if (argc > 1) + thread_count = ACE_OS::atoi (argv[1]); + + wfmo_test.open ((void *) thread_count); + + // Initialize the semaphores. + int result = ACE_OS::sema_init (&wfmo_test.sema_handles_[0], thread_count + 5); + ACE_ASSERT (result != -1); + + result = ACE_OS::sema_init (&wfmo_test.sema_handles_[1], thread_count + 5); + ACE_ASSERT (result != -1); + + for (int i = 0; i < MAX_ITERATIONS; i++) + { + wfmo_test.semaphore_count_ = 0; + + result = ACE_OS::sema_post (&wfmo_test.sema_handles_[0]); + ACE_ASSERT (result != -1); + + // No real synchronization here. Just sleep enough so that at + // least one (or two threads) run as a result of the semaphore. + ACE_OS::sleep (1); + + // Add one for the other thread that was signaled. + ACE_DEBUG ((LM_DEBUG, + "semaphore_count_ = %d (should have been %d).\n", + wfmo_test.semaphore_count_, + 2)); // Two semaphores should have been released. + } + + ACE_OS::exit (0); + + return 0; +} +#else +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_DEBUG ((LM_DEBUG, "this test only runs on Win32\n")); +} +#endif /* ACE_WIN32 */ diff --git a/ACE/examples/Timer_Queue/.cvsignore b/ACE/examples/Timer_Queue/.cvsignore new file mode 100644 index 00000000000..6f1917f64c8 --- /dev/null +++ b/ACE/examples/Timer_Queue/.cvsignore @@ -0,0 +1,3 @@ +Asynch_Timer_Queue_Test +Reactor_Timer_Queue_Test +Thread_Timer_Queue_Test diff --git a/ACE/examples/Timer_Queue/Async_Timer_Queue_Test.cpp b/ACE/examples/Timer_Queue/Async_Timer_Queue_Test.cpp new file mode 100644 index 00000000000..18d12b8017a --- /dev/null +++ b/ACE/examples/Timer_Queue/Async_Timer_Queue_Test.cpp @@ -0,0 +1,299 @@ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// examples +// +// = FILENAME +// Async_Timer_Queue_Test.cpp +// +// = DESCRIPTION +// This test exercises the <ACE_Asynch_Timer_Queue_Adapter> +// using an <ACE_Timer_Heap>. +// +// = AUTHORS +// Douglas C. Schmidt <schmidt@cs.wustl.edu> and +// Sergio Flores-Gaitan <sergio@cs.wustl.edu> +// +// ============================================================================ + +#include "ace/OS_NS_sys_time.h" +#include "ace/Signal.h" +#include "ace/Timer_Heap.h" +#include "ace/Timer_Queue_Adapters.h" + +#include "Async_Timer_Queue_Test.h" + +ACE_RCSID(Timer_Queue, Async_Timer_Queue_Test, "$Id$") + +// Hook method that is called to handle the expiration of a timer. +int +Async_Timer_Handler::handle_timeout (const ACE_Time_Value &tv, + const void *arg) +{ + // Print some information here (note that this is not strictly + // signal-safe since the ACE logging mechanism uses functions that + // aren't guaranteed to work in all signal handlers). + ACE_DEBUG ((LM_DEBUG, + "handle_timeout() = (%d, %d) %d\n", + tv.sec (), + tv.usec (), + arg)); + + // Commit suicide! + delete this; + return 0; +} + +// Initialize the Singleton pointer. +Async_Timer_Queue *Async_Timer_Queue::instance_ = 0; + +// Implement the Singleton logic. +Async_Timer_Queue * +Async_Timer_Queue::instance (void) +{ + if (Async_Timer_Queue::instance_ == 0) + { + // Initialize with all signals enabled. + ACE_Sig_Set ss (1); + + // But, don't block out SIGQUIT since we always want that + // signal to interrupt the program. + ss.sig_del (SIGQUIT); + + ACE_NEW_RETURN (Async_Timer_Queue::instance_, + Async_Timer_Queue (&ss), + 0); + } + return Async_Timer_Queue::instance_; +} + +// Sets the signal set to mask, for the timer queue. + +Async_Timer_Queue::Async_Timer_Queue (ACE_Sig_Set *ss) + : tq_ (ss) +{ +} + +// Dump the contents of the queue when we receive ^C. + +void +Async_Timer_Queue::dump (void) +{ + ACE_DEBUG ((LM_DEBUG, "begin dumping timer queue\n")); + + // This iterator is implicitly protected since SIGINT and SIGALRM + // signals cannot occur while it is running. + + for (ACE_Timer_Heap_Iterator iter (this->tq_.timer_queue ()); + iter.item () != 0; + iter.next ()) + iter.item ()->dump (); + + ACE_DEBUG ((LM_DEBUG, + "end dumping timer queue\n")); +} + +// Schedule a timer. + +void +Async_Timer_Queue::schedule (u_int microsecs) +{ + ACE_Time_Value tv (0, microsecs); + + // Create a new Event_Handler for our timer. + + ACE_Event_Handler *eh; + ACE_NEW (eh, + Async_Timer_Handler); + + // Schedule the timer to run in the future. + long tid = this->tq_.schedule + (eh, + 0, // Note that our "magic cookie" ACT is always NULL. + ACE_OS::gettimeofday () + tv); + + if (tid == -1) + ACE_ERROR ((LM_ERROR, + "%p\n", + "schedule_timer")); +} + +// Cancel a timer. + +void +Async_Timer_Queue::cancel (long timer_id) +{ + ACE_DEBUG ((LM_DEBUG, + "canceling %d\n", + timer_id)); + + const void *act = 0; + + if (this->tq_.cancel (timer_id, &act) == -1) + ACE_ERROR ((LM_ERROR, + "%p\n", + "cancel_timer")); + + // In this case, the act will be 0, but it could be a real pointer + // in other cases. + delete (ACE_Event_Handler *) act; +} + +// Schedule timer hook method. This method is called from the driver. + +int +Async_Timer_Queue::schedule_timer (void *argument) +{ + u_long useconds = *(int *)argument; + + // Schedule a timer. + Async_Timer_Queue::instance ()->schedule (useconds); + + return 0; +} + +// Cancel timer hook method. Is called from the driver class. + +int +Async_Timer_Queue::cancel_timer (void *argument) +{ + u_long id = *(int *)argument; + + // Cancel a timer. + Async_Timer_Queue::instance ()->cancel (id); + + return 0; +} + +// Dummy list timer hook method. The listing of timers is done from a +// signal handler using SIGINT, not from the driver. + +int +Async_Timer_Queue::list_timer (void *) +{ + // Display an error message. + ACE_ERROR_RETURN ((LM_ERROR, + "invalid input\n"), 0); +} + +// Dummy shutdown timer hook method. The shutdown of the timer queue +// is done with a signal handler using SIGQUIT, not from the driver. + +int +Async_Timer_Queue::shutdown_timer (void *) +{ + // Display an error message. + ACE_ERROR_RETURN ((LM_ERROR, + "invalid input\n"), + 0); +} + +// Handler for the SIGINT and SIGQUIT signals. + +static void +signal_handler (int signum) +{ + ACE_DEBUG ((LM_DEBUG, + "handling signal %S\n", + signum)); + + switch (signum) + { + case SIGINT: + Async_Timer_Queue::instance ()->dump (); + break; + /* NOTREACHED */ + + case SIGQUIT: + ACE_ERROR ((LM_ERROR, + "shutting down on SIGQUIT%a\n", + 1)); + /* NOTREACHED */ + break; + } +} + +// Register the signal handlers for SIGQUIT and SIGINT. We must +// ensure that the SIGINT handler isn't interrupted by SIGALRM. +// However, SIGQUIT is never blocked... + +static void +register_signal_handlers (void) +{ + // Register SIGQUIT (never blocked). + ACE_Sig_Action sigquit ((ACE_SignalHandler) signal_handler, + SIGQUIT); + ACE_UNUSED_ARG (sigquit); + + // Don't let the SIGALRM interrupt the SIGINT handler! + ACE_Sig_Set ss; + ss.sig_add (SIGALRM); + + // Register SIGINT (note that system calls will be restarted + // automatically). + ACE_Sig_Action sigint ((ACE_SignalHandler) signal_handler, + SIGINT, + ss, + SA_RESTART); + ACE_UNUSED_ARG (sigint); +} + +// constructor + +Async_Timer_Queue_Test_Driver::Async_Timer_Queue_Test_Driver (void) +{ +} + +// displays the menu of options. + +int +Async_Timer_Queue_Test_Driver::display_menu (void) +{ + // The menu of options provided to the user. + static char menu[] = + "****\n" + "1) schedule timer <usecs> \n" + "2) cancel timer <timer_id>\n" + "^C list timers\n" + "^\\ exit program\n"; + + ACE_DEBUG ((LM_DEBUG, + "%s", + menu)); + return 0; +} + +// Initializes the test driver. + +int +Async_Timer_Queue_Test_Driver::init (void) +{ + typedef Command<Async_Timer_Queue, Async_Timer_Queue::ACTION> CMD; + + // Initialize <Command> objects with their corresponding <Input_Task> methods. + ACE_NEW_RETURN (schedule_cmd_, + CMD (*Async_Timer_Queue::instance (), + &Async_Timer_Queue::schedule_timer), + -1); + + ACE_NEW_RETURN (cancel_cmd_, + CMD (*Async_Timer_Queue::instance (), + &Async_Timer_Queue::cancel_timer), + -1); + + ACE_NEW_RETURN (list_cmd_, + CMD (*Async_Timer_Queue::instance (), + &Async_Timer_Queue::list_timer), + -1); + + ACE_NEW_RETURN (shutdown_cmd_, + CMD (*Async_Timer_Queue::instance (), + &Async_Timer_Queue::shutdown_timer), + -1); + + register_signal_handlers (); + + return 0; +} diff --git a/ACE/examples/Timer_Queue/Async_Timer_Queue_Test.h b/ACE/examples/Timer_Queue/Async_Timer_Queue_Test.h new file mode 100644 index 00000000000..6b166f894c3 --- /dev/null +++ b/ACE/examples/Timer_Queue/Async_Timer_Queue_Test.h @@ -0,0 +1,119 @@ +/* -*- C++ -*- */ + +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// examples +// +// = FILENAME +// Async_Timer_Queue_Test.h +// +// = DESCRIPTION +// This test exercises the <ACE_Asynch_Timer_Queue_Adapter> +// using an <ACE_Timer_Heap>. +// +// = AUTHORS +// Douglas C. Schmidt and +// Sergio Flores-Gaitan +// ============================================================================ + +#ifndef _ASYNC_TIMER_QUEUE_TEST_H_ +#define _ASYNC_TIMER_QUEUE_TEST_H_ + +#include "ace/Signal.h" +#include "ace/svc_export.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Timer_Heap.h" +#include "ace/Timer_Queue_Adapters.h" + +#include "Driver.h" + +class Async_Timer_Handler : public ACE_Event_Handler +{ + // = TITLE + // Target of the asynchronous timeout operation. +public: + virtual int handle_timeout (const ACE_Time_Value &tv, + const void *arg); + // Callback hook invoked by the <Timer_Queue>. +}; + +class Async_Timer_Queue +{ + // = TITLE + // Asynchronous Timer Queue Singleton. + // + // = DESCRIPTION + // We use this class to avoid global variables and to + // consolidate all the Timer Queue processing in one central + // place. +public: + typedef int (Async_Timer_Queue::*ACTION) (void *); + + static Async_Timer_Queue *instance (void); + // Singleton access point. + + void schedule (u_int microsecs); + // Schedule a timer to expire <microsecs> in the future. + + void cancel (long timer_id); + // Cancel a timer with <timer_id>. + + void dump (void); + // Dump the contents of the queue. + + int schedule_timer (void *argument); + // hook method to schedule a timer. Called from + // <Timer_Queue_Test_Driver> + + int cancel_timer (void *argument); + // hook method to cancel a timer. Called from + // <Timer_Queue_Test_Driver> + + int list_timer (void *argument); + // hook method to list timers. Called from + // <Timer_Queue_Test_Driver> + + int shutdown_timer (void *argument); + // hook method to exit the timer queue. Called from + // <Timer_Queue_Test_Driver> + +private: + Async_Timer_Queue (ACE_Sig_Set *); + // Private constructor enforces the Singleton. + + static Async_Timer_Queue *instance_; + // Pointer to the timer queue. + + ACE_Async_Timer_Queue_Adapter<ACE_Timer_Heap> tq_; + // The adapter is instantiated by an <ACE_Timer_Heap>. +}; + +class ACE_Svc_Export Async_Timer_Queue_Test_Driver : public Timer_Queue_Test_Driver <Async_Timer_Queue *, Async_Timer_Queue, Async_Timer_Queue::ACTION> +{ + // = TITLE + // Async_Timer_Queue_Test_Driver + // + // = DESCRIPTION + // This class implements a test driver for the + // <Async_Timer_Queue>. Implements a display_menu() method that + // prints the options for a user. and init() which initializes + // the driver. The rest of the common functionality is in the + // parent class <Timer_Queue_Test_Driver>. +public: + Async_Timer_Queue_Test_Driver (void); + + virtual int display_menu (void); + // Print menu of options. + + virtual int init (void); + // Initializes the driver's internal variables inherited from the parent +}; + +#endif /* _ASYNC_TIMER_QUEUE_TEST_H_ */ diff --git a/ACE/examples/Timer_Queue/Driver.cpp b/ACE/examples/Timer_Queue/Driver.cpp new file mode 100644 index 00000000000..ca549b1f952 --- /dev/null +++ b/ACE/examples/Timer_Queue/Driver.cpp @@ -0,0 +1,164 @@ +// $Id$ + +// ============================================================================ +// = LIBRARY +// examples +// +// = FILENAME +// Driver.cpp +// +// = DESCRIPTION +// This code builds an abstraction to factor out common code for +// the different implementations of the Timer_Queue. +// +// = AUTHOR +// Douglas Schmidt <schmidt@cs.wustl.edu> && +// Sergio Flores-Gaitan <sergio@cs.wustl.edu> +// +// ============================================================================ + +#if !defined (_DRIVER_CPP_) +#define _DRIVER_CPP_ + +#include "ace/OS_NS_stdio.h" +#include "ace/OS_NS_string.h" +#include "ace/OS_NS_unistd.h" +#include "ace/Auto_Ptr.h" +#include "Driver.h" + +ACE_RCSID(Timer_Queue, Driver, "$Id$") + +// constructor + +template <class RECEIVER, class ACTION> +Command<RECEIVER, ACTION>::Command (RECEIVER &recvr, + ACTION action) + : receiver_ (recvr), + action_ (action) +{ +} + +// destructor +template <class RECEIVER, class ACTION> +Command<RECEIVER, ACTION>::~Command (void) +{ +} + +// invokes an operation. + +template <class RECEIVER, class ACTION> int +Command<RECEIVER, ACTION>::execute (void *arg) +{ + return (receiver_.*action_) (arg); +} + +// gets the next request from the user input. + +template <class TQ, class RECEIVER, class ACTION> +Timer_Queue_Test_Driver<TQ, RECEIVER, ACTION>::~Timer_Queue_Test_Driver (void) +{ +} + +template <class TQ, class RECEIVER, class ACTION> int +Timer_Queue_Test_Driver<TQ, RECEIVER, ACTION>::get_next_request (void) +{ + char buf[BUFSIZ]; + + this->display_menu (); + + ACE_OS::printf ("please enter your choice: "); + ACE_OS::fflush (stdout); + + // reads input from the user + if (this->read_input (buf, sizeof buf) <= 0) + return -1; + + // Parse and run the command. + return this->parse_commands (buf); +} + +// Runs the test. + +template <class TQ, class RECEIVER, class ACTION> int +Timer_Queue_Test_Driver<TQ, RECEIVER, ACTION>::run_test (void) +{ + this->init (); + + for (;;) + if (this->get_next_request () == -1) + return -1; + + ACE_NOTREACHED (return 0); +} + +// Reads input from the user from ACE_STDIN into the buffer specified. + +template <class TQ, class RECEIVER, class ACTION> ssize_t +Timer_Queue_Test_Driver<TQ, RECEIVER, ACTION>::read_input (char *buf, size_t bufsiz) +{ + ACE_OS::memset (buf, 0, bufsiz); + + // Wait for user to type commands. This call is automatically + // restarted when SIGINT or SIGALRM signals occur. + return ACE_OS::read (ACE_STDIN, buf, bufsiz); +} + +// Parse the input and executes the corresponding operation + +template <class TQ, class RECEIVER, class ACTION> int +Timer_Queue_Test_Driver<TQ, RECEIVER, ACTION>::parse_commands (const char *buf) +{ + int option; + + if (::sscanf (buf, "%d", &option) <= 0) + // If there was an error reading the option simply try on the next line. + return 0; + + switch (option) + { + case 1: // Schedule a new timer. + { + u_long useconds; + // We just reread the option, this simplies parsing (since + // sscanf can do it for us.) + if (::sscanf (buf, "%d %lu", &option, &useconds) < 2) + return 0; + + if (schedule_cmd_->execute ((void *) &useconds) == -1) + ACE_ERROR_RETURN ((LM_ERROR, "%t %p\n", "new timer failed"), -1); + } + break; // Cancel an existing timer. + /* NOTREACHED */ + case 2: + { + u_long id; + // We just reread the option, this simplies parsing (since + // sscanf can do it for us.) + if (::sscanf (buf, "%d %lu", &option, &id) < 2) + return 0; + + if (cancel_cmd_->execute ((void *) &id) == -1) + ACE_DEBUG ((LM_DEBUG, "Timer #%d is not valid\n", id)); + + } + break; + /* NOTREACHED */ + + case 3: // Dump the existing timers. + return list_cmd_->execute (NULL); + /* NOTREACHED */ + + case 4: // Exit the program. + return shutdown_cmd_->execute (NULL); + /* NOTREACHED */ + + default: + // Display an error message. + ACE_ERROR_RETURN ((LM_ERROR, "invalid input %s\n", buf), 0); + ACE_NOTREACHED (break); + /* NOTREACHED */ + } + return 0; +} + +#endif /* _DRIVER_CPP_ */ diff --git a/ACE/examples/Timer_Queue/Driver.h b/ACE/examples/Timer_Queue/Driver.h new file mode 100644 index 00000000000..4677b904982 --- /dev/null +++ b/ACE/examples/Timer_Queue/Driver.h @@ -0,0 +1,137 @@ +/* -*- C++ -*- */ + +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// examples +// +// = FILENAME +// Driver.h +// +// = DESCRIPTION +// This code builds an abstraction to factor out common code for +// the different implementations of the Timer_Queue. +// +// = AUTHORS +// Sergio Flores-Gaitan <sergio@cs.wustl.edu> +// +// ============================================================================ + +#ifndef _DRIVER_H_ +#define _DRIVER_H_ + +#include "ace/Task.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Timer_Heap_T.h" +#include "ace/Timer_Queue_Adapters.h" + +template <class RECEIVER, class ACTION> +class Command +{ + // = TITLE + // Defines an abstract class that allows us to invoke commands + // without knowing anything about the implementation. This class + // is used in the <Timer_Queue_Test_Driver> to invoke operations + // of the driver. + // + // = DESCRIPTION + // This class declares an interface to execute operations, + // binding a RECEIVER object with an ACTION. The RECEIVER knows + // how to implement the operation. A class can invoke operations + // without knowing anything about it, or how it was implemented. +public: + Command (RECEIVER &recvr, ACTION action); + // Sets the <receiver_> of the Command to recvr, and the + // <action_> of the Command to <action>. + + virtual ~Command (void); + + virtual int execute (void *arg); + // Invokes the method <action_> from the object <receiver_>. + +private: + RECEIVER &receiver_; + // object where the method resides. + + ACTION action_; + // method that is going to be invoked. +}; + +template <class TQ, class RECEIVER, class ACTION> +class Timer_Queue_Test_Driver +{ + // = TITLE + // Defines a class that provides a simmple implementation for + // a test driver for timer queues. + // + // = DESCRIPTION + // This is the place where the common code to test the different + // implementations of the timer queue resides. This class has + // the logic for the parse_commands() method, the run_test(), + // read_input() and the get_next_request(). Subclasses can + // override these methods if there is some logic that is specific + // to that implementation. +public: + virtual ~Timer_Queue_Test_Driver (void); + // Default destructor + + virtual int parse_commands (const char *buf); + // Breaks up the input string buffer into pieces and executes + // the appropriate method to handle that operation. + + virtual int run_test (void); + // This is the main entry point to the test driver. The user + // of the class should normally invoke this method. + // Returns 0 when successful, or 0 otherwise. + + virtual int get_next_request (void); + // This internal method gets the next request from the user. + // Returns -1 when user wants to exit. Returns 0 otherwise. + + virtual ssize_t read_input (char *buf, size_t bufsiz); + // Reads input from the user into the buffer <buf> with a maximum + // of <bufsiz> bytes. Returns the amount of bytes actually read + // Otherwise, a -1 is returned and errno is set to indicate the error. + + // = Template Methods. + + virtual int display_menu (void)=0; + // Prints the user interface for the driver to STDOUT. + + virtual int init (void)=0; + // Initializes values and operations for the driver. + +protected: + TQ timer_queue_; + // timer queue + + // = Set of <Command>s to be executed. + + Command<RECEIVER, ACTION> *schedule_cmd_; + // schedule timer command + + Command<RECEIVER, ACTION> *cancel_cmd_; + // cancel timer command. + + Command<RECEIVER, ACTION> *list_cmd_; + // list timers command. + + Command<RECEIVER, ACTION> *shutdown_cmd_; + // shutdown the driver. +}; + +#if defined (ACE_TEMPLATES_REQUIRE_SOURCE) +#include "Driver.cpp" +#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */ + +#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA) +#pragma implementation ("Driver.cpp") +#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */ + +#endif /* _DRIVER_H_ */ diff --git a/ACE/examples/Timer_Queue/Makefile.am b/ACE/examples/Timer_Queue/Makefile.am new file mode 100644 index 00000000000..e2109fde6d6 --- /dev/null +++ b/ACE/examples/Timer_Queue/Makefile.am @@ -0,0 +1,95 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +ACE_BUILDDIR = $(top_builddir) +ACE_ROOT = $(top_srcdir) + +## Makefile.Timer_Queue_Library.am + +noinst_LTLIBRARIES = libtqtd.la + +libtqtd_la_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) \ + -DACE_BUILD_SVC_DLL + +libtqtd_la_SOURCES = \ + Async_Timer_Queue_Test.cpp \ + Driver.cpp \ + Reactor_Timer_Queue_Test.cpp \ + Thread_Timer_Queue_Test.cpp + +noinst_HEADERS = \ + Async_Timer_Queue_Test.h \ + Driver.h \ + Reactor_Timer_Queue_Test.h \ + Thread_Timer_Queue_Test.h + +## Makefile.Timer_Queue_Async.am +noinst_PROGRAMS = Asynch_Timer_Queue_Test + +Asynch_Timer_Queue_Test_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +Asynch_Timer_Queue_Test_SOURCES = \ + main_async.cpp \ + Async_Timer_Queue_Test.h \ + Driver.h \ + Reactor_Timer_Queue_Test.h \ + Thread_Timer_Queue_Test.h + +Asynch_Timer_Queue_Test_LDADD = \ + libtqtd.la \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Timer_Queue_Reactor.am +noinst_PROGRAMS += Reactor_Timer_Queue_Test + +Reactor_Timer_Queue_Test_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +Reactor_Timer_Queue_Test_SOURCES = \ + main_reactor.cpp \ + Async_Timer_Queue_Test.h \ + Driver.h \ + Reactor_Timer_Queue_Test.h \ + Thread_Timer_Queue_Test.h + +Reactor_Timer_Queue_Test_LDADD = \ + libtqtd.la \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Makefile.Timer_Queue_Thread.am +noinst_PROGRAMS += Thread_Timer_Queue_Test + +Thread_Timer_Queue_Test_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +Thread_Timer_Queue_Test_SOURCES = \ + main_thread.cpp \ + Async_Timer_Queue_Test.h \ + Driver.h \ + Reactor_Timer_Queue_Test.h \ + Thread_Timer_Queue_Test.h + +Thread_Timer_Queue_Test_LDADD = \ + libtqtd.la \ + $(ACE_BUILDDIR)/ace/libACE.la + +## Clean up template repositories, etc. +clean-local: + -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.* + -rm -f gcctemp.c gcctemp so_locations *.ics + -rm -rf cxx_repository ptrepository ti_files + -rm -rf templateregistry ir.out + -rm -rf ptrepository SunWS_cache Templates.DB diff --git a/ACE/examples/Timer_Queue/README b/ACE/examples/Timer_Queue/README new file mode 100644 index 00000000000..3cf6ec1b75b --- /dev/null +++ b/ACE/examples/Timer_Queue/README @@ -0,0 +1,26 @@ +This directory contains several examples that illustrate how to use +various concurrency mechanisms to schedule and handle timer-based +events. All programs are interactive and utilize a common timer queue +test framework. You can schedule or cancel time events and list all +the timers that are waiting to be triggered. + +The tests include: + +Reactor_Timer_Queue_Test: +------------------------- + +This example shows how to use ACE_Reactor as the timer queue +management mechanism. + +Thread_Timer_Queue_Test: +------------------------ + +This example shows how to use threads as the mechanism to generate +timer queue events. + +Async_Timer_Queue_Test: +----------------------- + +This example shows how to use singals as the mechanism to generate +timer queue events. It doesn't work on NT because of NT's limited +signal mechanism, i.e., no support for SIGALRM. diff --git a/ACE/examples/Timer_Queue/Reactor_Timer_Queue_Test.cpp b/ACE/examples/Timer_Queue/Reactor_Timer_Queue_Test.cpp new file mode 100644 index 00000000000..c3526e8daf9 --- /dev/null +++ b/ACE/examples/Timer_Queue/Reactor_Timer_Queue_Test.cpp @@ -0,0 +1,223 @@ +// $Id$ + +// ============================================================================ +// = LIBRARY +// examples +// +// = FILENAME +// Reactor_Timer_Queue_Test +// +// = DESCRIPTION +// This example tests the timer queue mechanism of ACE_Reactor. +// +// = AUTHOR +// Nanbor Wang <nw1@cs.wustl.edu> and +// Sergio Flores-Gaitan <sergio@cs.wustl.edu> +// +// ============================================================================ + +#include "ace/OS_NS_sys_time.h" +#include "ace/Thread_Manager.h" +#include "ace/Select_Reactor.h" +#include "ace/Reactor.h" +#include "ace/Timer_Heap.h" + +#include "Driver.h" +#include "Reactor_Timer_Queue_Test.h" + +ACE_RCSID(Timer_Queue, Reactor_Timer_Queue_Test, "$Id$") + +void +Reactor_Timer_Handler::set_timer_id (long tid) +{ + this->tid_ = tid; +} + +int +Reactor_Timer_Handler::handle_timeout (const ACE_Time_Value &tv, + const void *) +{ + // Macro to avoid "warning: unused parameter" type warning. + ACE_UNUSED_ARG (tv); + + ACE_Time_Value txv = ACE_OS::gettimeofday (); + ACE_DEBUG ((LM_DEBUG, + "\nTimer #%d fired at %d.%06d (%T)!\n", + this->tid_, + txv.sec (), + txv.usec ())); + delete this; + + return 0; +} + +Input_Handler::Input_Handler (ACE_Timer_Queue *tq, + Reactor_Timer_Queue_Test_Driver &timer_queue_driver) + : done_ (0), + driver_ (timer_queue_driver) +{ + this->tq_ = tq; +} + +int +Input_Handler::done (void) +{ + return this->done_; +} + +int +Input_Handler::schedule_timer (void *argument) +{ + int delay = *(int *) argument; + Reactor_Timer_Handler *th; + long tid; + + th = new Reactor_Timer_Handler; + if (th != 0) + { + tid = this->reactor ()->schedule_timer (th, + 0, + ACE_Time_Value (0, delay)); + if (tid == -1) + ACE_DEBUG ((LM_DEBUG, + "Unable to schedule timer\n")); + else + { + ACE_DEBUG ((LM_DEBUG, + "Timer #%d schedule to fire after %d usec from now.\n", + tid, + delay)); + th->set_timer_id (tid); + } + } + else + ACE_ERROR_RETURN ((LM_ERROR, + "not enough memory?\n"), + -1); + return tid; +} + +int +Input_Handler::cancel_timer (void *argument) +{ + int id = *(int *) argument; + return this->reactor ()->cancel_timer (id); +} + +int +Input_Handler::shutdown_timer (void *argument) +{ + // Macro to avoid "warning: unused parameter" type warning. + ACE_UNUSED_ARG (argument); + + this->done_ = 1; + ACE_DEBUG ((LM_DEBUG, + "Shutting down event loop\n")); + return -1; +} + +int +Input_Handler::list_timer (void *argument) +{ + // Macro to avoid "warning: unused parameter" type warning. + ACE_UNUSED_ARG (argument); + + ACE_Timer_Queue_Iterator &iter = this->tq_->iter (); + ACE_DEBUG ((LM_DEBUG, + "\n\nTimers in queue:\n")); + + for (; !iter.isdone (); iter.next ()) + { + ACE_Timer_Node *tn = iter.item (); + ACE_DEBUG ((LM_DEBUG, "Timer #%d: %d.%06d\n", + tn->get_timer_id (), + tn->get_timer_value ().sec (), + tn->get_timer_value ().usec ())); + } + return 0; +} + +int +Input_Handler::handle_input (ACE_HANDLE) +{ + return driver_.get_next_request (); +} + +Reactor_Timer_Queue_Test_Driver::Reactor_Timer_Queue_Test_Driver (void) + : thandler_ (&timer_queue_, *this) +{ +} + +Reactor_Timer_Queue_Test_Driver::~Reactor_Timer_Queue_Test_Driver (void) +{ +} + +int +Reactor_Timer_Queue_Test_Driver::display_menu (void) +{ + static char menu[] = + "\n*****\n" + "1) Schedule timer <usec>\n" + "2) Cancel timer <id>\n" + "3) List all timers\n" + "4) Shutdown program\n" + "Enter selection:"; + + ACE_DEBUG ((LM_DEBUG, + "%s", + menu)); + return 0; +} + +int +Reactor_Timer_Queue_Test_Driver::init (void) +{ + typedef Command<Input_Handler, Input_Handler::ACTION> CMD; + + // initialize <Command>s with their corresponding <Input_Handler> methods. + ACE_NEW_RETURN (schedule_cmd_, + CMD (thandler_, &Input_Handler::schedule_timer), + -1); + + ACE_NEW_RETURN (cancel_cmd_, + CMD (thandler_, &Input_Handler::cancel_timer), + -1); + + ACE_NEW_RETURN (list_cmd_, + CMD (thandler_, &Input_Handler::list_timer), + -1); + + ACE_NEW_RETURN (shutdown_cmd_, + CMD (thandler_, &Input_Handler::shutdown_timer), + -1); + + ACE_Reactor::instance ()->timer_queue (&timer_queue_); + + ACE_Event_Handler::register_stdin_handler (&thandler_, + ACE_Reactor::instance (), + ACE_Thread_Manager::instance ()); + + // print the menu of options. + this->display_menu (); + + return 0; +} + +// run test was overrun due to the reactive way of handling input. + +int +Reactor_Timer_Queue_Test_Driver::run_test (void) +{ + ACE_DEBUG ((LM_DEBUG, + "TIMER TEST STARTED\n")); + + this->init (); + + // Run until we say stop. + while (thandler_.done () == 0) + ACE_Reactor::instance ()->handle_events (); + + ACE_DEBUG ((LM_DEBUG, + "TIMER TEST ENDED\n")); + return 0; +} diff --git a/ACE/examples/Timer_Queue/Reactor_Timer_Queue_Test.h b/ACE/examples/Timer_Queue/Reactor_Timer_Queue_Test.h new file mode 100644 index 00000000000..3db20728814 --- /dev/null +++ b/ACE/examples/Timer_Queue/Reactor_Timer_Queue_Test.h @@ -0,0 +1,153 @@ +/* -*- C++ -*- */ + +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// examples +// +// = FILENAME +// Reactor_Timer_Queue_Test.h +// +// = DESCRIPTION +// This code is an implementation of a test driver for a reactor based +// timer queue. +// +// = AUTHORS +// Nanbor Wang <nw1@cs.wustl.edu> and +// Sergio Flores-Gaitan <sergio@cs.wustl.edu> +// +// ============================================================================ + +#ifndef _REACTOR_TIMER_QUEUE_TEST_H_ +#define _REACTOR_TIMER_QUEUE_TEST_H_ + +#include "Driver.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +/// @@todo: Not sure why this needs to be included. But am sure that, +/// there is some circular dependency setup. Needs to be +/// fixed. Atleast on g++ +#include "ace/Timer_Queue.h" +#include "ace/Timer_Heap.h" +#include "ace/svc_export.h" + +class Reactor_Timer_Queue_Test_Driver; + +class Input_Handler : public ACE_Event_Handler +{ + // = TITLE + // Implements the handler to be called for input events. Also has + // the logic to handle the different timer queue operations (i.e., + // schedule, cancel, list, shutdown). + // + // = DESCRIPTION + // This class handles the reading of user input from stdin. Also + // has the logic to handle the commands that are to be invoked in + // response to the user input. +public: + typedef int (Input_Handler::*ACTION) (void *); + + Input_Handler (ACE_Timer_Queue *tq, + Reactor_Timer_Queue_Test_Driver &timer_queue_driver); + // Sets <done_> flag to 0, <driver_> to <timer_queue_driver> and + // timer queue <tq_> to <tq> + + int handle_input (ACE_HANDLE); + // Hook method for the <ACE_Reactor> to call whenever there is input + // ready to be read. + + int done (void); + // returns the value for <done_> that indicates whether we are + // exiting the program.A value of 0 indicates that we are NOT done, + // 1 otherwise. + + // = Hook methods to be called from <Reactor_Timer_Queue_Test_Driver> + + int schedule_timer (void *argument); + // Schedule a timer. The (void *) will be mapped to the delay + // parameter for the timer queue schedule method. + + int cancel_timer (void *argument); + // Cancel a timer. The (void *) will be mapped to the ID of the + // timer being cancelled. + + int list_timer (void *argument); + // Dump the timers in the queue. The argument is ignored. + + int shutdown_timer (void *argument); + // Processes the request to exit the timer queue application. + // argument is ignored. + +private: + ACE_Timer_Queue *tq_; + // Keep a pointer to the timer queue we are using so we can traverse + // the queue. + + int done_; + // Flag used to close down program. + + Reactor_Timer_Queue_Test_Driver &driver_; + // Test driver. Used to call hook methods that are common code for + // all drivers. +}; + +class ACE_Svc_Export Reactor_Timer_Queue_Test_Driver : public Timer_Queue_Test_Driver <ACE_Timer_Heap, Input_Handler, Input_Handler::ACTION> +{ + // = TITLE + // Implements a test driver for a reactive timer queue using + // <ACE_Reactor>. + // + // = DESCRIPTION + // This class implements the logic to test the reactor + // implementation of timer queue, using an <ACE_Timer_Heap>. +public: + Reactor_Timer_Queue_Test_Driver (void); + // Sets the input handler <thandler_> with <timer_queue_> from the + // <Timer_Queue_Test_Driver> class and a reference to "this", so the + // input handler can call hook methods from the driver. Such + // methods are the common factored out code from other + // implementations of timer queues. + + virtual ~Reactor_Timer_Queue_Test_Driver (void); + // Default destructor + + virtual int display_menu (void); + // Prints the menu of options. + + virtual int init (void); + // Sets the timer queue that the REACTOR will use; registers the + // stdin input handler with the REACTOR and sets the <Command>s that + // the <Timer_Queue_Test_Driver> will execute(). + + virtual int run_test (void); + // Main entry point to the test driver implementation. + +private: + Input_Handler thandler_; + // This is the stdin handler. +}; + +class Reactor_Timer_Handler : public ACE_Event_Handler +{ + // = TITLE + // Target of the reactive timeout operation. +public: + virtual int handle_timeout (const ACE_Time_Value &tv, + const void *); + // Hook method that is called by the reactor when a timer expires. + // It prints the timer ID and the time it expired. + + void set_timer_id (long tid); + // Sets the timer id for this handler <tid_> to <tid> + +private: + long tid_; + // timer ID. +}; + +#endif /* _REACTOR_TIMER_QUEUE_TEST_H_ */ diff --git a/ACE/examples/Timer_Queue/Thread_Timer_Queue_Test.cpp b/ACE/examples/Timer_Queue/Thread_Timer_Queue_Test.cpp new file mode 100644 index 00000000000..d9cf88ff5ee --- /dev/null +++ b/ACE/examples/Timer_Queue/Thread_Timer_Queue_Test.cpp @@ -0,0 +1,270 @@ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// examples +// +// = FILENAME +// Thread_Timer_Queue_Test.cpp +// +// = DESCRIPTION +// This test exercises the <ACE_Thread_Timer_Queue_Adapter> +// using an <ACE_Timer_Heap>. +// +// = AUTHORS +// Carlos O'Ryan <coryan@cs.wustl.edu> and +// Douglas C. Schmidt <schmidt@cs.wustl.edu> +// +// ============================================================================ + +#include "ace/OS_NS_stdio.h" +#include "ace/OS_NS_sys_time.h" +#include "ace/Task.h" +#include "ace/Timer_Heap_T.h" +#include "ace/Timer_Queue_Adapters.h" + +#include "Thread_Timer_Queue_Test.h" + +#include "ace/Condition_T.h" +#include "ace/Thread_Mutex.h" + +ACE_RCSID(Timer_Queue, Thread_Timer_Queue_Test, "$Id$") + +// Administrivia methods... +Handler::Handler(const ACE_Time_Value &expiration_time) + : expires_ (expiration_time), + id_ (0) +{ +} + +Handler::~Handler (void) +{ +} + +void +Handler::set_id (int id) +{ + this->id_ = id; +} + +// This is the method invoked when the Timer expires. + +int +Handler::handle_timeout (const ACE_Time_Value ¤t_time, + const void *) +{ + ACE_Time_Value delay = current_time - this->expires_; + + // No need to protect this printf is always called from a Async safe + // point. + ACE_OS::printf ("\nexpiring timer %d at %lu.%7.7lu secs\n" + "\tthere was a %lu.%7.7lu secs delay\n", + this->id_, + current_time.sec (), + current_time.usec (), + delay.sec (), + delay.usec ()); + // Notice this delete is protected. + delete this; + return 0; +} + +Input_Task::Input_Task (Thread_Timer_Queue *queue, + Thread_Timer_Queue_Test_Driver &timer_queue_driver) + : ACE_Task_Base (ACE_Thread_Manager::instance ()), + queue_ (queue), + usecs_ (ACE_ONE_SECOND_IN_USECS), + driver_ (timer_queue_driver) +{ +} + +// Svc method is called from the thread library to read input from the +// user. + +int +Input_Task::svc (void) +{ + for (;;) + // call back to the driver's implementation on how to read and + // parse input. + if (this->driver_.get_next_request () == -1) + break; + + // we are done. + this->queue_->deactivate (); + ACE_DEBUG ((LM_DEBUG, + "terminating input thread\n")); + return 0; +} + +// schedule a new timer. This method will be called from inside the +// <Timer_Queue_Test_Driver> class. (see Command pattern) + +int +Input_Task::add_timer (void *argument) +{ + u_long useconds = *reinterpret_cast<int *> (argument); + ACE_Time_Value interval (useconds / usecs_, + useconds % usecs_); + ACE_Time_Value expire_at = ACE_OS::gettimeofday () + interval; + + Handler *h; + + ACE_NEW_RETURN (h, + Handler (expire_at), + -1); + + int id = queue_->schedule (h, 0, expire_at); + + if (id == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "schedule failed"), + -1); + + // We store the id into the handler, this is only used to produce + // nicer messages. + h->set_id (id); + + ACE_OS::printf ("scheduling timer %d\n", + id); + return 0; +} + +// Cancel a timer. This method will be called from inside the +// <Timer_Queue_Test_Driver> class. (see Command pattern) + +int +Input_Task::cancel_timer (void *argument) +{ + return this->queue_->cancel (*reinterpret_cast<int *> (argument)); +} + +// Lists the timers in the queue. Ignores the argument. This method +// will be called from inside the <Timer_Queue_Test_Driver> class. +// (see Command pattern) + +int +Input_Task::list_timer (void *argument) +{ + // Macro to avoid "warning: unused parameter" type warning. + ACE_UNUSED_ARG (argument); + + // Dump the timer queue contents. + this->dump (); + + return 0; +} + +// Shutdown the timer queue. Return -1 indicates to the +// <Timer_Queue_Test_Driver> class that we are done. + +int +Input_Task::shutdown_timer (void *argument) +{ + // Macro to avoid "warning: unused parameter" type warning. + ACE_UNUSED_ARG (argument); + +#if defined (ACE_LACKS_PTHREAD_CANCEL) + // Cancel the thread timer queue task "voluntarily." + this->queue_->deactivate (); +#else + // Cancel the thread timer queue task "preemptively." + if (ACE_Thread::cancel (this->queue_->thr_id ()) == -1) + ACE_ERROR ((LM_ERROR, + "%p\n", + "cancel")); +#endif /* ACE_LACKS_PTHREAD_CANCEL */ + + // -1 indicates we are shutting down the application. + return -1; +} + +void +Input_Task::dump (void) +{ + ACE_GUARD (ACE_SYNCH_RECURSIVE_MUTEX, ace_mon, this->queue_->mutex ()); + + ACE_DEBUG ((LM_DEBUG, + "begin dumping timer queue\n")); + + for (Timer_Heap_Iterator i (*this->queue_->timer_queue ()); + i.item () != 0; + i.next ()) + i.item ()->dump (); + + ACE_DEBUG ((LM_DEBUG, + "end dumping timer queue\n")); +} + +// constructor + +Thread_Timer_Queue_Test_Driver::Thread_Timer_Queue_Test_Driver (void) + : input_task_ (&timer_queue_, *this) +{ +} + +Thread_Timer_Queue_Test_Driver::~Thread_Timer_Queue_Test_Driver (void) +{ +} + +int +Thread_Timer_Queue_Test_Driver::run_test (void) +{ + this->init (); + return 0; +} + +int +Thread_Timer_Queue_Test_Driver::display_menu (void) +{ + static char menu[] = + "Usage:\n" + "1 <microseconds>: setups a new timer\n" + "2 <timerid>: removes a timer\n" + "3 : prints timer queue\n" + "4 : exit\n"; + + ACE_DEBUG ((LM_DEBUG, + "%s", + menu)); + return 0; +} + +int +Thread_Timer_Queue_Test_Driver::init (void) +{ + typedef Command<Input_Task, Input_Task::ACTION> CMD; + + // initialize the <Command> objects with their corresponding + // methods from <Input_Task> + ACE_NEW_RETURN (schedule_cmd_, + CMD (input_task_, &Input_Task::add_timer), + -1); + + ACE_NEW_RETURN (cancel_cmd_, + CMD (input_task_, &Input_Task::cancel_timer), + -1); + + ACE_NEW_RETURN (list_cmd_, + CMD (input_task_, &Input_Task::list_timer), + -1); + + ACE_NEW_RETURN (shutdown_cmd_, + CMD (input_task_, &Input_Task::shutdown_timer), + -1); + + if (this->input_task_.activate () == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "cannot activate input task"), + -1); + else if (this->timer_queue_.activate () == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "cannot activate timer queue"), + -1); + else if (ACE_Thread_Manager::instance ()->wait () == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "wait on Thread_Manager failed"), + -1); + return 0; +} diff --git a/ACE/examples/Timer_Queue/Thread_Timer_Queue_Test.h b/ACE/examples/Timer_Queue/Thread_Timer_Queue_Test.h new file mode 100644 index 00000000000..573df6121f8 --- /dev/null +++ b/ACE/examples/Timer_Queue/Thread_Timer_Queue_Test.h @@ -0,0 +1,157 @@ +/* -*- C++ -*- */ + +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// examples +// +// = FILENAME +// Thread_Timer_Queue_Test.h +// +// = DESCRIPTION +// This code exercises the <ACE_Thread_Timer_Queue_Adapter> using +// an <ACE_Timer_Heap_T>. +// +// = AUTHORS +// Carlos O'Ryan <coryan@cs.wustl.edu> and +// Sergio Flores-Gaitan <sergio@cs.wustl.edu> +// +// ============================================================================ + +#ifndef _THREAD_TIMER_QUEUE_TEST_H_ +#define _THREAD_TIMER_QUEUE_TEST_H_ + +#include "ace/Task.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Null_Mutex.h" +#include "ace/Timer_Heap_T.h" +#include "ace/Timer_Queue_Adapters.h" +#include "ace/svc_export.h" +#include "ace/Condition_Recursive_Thread_Mutex.h" +#include "Driver.h" + +// These typedefs ensure that we use the minimal amount of locking +// necessary. +typedef ACE_Event_Handler_Handle_Timeout_Upcall<ACE_Null_Mutex> + Upcall; +typedef ACE_Timer_Heap_T<ACE_Event_Handler *, + Upcall, + ACE_Null_Mutex> + Timer_Heap; +typedef ACE_Timer_Heap_Iterator_T<ACE_Event_Handler *, + Upcall, + ACE_Null_Mutex> + Timer_Heap_Iterator; +typedef ACE_Thread_Timer_Queue_Adapter<Timer_Heap> + Thread_Timer_Queue; + +// Forward declaration. +class Thread_Timer_Queue_Test_Driver; + +class Input_Task : public ACE_Task_Base +{ + // = TITLE + // Read user actions on the Timer_Queue from stdin. + // + // = DESCRIPTION + // This class reads user input from stdin; those commands permit + // the control of a Timer_Queue, which is dispatched by another + // thread. +public: + typedef int (Input_Task::*ACTION) (void *); + + Input_Task (Thread_Timer_Queue *queue, + Thread_Timer_Queue_Test_Driver &timer_queue_driver); + + virtual int svc (void); + // This method runs the event loop in the new thread. + + // = Some helper methods. + + int add_timer (void *); + // Add a new timer to expire in <seconds> more. + + int cancel_timer (void *); + // Cancel timer <id>. + + int list_timer (void *); + // List the current scheduled timers. + + int shutdown_timer (void *); + // Shutdown task. + + void dump (void); + // Dump the state of the timer queue. + +private: + Thread_Timer_Queue *queue_; + // The timer queue implementation. + + const int usecs_; + // How many micro seconds are in a second. + + Thread_Timer_Queue_Test_Driver &driver_; + // The thread timer queue test driver. +}; + +class ACE_Svc_Export Thread_Timer_Queue_Test_Driver : public Timer_Queue_Test_Driver <Thread_Timer_Queue, Input_Task, Input_Task::ACTION> +{ + // = TITLE + // Implements an example application that exercises + // <Thread_Timer_Queue> timer queue. + // + // = DESCRIPTION + // This class implements a simple test driver for the + // <Thread_Timer_Queue>. The <display_menu> hook method is + // called from the base class to print a menu specific to the + // thread implementation of the timer queue. +public: + Thread_Timer_Queue_Test_Driver (void); + ~Thread_Timer_Queue_Test_Driver (void); + + virtual int display_menu (void); + virtual int init (void); + virtual int run_test (void); + +private: + Input_Task input_task_; + // Subclassed from ACE_Task. +}; + +class Handler : public ACE_Event_Handler +{ + // = TITLE + // Event handler for the timer queue timeout events. + // + // = DESCRIPTION + // The <handle_timeout> hook method prints out the current time, + // prints the time when this timer expired and deletes "this". +public: + Handler (const ACE_Time_Value &expiration_time); + ~Handler (void); + + void set_id (int id); + // Store an "id" for the Handler, which is only use to print better + // messages. + + virtual int handle_timeout (const ACE_Time_Value ¤t_time, + const void *arg); + // Call back hook. + +private: + ACE_Time_Value expires_; + // Store the expected time of expiration, it is used to print a nice + // message saying how much delay was at the actual expiration time. + + int id_; + // Store an "id" for the Handler, which is only use to print better + // messages. +}; + +#endif /* _THREAD_TIMER_QUEUE_TEST_H_ */ diff --git a/ACE/examples/Timer_Queue/Timer_Queue.mpc b/ACE/examples/Timer_Queue/Timer_Queue.mpc new file mode 100644 index 00000000000..04026c0babd --- /dev/null +++ b/ACE/examples/Timer_Queue/Timer_Queue.mpc @@ -0,0 +1,40 @@ +// -*- MPC -*- +// $Id$ + +project(*Library) : acelib { + sharedname = tqtd + dynamicflags += ACE_BUILD_SVC_DLL + Source_Files { + Async_Timer_Queue_Test.cpp + Driver.cpp + Reactor_Timer_Queue_Test.cpp + Thread_Timer_Queue_Test.cpp + } +} + +project(*Async) : aceexe { + exename = Asynch_Timer_Queue_Test + after += Timer_Queue_Library + libs += tqtd + Source_Files { + main_async.cpp + } +} + +project(*Reactor) : aceexe { + exename = Reactor_Timer_Queue_Test + after += Timer_Queue_Library + libs += tqtd + Source_Files { + main_reactor.cpp + } +} + +project(*Thread) : aceexe { + exename = Thread_Timer_Queue_Test + after += Timer_Queue_Library + libs += tqtd + Source_Files { + main_thread.cpp + } +} diff --git a/ACE/examples/Timer_Queue/main_async.cpp b/ACE/examples/Timer_Queue/main_async.cpp new file mode 100644 index 00000000000..8c21c4fcdd2 --- /dev/null +++ b/ACE/examples/Timer_Queue/main_async.cpp @@ -0,0 +1,57 @@ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// examples +// +// = FILENAME +// main_async.cpp +// +// = DESCRIPTION +// Implements an asynchronous timer queue. +// This code exercises the Timer_Queue_Test_Driver class using +// signals as an asynchronous mechanism to dispatch events. +// +// = AUTHORS +// Douglas Schmidt <schmidt@cs.wustl.edu> && +// Sergio Flores-Gaitan <sergio@cs.wustl.edu> +// +// ============================================================================ + +// The following #pragma is needed to disable a warning that occurs +// in MSVC 6 due to the overly long debugging symbols generated for +// the std::auto_ptr<Timer_Queue_Test_Driver<...> > template +// instance used by some of the methods in this file. +#ifdef _MSC_VER +# pragma warning(disable: 4786) /* identifier was truncated to '255' + characters in the browser + information */ +#endif /* _MSC_VER */ + +#include "ace/OS_main.h" +#include "ace/Auto_Ptr.h" +#include "Driver.h" +#include "Async_Timer_Queue_Test.h" + +ACE_RCSID (Timer_Queue, + main_async, + "$Id$") + +typedef Timer_Queue_Test_Driver<Async_Timer_Queue *, + Async_Timer_Queue, + Async_Timer_Queue::ACTION> + ASYNC_TIMER_QUEUE_TEST_DRIVER; + +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ASYNC_TIMER_QUEUE_TEST_DRIVER *tqtd; + ACE_NEW_RETURN (tqtd, Async_Timer_Queue_Test_Driver, -1); + // Auto ptr ensures that the driver memory is released + // automatically. + auto_ptr <ASYNC_TIMER_QUEUE_TEST_DRIVER> driver (tqtd); + + return driver->run_test (); +} + diff --git a/ACE/examples/Timer_Queue/main_reactor.cpp b/ACE/examples/Timer_Queue/main_reactor.cpp new file mode 100644 index 00000000000..9ce80093bd9 --- /dev/null +++ b/ACE/examples/Timer_Queue/main_reactor.cpp @@ -0,0 +1,57 @@ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// examples +// +// = FILENAME +// main_reactor.cpp +// +// = DESCRIPTION +// Implements an reactive timer queue. +// This code exercises the Timer_Queue_Test_Driver class using +// a reactor. +// +// = AUTHORS +// Douglas Schmidt <schmidt@cs.wustl.edu> && +// Sergio Flores-Gaitan <sergio@cs.wustl.edu> +// +// ============================================================================ + +// The following #pragma is needed to disable a warning that occurs +// in MSVC 6 due to the overly long debugging symbols generated for +// the std::auto_ptr<Timer_Queue_Test_Driver<...> > template +// instance used by some of the methods in this file. +#ifdef _MSC_VER +# pragma warning(disable: 4786) /* identifier was truncated to '255' + characters in the browser + information */ +#endif /* _MSC_VER */ + +#include "ace/OS_main.h" +#include "ace/Auto_Ptr.h" +#include "Reactor_Timer_Queue_Test.h" +#include "Driver.h" + +ACE_RCSID (Timer_Queue, + main_reactor, + "$Id$") + +typedef Timer_Queue_Test_Driver <ACE_Timer_Heap, + Input_Handler, + Input_Handler::ACTION> + REACTOR_TIMER_QUEUE_TEST_DRIVER; + +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + REACTOR_TIMER_QUEUE_TEST_DRIVER *tqtd; + ACE_NEW_RETURN (tqtd, Reactor_Timer_Queue_Test_Driver, -1); + // Auto ptr ensures that the driver memory is released + // automatically. + auto_ptr <REACTOR_TIMER_QUEUE_TEST_DRIVER> driver (tqtd); + + return driver->run_test (); +} + diff --git a/ACE/examples/Timer_Queue/main_thread.cpp b/ACE/examples/Timer_Queue/main_thread.cpp new file mode 100644 index 00000000000..7287e0ed263 --- /dev/null +++ b/ACE/examples/Timer_Queue/main_thread.cpp @@ -0,0 +1,58 @@ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// examples +// +// = FILENAME +// main_thread.cpp +// +// = DESCRIPTION +// Implements an threaded timer queue. +// This code exercises the Timer_Queue_Test_Driver class using +// threads. +// +// = AUTHORS +// Douglas Schmidt <schmidt@cs.wustl.edu> && +// Sergio Flores-Gaitan <sergio@cs.wustl.edu> +// +// ============================================================================ + +// The following #pragma is needed to disable a warning that occurs +// in MSVC 6 due to the overly long debugging symbols generated for +// the std::auto_ptr<Timer_Queue_Test_Driver<...> > template +// instance used by some of the methods in this file. +#ifdef _MSC_VER +# pragma warning(disable: 4786) /* identifier was truncated to '255' + characters in the browser + information */ +#endif /* _MSC_VER */ + +#include "ace/OS_main.h" +#include "ace/Auto_Ptr.h" +#include "Driver.h" +#include "Thread_Timer_Queue_Test.h" + +ACE_RCSID (Timer_Queue, + main_thread, + "$Id$") + +typedef Timer_Queue_Test_Driver<Thread_Timer_Queue, + Input_Task, + Input_Task::ACTION> + THREAD_TIMER_QUEUE_TEST_DRIVER; + +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + // Auto ptr ensures that the driver memory is released + // automatically. + THREAD_TIMER_QUEUE_TEST_DRIVER *tqtd; + ACE_NEW_RETURN (tqtd, Thread_Timer_Queue_Test_Driver, -1); + + auto_ptr <THREAD_TIMER_QUEUE_TEST_DRIVER> driver (tqtd); + + return driver->run_test (); +} + diff --git a/ACE/examples/Web_Crawler/.cvsignore b/ACE/examples/Web_Crawler/.cvsignore new file mode 100644 index 00000000000..ba2906d0666 --- /dev/null +++ b/ACE/examples/Web_Crawler/.cvsignore @@ -0,0 +1 @@ +main diff --git a/ACE/examples/Web_Crawler/Command_Processor.cpp b/ACE/examples/Web_Crawler/Command_Processor.cpp new file mode 100644 index 00000000000..83289095444 --- /dev/null +++ b/ACE/examples/Web_Crawler/Command_Processor.cpp @@ -0,0 +1,128 @@ +// $Id$ + +#include "ace/OS_NS_string.h" +#include "URL.h" +#include "HTTP_URL.h" +#include "Options.h" +#include "Command_Processor.h" +#include "URL_Visitor.h" + +ACE_RCSID(Web_Crawler, Command_Processor, "$Id$") + +Command::~Command (void) +{ +} + +URL_Command::URL_Command (URL *url) + : url_ (url) +{ +} + +int +URL_Command::execute (void) +{ + + ACE_CString check_string + (ACE_TEXT_ALWAYS_CHAR (this->url_->url_addr ().get_path_name ())); + if (check_string.find ("news:") != ACE_CString::npos) + return 0; + + if (check_string.find (".cgi") != ACE_CString::npos) + return 0; + + if (check_string.find ("mailto") != ACE_CString::npos) + return 0; + + if (check_string.find (".gif") != ACE_CString::npos) + return 0; + + if (check_string.find (".pdf") != ACE_CString::npos) + return 0; + + if (check_string.find (".map") != ACE_CString::npos) + return 0; + + if (check_string.find (".bmp") != ACE_CString::npos) + return 0; + + if (check_string.find (".jpg") != ACE_CString::npos) + return 0; + + if (this->url_->accept (OPTIONS::instance ()->visitor ()) !=0) + { + ACE_DEBUG ((LM_DEBUG, + "Coudnt accept url\n")); + return -1; + } + return 0; +} + +int +URL_Command::destroy (void) +{ + delete this; + return 0; +} +Command_Processor::Command_Processor (void) +{ +} + +Command_Processor::~Command_Processor (void) +{ +} + +int +Command_Processor::destroy (void) +{ + delete this; + return 0; +return 0; +} + +int +Command_Processor::execute (void) +{ + Command *command; + while (this->url_queue_.is_empty () != 1) + { + if (this->url_queue_.dequeue_head (command) != 0) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", "dequeue_head"), + -1); + URL_Command *url_command = dynamic_cast<URL_Command *> (command); + Auto_Destroyer<URL_Command> url_command_ptr (url_command); + if (url_command_ptr->execute () != 0) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", "Couldnt execute command"), + -1); + } + return 0; +} + +int +Command_Processor::insert (Command *command) +{ + // According to the order specified the commands are removed from the queue. + if (this->url_queue_.is_full() != 1) + { + if (ACE_OS::strcmp (OPTIONS::instance ()->order (), ACE_TEXT ("FIFO")) == 0) + { + if (this->url_queue_.enqueue_tail (command) !=0) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), ACE_TEXT ("enqueue_tail")), + - 1); + } + if (ACE_OS::strcmp (OPTIONS::instance ()->order (), ACE_TEXT ("LIFO")) == 0) + { + if (this->url_queue_.enqueue_head (command) !=0) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), ACE_TEXT ("enqueue_head")), + - 1); + } + } + return 0; +} + +#if defined (ACE_HAS_EXPLICIT_STATIC_TEMPLATE_MEMBER_INSTANTIATION) +template ACE_Singleton<Options, ACE_Null_Mutex> *ACE_Singleton<Options, ACE_Null_Mutex>::singleton_; +#endif /* ACE_HAS_EXPLICIT_STATIC_TEMPLATE_MEMBER_INSTANTIATION */ diff --git a/ACE/examples/Web_Crawler/Command_Processor.h b/ACE/examples/Web_Crawler/Command_Processor.h new file mode 100644 index 00000000000..742a316804c --- /dev/null +++ b/ACE/examples/Web_Crawler/Command_Processor.h @@ -0,0 +1,98 @@ +/* -*- C++ -*- */ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// examples/Web_Crawler +// +// = FILENAME +// Command_Processor.h +// +// = AUTHOR +// Douglas C. Schmidt <schmidt@cs.wustl.edu> +// +// ============================================================================ + +#ifndef _COMMAND_PROCESSOR_H +#define _COMMAND_PROCESSOR_H + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +#pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Containers.h" +#include "Options.h" + +// Forward decl. +class URL; + +class Command +{ + // = TITLE + // Abstract base class for a command. + // + // = DESCRIPTION + // Each command is executed by a <Command_Processor>. +public: + virtual ~Command (void); + // Virtual destructor. + + virtual int execute (void) = 0; + // This is the entry point to execute the command. + virtual int destroy (void) = 0; +}; + +class URL_Command : public Command +{ + // = TITLE + // Defines an API for executing a command on a URL. + // + // = DESCRIPTION + // Each command is executed by a <Command_Processor>. +public: + URL_Command (URL *); + // Constructor. + + virtual int execute (void); + // Execute the URL command. + + int destroy (void); + // Commit suicide. +private: + URL *url_; + // Pointer to the URL. +}; + +class Command_Processor +{ + // = TITLE + // Execute commands that are passed to it. + // + // = DESCRIPTION + // This class implements the Command Processor pattern. +public: + Command_Processor (void); + + int insert (Command *); + // Insert a new <Command> into the <Command_Processor>'s queue. + + int execute (void); + // Execute all the <Commands> in the queue. + + int destroy (void); + // Destroy the <Command_Processor>. + +private: + friend class ACE_Shutup_GPlusPlus; + // Turn off g++ warning + + ~Command_Processor (void); + // Ensure dynamic allocation. + + // @@ You fill in here... + ACE_Unbounded_Queue<Command *> url_queue_; +}; + + +#endif /* _COMMAND_PROCESSOR_H */ diff --git a/ACE/examples/Web_Crawler/HTTP_URL.cpp b/ACE/examples/Web_Crawler/HTTP_URL.cpp new file mode 100644 index 00000000000..44ceea324d4 --- /dev/null +++ b/ACE/examples/Web_Crawler/HTTP_URL.cpp @@ -0,0 +1,87 @@ +// $Id$ + +#include "ace/OS_NS_stdio.h" +#include "ace/OS_NS_string.h" +#include "ace/Auto_Ptr.h" +#include "URL_Visitor.h" +#include "Options.h" +#include "HTTP_URL.h" + +ACE_RCSID(Web_Crawler, HTTP_URL, "$Id$") + +const ACE_URL_Addr & +HTTP_URL::url_addr (void) const +{ + return this->url_addr_; +} + +HTTP_URL::HTTP_URL (const ACE_URL_Addr &url_addr, + HTTP_URL *cp) + : url_addr_ (url_addr), + containing_page_ (cp == 0 ? this : cp) +{ + ACE_DEBUG ((LM_DEBUG, "HTTP_URL %s\n", url_addr.addr_to_string ())); +} + +ssize_t +HTTP_URL::send_request (void) +{ + size_t commandsize = + ACE_OS::strlen (this->url_addr ().get_path_name ()) + + ACE_OS::strlen (this->url_addr ().get_host_name ()) + + 20 // Extra + + 1 // NUL byte + + 16; // Protocol filler... + + char *command; + ACE_NEW_RETURN (command, + char[commandsize], + -1); + + // Ensure that the <command> memory is deallocated. + ACE_Auto_Basic_Array_Ptr<char> cmd_ptr (command); + + ACE_OS::sprintf (cmd_ptr.get (), + "GET /%s HTTP/1.1\r\n", + ACE_TEXT_ALWAYS_CHAR (this->url_addr ().get_path_name ())); + + // Send the GET command to the connected server. + if (this->stream ().send_n (cmd_ptr.get (), + ACE_OS::strlen (cmd_ptr.get ()), + const_cast<ACE_Time_Value *> + (OPTIONS::instance ()->timeout ())) > 0) + { + ACE_OS::sprintf (cmd_ptr.get (), + "Host: %s\r\n\r\n", + this->url_addr ().get_host_name ()); + + // IMP: The length of teh command has to be sent! + ssize_t retval = + this->stream ().send_n (cmd_ptr.get (), + ACE_OS::strlen (cmd_ptr.get ()), + const_cast<ACE_Time_Value *> + (OPTIONS::instance ()->timeout ())); + this->stream ().svc_handler ()->idle (0); + if (retval <= 0) + return -1; + else + return retval; + } + else + return -1; +} + +int +HTTP_URL::accept (URL_Visitor *visitor) +{ + // This is part of the visitor pattern. + return visitor->visit (*this); +} + +int +HTTP_URL::destroy (void) +{ + delete this; + return 0; + // Commit suicide! +} diff --git a/ACE/examples/Web_Crawler/HTTP_URL.h b/ACE/examples/Web_Crawler/HTTP_URL.h new file mode 100644 index 00000000000..a926bb47938 --- /dev/null +++ b/ACE/examples/Web_Crawler/HTTP_URL.h @@ -0,0 +1,64 @@ +/* -*- C++ -*- */ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// examples/Web_Crawler +// +// = FILENAME +// HTTP_URL.h +// +// = AUTHOR +// Douglas C. Schmidt <schmidt@cs.wustl.edu> +// +// ============================================================================ + +#ifndef _HTTP_URL_H +#define _HTTP_URL_H + +#include "URL_Status.h" +#include "URL.h" +#include "Options.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +#pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +class HTTP_URL : public URL +{ + // = TITLE + // An ADT for an HTTP URL. + // + // = DESCRIPTION + // This class plays the "element" role in the Visitor pattern. +public: + HTTP_URL (const ACE_URL_Addr &url_addr, + HTTP_URL *containing_page = 0); + // The <url_addr> is the URL that we're going to be visiting. We + // also keep track of the containing page, if any, which is used to + // print out more meaningful messages. + + virtual int accept (URL_Visitor *visitor); + // Accept the visitor, which will then perform a particular + // visitation strategy on the URL. This method is part of the + // Visitor pattern. + + virtual ssize_t send_request (void); + // Send a <GET> command to fetch the contents in the URI from the + // server. + + virtual const ACE_URL_Addr &url_addr (void) const; + // Returns the URL that we represent. + + int destroy (void); + // Commit suicide +private: + ACE_URL_Addr url_addr_; + // Address of the URL we're connected to. + + HTTP_URL *containing_page_; + // Page that contained us. +}; + +#endif /* _HTTP_URL_H */ diff --git a/ACE/examples/Web_Crawler/Iterators.cpp b/ACE/examples/Web_Crawler/Iterators.cpp new file mode 100644 index 00000000000..98b4f999622 --- /dev/null +++ b/ACE/examples/Web_Crawler/Iterators.cpp @@ -0,0 +1,163 @@ +// $Id$ + +#include "Options.h" +#include "Iterators.h" + +ACE_RCSID(Web_Crawler, Iterators, "$Id$") + +URL_Iterator::~URL_Iterator (void) +{ +} + +int +URL_Iterator::destroy (void) +{ + // Commit suicide. + delete this; + return 0; +} + +HTML_Body_Iterator::HTML_Body_Iterator (URL &url) + : url_ (url) +{ +} + +int +HTML_Body_Iterator::next (ACE_CString &url) +{ + size_t len = BUFSIZ; + const char *buf; + ACE_CString buffer; + int href_index = 0; + + for (buf = this->url_.stream ().recv (len); + buf > 0; + buf = this->url_.stream ().recv (len)) + { + + buffer.set (buf, BUFSIZ, 1); + + href_index = buffer.find ("HREF"); + + if (href_index < 0) + href_index = buffer.find ("href"); + + // Grep fpr " and grab the string until end-" + if ( href_index > 0) + { + // Get back to buffer start location. + this->url_.stream ().seek (-1 * static_cast<off_t> (len), + SEEK_CUR); + + int start_index = buffer.find ('\"', + href_index); + if (start_index <= 0) + break; + + start_index += href_index; + + int end_index = buffer.find ('\"', + start_index + 1); + if (end_index <= 0) + break; + + end_index += start_index + 1; + + ssize_t url_len = end_index - (start_index + 1); + + ACE_CString temp = buffer.substring (start_index + 1, + url_len); + url.set (temp.c_str (), len, 1); + + this->url_.stream ().seek (end_index + 1); + + return url_len; + } + } + return 0; + +} + +HTTP_Header_Iterator::HTTP_Header_Iterator (URL &url) + : url_ (url), + end_of_header_ (0) +{ +} + +int +HTTP_Header_Iterator::next (ACE_CString &line) +{ + if (this->end_of_header_) + return 0; + else + { + for (char c; + (c = this->url_.stream ().get_char ()) != (char)EOF; + ) + { + // Check to see if we're at the end of the header line. + if (c == '\r' && this->url_.stream ().peek_char (0) == '\n') + { + line.set (this->url_.stream ().recv (), + this->url_.stream ().recv_len () - 1, + 1); + + // Check to see if we're at the end of the header. + if (this->url_.stream ().peek_char (1) == '\r' + && this->url_.stream ().peek_char (2) == '\n') + { + this->end_of_header_ = 1; + // We're at the end of the header section. + this->url_.stream ().seek (3); + } + else + // We're at the end of the line. + this->url_.stream ().seek (1); + + return 1; + } + // Handle broken Web servers that use '\n' instead of + // '\r\n'. + else if (c == '\n') + { + line.set (this->url_.stream ().recv (), + (this->url_.stream ().recv_len ()), + 1); + + // Check to see if we're at the end of the header. + if (this->url_.stream ().peek_char (0) == '\n') + { + // We're at the end of the header section. + this->url_.stream ().seek (1); + this->end_of_header_ = 1; + } + + return 1; + } + } + + } + return 0; +} + +URL_Download_Iterator::URL_Download_Iterator (URL &url) + : url_ (url) +{ +} + +int +URL_Download_Iterator::next (ACE_CString &buffer) +{ + size_t len = BUFSIZ; + + const char *buf = this->url_.stream ().recv (len); + + + if (buf == 0) + return 0; + else + { + buffer.set (buf, len, 1); + return 1; + } +} diff --git a/ACE/examples/Web_Crawler/Iterators.h b/ACE/examples/Web_Crawler/Iterators.h new file mode 100644 index 00000000000..b5d267f7afb --- /dev/null +++ b/ACE/examples/Web_Crawler/Iterators.h @@ -0,0 +1,117 @@ +/* -*- C++ -*- */ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// examples/Web_Crawler +// +// = FILENAME +// Iterators.h +// +// = AUTHOR +// Douglas C. Schmidt <schmidt@cs.wustl.edu> +// +// ============================================================================ + +#ifndef _ITERATORS_H +#define _ITERATORS_H + +#include "URL.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +#pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +class URL_Iterator +{ + // = TITLE + // An abstract base class that defines an iterator. + // + // = DESCRIPTION + // Subclasses of this base class can define what strings + // to return from <next>. This class decouples higher-level + // software from the details of whatever type of URL header or + // body we're iterating over. +public: + // = Initialization and termination methods. + virtual int destroy (void); + // "virtual" destructor. + + // = Iterator methods. + virtual int next (ACE_CString &string) = 0; + // Pass back the next <string> that hasn't been seen yet. Returns 0 + // when all items have been seen, else 1. + +protected: + virtual ~URL_Iterator (void); + // C++ destructor. +}; + +class HTML_Body_Iterator : public URL_Iterator +{ + // = TITLE + // An iterator that returns URLs embedded in HTML files. +public: + // = Initialization and termination methods. + HTML_Body_Iterator (URL &url); + // Constructor. + + // = Iterator methods. + virtual int next (ACE_CString &url); + // Pass back the next <url> that hasn't been seen in the + // memory-mapped file. Returns 0 when all items have been seen, + // else 1. + +private: + URL &url_; + // HTTP URL that we're iterating over. +}; + +class HTTP_Header_Iterator : public URL_Iterator +{ + // = TITLE + // An iterator that iterates over the HTTP header. +public: + // = Initialization and termination methods. + HTTP_Header_Iterator (URL &url); + // Constructor. + + // = Iterator methods. + virtual int next (ACE_CString &line); + // Pass back the next <line> that hasn't been seen in the + // memory-mapped file header. Returns 0 when we've reached the end + // of the header. seen, else 1. + +private: + URL &url_; + // HTTP URL that we're iterating over. + + int end_of_header_; + // We've found the end of the header, which means this iterator is + // finished. +}; + +class URL_Download_Iterator : public URL_Iterator +{ + // = TITLE + // An iterator that iterates over the contents of an entire URL, + // i.e., both header and body, and returns it in <BUFSIZ> + // <buffer>s. +public: + // = Initialization and termination methods. + URL_Download_Iterator (URL &url); + // Constructor. + + // = Iterator methods. + virtual int next (ACE_CString &buffer); + // Pass back the next <buffer> data from the stream, where + // <buffer.size> <= <BUFSIZ> . Returns 0 when we've reached the end + // of the header, else 1. + +private: + URL &url_; + // HTTP URL that we're iterating over. +}; + +#endif /* _ITERATORS_H */ diff --git a/ACE/examples/Web_Crawler/Makefile.am b/ACE/examples/Web_Crawler/Makefile.am new file mode 100644 index 00000000000..00a30a4d2e1 --- /dev/null +++ b/ACE/examples/Web_Crawler/Makefile.am @@ -0,0 +1,60 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu + +ACE_BUILDDIR = $(top_builddir) +ACE_ROOT = $(top_srcdir) + + +## Makefile.Web_Crawler.am + +if !BUILD_ACE_FOR_TAO +noinst_PROGRAMS = main + +main_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) + +main_SOURCES = \ + Command_Processor.cpp \ + HTTP_URL.cpp \ + Iterators.cpp \ + Mem_Map_Stream.cpp \ + Options.cpp \ + URL.cpp \ + URL_Addr.cpp \ + URL_Status.cpp \ + URL_Visitor.cpp \ + URL_Visitor_Factory.cpp \ + Web_Crawler.cpp \ + main.cpp \ + Command_Processor.h \ + HTTP_URL.h \ + Iterators.h \ + Mem_Map_Stream.h \ + Options.h \ + URL.h \ + URL_Addr.h \ + URL_Status.h \ + URL_Visitor.h \ + URL_Visitor_Factory.h \ + Web_Crawler.h + +main_LDADD = \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Clean up template repositories, etc. +clean-local: + -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.* + -rm -f gcctemp.c gcctemp so_locations *.ics + -rm -rf cxx_repository ptrepository ti_files + -rm -rf templateregistry ir.out + -rm -rf ptrepository SunWS_cache Templates.DB diff --git a/ACE/examples/Web_Crawler/Mem_Map_Stream.cpp b/ACE/examples/Web_Crawler/Mem_Map_Stream.cpp new file mode 100644 index 00000000000..dda1d465a71 --- /dev/null +++ b/ACE/examples/Web_Crawler/Mem_Map_Stream.cpp @@ -0,0 +1,240 @@ +// $Id$ + +#include "ace/FILE_Addr.h" +#include "ace/Auto_Ptr.h" +#include "Options.h" +#include "Mem_Map_Stream.h" + +ACE_RCSID(Web_Crawler, Mem_Map_Stream, "$Id$") + +ACE_SOCK_Stream & +Mem_Map_Stream::stream (void) +{ + return svc_handler_->peer (); +} + +ssize_t +Mem_Map_Stream::send_n (const void *buf, size_t size, ACE_Time_Value *tv) +{ + return svc_handler_->peer ().send_n (buf, size, 0, tv); +} + +int +Mem_Map_Stream::eof (void) const +{ + return this->get_pos_ >= this->end_of_mapping_plus1_; +} + +int +Mem_Map_Stream::get_char (void) +{ + if (this->eof () && this->grow_file_and_remap () == -1) + return EOF; + + return *this->get_pos_++; +} + +int +Mem_Map_Stream::rewind (void) +{ + this->recv_pos_ = + reinterpret_cast<char *> (this->mem_map_.addr ()); + this->get_pos_ = this->recv_pos_; + this->end_of_mapping_plus1_ = + this->recv_pos_ + this->mem_map_.size (); + return 0; +} + +int +Mem_Map_Stream::peek_char (size_t offset) +{ + // We may need to iterate if the size of <n> is large. + while (this->get_pos_ + offset >= this->end_of_mapping_plus1_) + if (this->grow_file_and_remap () == -1) + return EOF; + + return this->get_pos_[offset]; +} + +const char * +Mem_Map_Stream::recv (void) const +{ + return this->recv_pos_; +} + +const char * +Mem_Map_Stream::recv (size_t &len) +{ + if (this->eof () && this->grow_file_and_remap () == -1) + return 0; + + + const char *s = this->recv_pos_; + off_t olen = static_cast <off_t> (len); + this->seek (olen, SEEK_CUR); + len = this->get_pos_ - s; + return s; +} + +size_t +Mem_Map_Stream::recv_len (void) const +{ + return this->get_pos_ - this->recv_pos_; +} + +const char * +Mem_Map_Stream::peek_str (size_t offset, + size_t size) +{ + // We will iterate if the size of <offset> is large. + while (this->get_pos_ + (offset + size) > this->end_of_mapping_plus1_) + if (this->grow_file_and_remap () == -1) + return 0; + + return &this->get_pos_[offset]; +} + +off_t +Mem_Map_Stream::seek (off_t offset, int whence) +{ + switch (whence) + { + case SEEK_SET: + this->get_pos_ = + reinterpret_cast<char *> (this->mem_map_.addr ()) + + offset; + break; + + case SEEK_CUR: + this->get_pos_ += offset; + break; + + case SEEK_END: + this->get_pos_ = + this->end_of_mapping_plus1_ + offset; + // @@ Not sure how to implement this (yet). + ACE_NOTSUP_RETURN (-1); + break; + } + + // Make sure that the backing store will cover this. + while (this->get_pos_ > this->end_of_mapping_plus1_) + if (this->grow_file_and_remap () == -1) + return (off_t) -1; + + this->recv_pos_ = this->get_pos_; + return this->recv_pos_ - reinterpret_cast<char *> (this->mem_map_.addr ()); +} + +Mem_Map_Stream::Svc_Handler * +Mem_Map_Stream::svc_handler (void) +{ + return this->svc_handler_; +} + + +int +Mem_Map_Stream::open (STRAT_CONNECTOR *connector, + const ACE_INET_Addr &addr) +{ + svc_handler_ = 0; + + // Connect to the server at <addr>. If the handler has to be + // connected to the server again, the Caching strategy takes care + // and uses the same connection. + if (connector->connect (svc_handler_, + addr) == -1) + { + + ACE_ERROR_RETURN ((LM_ERROR, + "%p %s %d\n", + "Connect failed", + addr.get_host_name (), + addr.get_port_number ()), + -1); + } + // Create a temporary filename. + ACE_FILE_Addr file (ACE_sap_any_cast (ACE_FILE_Addr &)); + + // Create the temporary file via the <ACE_Mem_Map> class API. + if (this->mem_map_.open (file.get_path_name (), + O_RDWR | O_CREAT | O_APPEND, + ACE_DEFAULT_FILE_PERMS) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "open"), + -1); + // Make sure to unlink this right away so that if this process + // crashes these files will be removed automatically. +#if 0 + else if (ACE_OS::unlink (file.get_path_name ()) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "unlink"), + -1); + else +#endif + // Initialize all the position pointers to 0. + this->rewind (); + + return 0; +} + +int +Mem_Map_Stream::grow_file_and_remap (void) +{ + char buf[BUFSIZ + 1]; + + // Copy the next chunk of bytes from the socket into the temporary + // file. + ACE_Time_Value tv (*OPTIONS::instance ()->timeout ()); + + ssize_t n = this->svc_handler_->peer ().recv_n (buf, + sizeof buf, + 0, + &tv); + if (n == -1) + { + if (OPTIONS::instance ()->debug ()) + ACE_ERROR ((LM_ERROR, + "%p\n", + "recv")); + return -1; + } + else if (n == 0) + return -1; + else if (ACE::write_n (this->mem_map_.handle (), buf, n) != n) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "write_n"), + -1); + + // Grow the memory-mapping to encompass the entire temporary file. + if (this->mem_map_.map (-1, + PROT_RDWR, + ACE_MAP_PRIVATE | ACE_MAP_FIXED, + ACE_DEFAULT_BASE_ADDR) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "map"), + -1); + // MAP_FAILED is used as a "first time in" flag. + if (this->recv_pos_ == MAP_FAILED) + { + this->recv_pos_ = reinterpret_cast<char *> (this->mem_map_.addr ()); + this->get_pos_ = this->recv_pos_; + } + + this->end_of_mapping_plus1_ = + reinterpret_cast<char *> (this->mem_map_.addr ()) + + this->mem_map_.size (); + + return 0; +} + +Mem_Map_Stream::~Mem_Map_Stream (void) +{ + // Remove the mapping and the file. + this->mem_map_.remove (); +} + diff --git a/ACE/examples/Web_Crawler/Mem_Map_Stream.h b/ACE/examples/Web_Crawler/Mem_Map_Stream.h new file mode 100644 index 00000000000..3595f04ab77 --- /dev/null +++ b/ACE/examples/Web_Crawler/Mem_Map_Stream.h @@ -0,0 +1,190 @@ +/* -*- C++ -*- */ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// examples/Web_Crawler +// +// = FILENAME +// Mem_Map_Stream.h +// +// = AUTHOR +// Douglas C. Schmidt <schmidt@cs.wustl.edu> +// +// ============================================================================ + +#ifndef _MEM_MAP_STREAM_H +#define _MEM_MAP_STREAM_H +#include /**/ "ace/pre.h" + +#include "ace/SOCK_Stream.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +#pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + + +#include "ace/Mem_Map.h" +#include "ace/SOCK_Connector.h" +#include "ace/Connector.h" +#include "ace/Svc_Handler.h" +#include "ace/Strategies_T.h" + +class Mem_Map_Stream +{ + // = TITLE + // Provides a memory-mapped stream abstraction to simplify parsing + // of tokens. + // + // = DESCRIPTION + // This class makes it possible to treat an connection as a stream + // of bytes, similar to the C library stdio streams. The contents + // of the connection are buffered incrementally in a memory-mapped + // file. This class maintains pointers to two positions in the + // stream: + // + // 1. The <recv> position, which keeps track of the beginning of a + // token that is in the stream. + // + // 2. The <get> position, which moves along character-by-character + // until the end of the token is reached. + // + // Once a token has been located, it can be extracted from the + // stream by calling the <recv>. The length of the token, i.e., + // the <recv_len>, is the length in bytes between the <get> + // position and the <recv> position. Once the token has been + // extracted, the <recv> and <get> positions can be updated by the + // <seek> method. + +public: + typedef ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH> Svc_Handler; + + typedef ACE_Strategy_Connector<Svc_Handler, + ACE_SOCK_CONNECTOR> + STRAT_CONNECTOR; + + // Mem_Map_Stream (void); + // constructor added:KIRTHIKA + virtual int open (STRAT_CONNECTOR *connector, + const ACE_INET_Addr &); + // Initialize this object. + + virtual ~Mem_Map_Stream (void); + // Destructor. + + // = Accessor. + ACE_SOCK_Stream &stream (void); + // Returns the underlying <ACE_SOCK_Stream>. + + // = I/O methods. + + virtual ssize_t send_n (const void *buf, + size_t size, + ACE_Time_Value *tv = 0); + // Send <size> bytes in <buf> to the connected peer. This is a + // completely unbuffered call. + + virtual int get_char (void); + // Return the next character in the stream and advance the <get> + // position. Returns EOF when the <get> position reaches the end of + // the HTTP stream. + + virtual const char *recv (size_t &len); + // Returns a pointer to array of at most <len> characters starting + // at the <recv> position. If the <recv> position + <len> extends + // past the EOF then <len> is set to the number of characters + // between the <recv> position and the EOF and both the <get> and + // <recv> positions are advanced by <len>. Returns 0 if the <recv> + // position is at the EOF. + + virtual const char *recv (void) const; + // Returns a pointer to array of characters starting at the <recv> + // position. + + virtual size_t recv_len (void) const; + // Returns the length in bytes between the <get> position and the + // <recv> position. + + virtual int rewind (void); + // Resets the <get> and <recv> positions to the beginning of the + // stream. This works since all the data has been cached in the + // memory-mapped backing store. + + virtual int peek_char (size_t offset); + // Returns the nth character <offset> from the <get> position in the + // stream without advancing the <get> position. Automatically + // extends the backing store if necessary. Returns EOF if <offset> + // is past the end of the stream. + + virtual const char *peek_str (size_t offset, size_t size); + // Return a pointer to an array of <size> characters starting at + // <offset> characters from the <get> position in the stream without + // advancing the <get> position. Automatically extends the backing + // store if necessary. Returns 0 if <offset> or <offset + size> is + // past the end of the stream. + + virtual off_t seek (off_t offset, int whence = SEEK_CUR); + // Sets the <get> and <recv> positions as follows: + // o If <whence> is <SEEK_SET>, the positions are set to <offset> + // bytes from the start of the stream. + // + // o If <whence> is <SEEK_CUR>, the positions are set to the + // current <get> position plus <offset>. + // + // o If <whence> is <SEEK_END>, the positions are set to the size + // of the stream plus <offset>. + + virtual int eof (void) const; + // Returns 1 if we're at the end of the HTTP stream, else 0. + + + /* + typedef ACE_NOOP_Creation_Strategy<Svc_Handler> + NULL_CREATION_STRATEGY; + typedef ACE_NOOP_Concurrency_Strategy<Svc_Handler> + NULL_ACTIVATION_STRATEGY; + typedef ACE_Cached_Connect_Strategy<Svc_Handler, + ACE_SOCK_CONNECTOR, + ACE_SYNCH_NULL_MUTEX> + CACHED_CONNECT_STRATEGY;*/ + + Svc_Handler *svc_handler (void); + +private: + int grow_file_and_remap (void); + // Grow the file by reading another chunk from the HTTP socket and + // extend the mapping to cover this chunk. Returns -1 on failure or + // EOF, else 0. + + //ACE_SOCK_Stream stream_; + + Svc_Handler *svc_handler_; + // Connection to peer. The granularity is at the Svc_Handler level. + // The Svc_Handler has an SOCK_Stream. + /* + NULL_CREATION_STRATEGY creation_strategy_; + NULL_ACTIVATION_STRATEGY activation_strategy_; + // Configure the Strategy Connector with a strategy that caches + // connection. + CACHED_CONNECT_STRATEGY caching_connect_strategy_; + + STRAT_CONNECTOR *strat_connector_; */ + + ACE_Mem_Map mem_map_; + // Memory-mapped file that we're iterating over. + + char *recv_pos_; + // Pointer to the address where the next <recv> method will start. + + char *get_pos_; + // Pointer to the address where the next <get_char> method will + // start. + + char *end_of_mapping_plus1_; + // Address at the end of the file mapping. + +}; + +#include /**/ "ace/post.h" +#endif /* _MEM_MAP_STREAM_H */ diff --git a/ACE/examples/Web_Crawler/Options.cpp b/ACE/examples/Web_Crawler/Options.cpp new file mode 100644 index 00000000000..389cbfa0733 --- /dev/null +++ b/ACE/examples/Web_Crawler/Options.cpp @@ -0,0 +1,177 @@ +// $Id$ + +#include "ace/Get_Opt.h" +#include "ace/Log_Msg.h" +#include "URL_Addr.h" +#include "Options.h" +#include "ace/OS_NS_string.h" + +ACE_RCSID(Web_Crawler, Options, "$Id$") + +int +Options::parse_args (int argc, ACE_TCHAR *argv[]) +{ + ACE_Get_Opt getopt (argc, argv, ACE_TEXT ("df:h:i:l:rt:u:vo:p:")); + + ACE_LOG_MSG->open (argv[0]); + + this->hostname_ = ACE_TEXT ("www.cs.wustl.edu"); + this->uri_ = ACE_TEXT ("index.html"); + this->recurse_ = 0; + this->debug_ = 0; + this->timeout_.sec (ACE_DEFAULT_TIMEOUT); + this->url_filter_ = 0; + this->verbose_ = 0; + this->order_ = ACE_TEXT ("FIFO"); + this->port_no_ = ACE_DEFAULT_HTTP_PORT; + + // The default is to make this limit as large as possible. + this->handle_limit_ = -1; + + for (int c; + (c = getopt ()) != EOF; + ) + switch (c) + { + case ACE_TEXT ('d'): + this->debug_ = 1; + break; + case ACE_TEXT ('f'): + this->url_filter_ = getopt.opt_arg (); + break; + case ACE_TEXT ('h'): + this->hostname_ = getopt.opt_arg (); + break; + case ACE_TEXT ('i'): + this->uri_ = getopt.opt_arg (); + break; + case ACE_TEXT ('l'): + this->handle_limit_ = ACE_OS::atoi (getopt.opt_arg ()); + break; + case ACE_TEXT ('r'): + this->recurse_ = 1; + break; + case ACE_TEXT ('t'): + this->timeout_.sec (ACE_OS::atoi (getopt.opt_arg ())); + break; + case ACE_TEXT ('u'): + { + this->hostname_ = getopt.opt_arg (); + ACE_TCHAR *s = ACE_OS::strchr (getopt.opt_arg (), ACE_TEXT ('/')); + if (s != 0) + { + this->uri_ = s + 1; + *s = ACE_TEXT ('\0'); + } + else + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("invalid URL %s\n"), + getopt.opt_arg ())); + } + break; + case ACE_TEXT ('v'): + this->verbose_ = 1; + break; + case ACE_TEXT ('o'): + { + this->order_ = getopt.opt_arg (); + } + break; + case ACE_TEXT ('p'): + this->port_no_ = ACE_OS::atoi (getopt.opt_arg ()); + break; + default: + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("usage: %n [-d] [-f filter] [-h hostname]") + ACE_TEXT (" [-l handle-limit] [-r] [-t timeout] [-u URI]") + ACE_TEXT (" [-v]\n%a"), + 1)); + + /* NOTREACHED */ + } + + return 0; +} + +int +Options::port_no (void) const +{ + return this->port_no_; +} + +int +Options::recurse (void) const +{ + return this->recurse_; +} + +const ACE_Time_Value * +Options::timeout (void) const +{ + return &this->timeout_; +} + +int +Options::debug (void) const +{ + return this->debug_; +} + +int +Options::verbose (void) const +{ + return this->verbose_; +} + +const ACE_TCHAR * +Options::order (void) const +{ + return this->order_; +} +const ACE_TCHAR * +Options::hostname (void) const +{ + return this->hostname_; +} + +const ACE_TCHAR * +Options::path_name (void) const +{ + return this->uri_; +} + +const ACE_TCHAR * +Options::url_filter (void) const +{ + return this->url_filter_; +} + +Command_Processor * +Options::command_processor (void) const +{ + return this->command_processor_; +} + +void +Options::command_processor (Command_Processor *cp) +{ + this->command_processor_ = cp; +} + +URL_Visitor * +Options::visitor (void) const +{ + return this->visitor_; +} + +void +Options::visitor (URL_Visitor *v) +{ + this->visitor_ = v; +} + +int +Options::handle_limit (void) +{ + return this->handle_limit_; +} diff --git a/ACE/examples/Web_Crawler/Options.h b/ACE/examples/Web_Crawler/Options.h new file mode 100644 index 00000000000..ef5f2efd40c --- /dev/null +++ b/ACE/examples/Web_Crawler/Options.h @@ -0,0 +1,124 @@ +/* -*- C++ -*- */ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// examples/Web_Crawler +// +// = FILENAME +// Options.h +// +// = AUTHOR +// Douglas C. Schmidt <schmidt@cs.wustl.edu> +// +// ============================================================================ + +#ifndef _OPTIONS_H +#define _OPTIONS_H + +#include "ace/Null_Mutex.h" +#include "ace/Singleton.h" +#include "ace/Time_Value.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +#pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +// Forward decls. +class Command_Processor; +class URL_Visitor; + +class Options +{ + // = TITLE + // Maintains the global options. + // + // = DESCRIPTION + // This class is converted into a Singleton by the + // <ACE_Singleton> template. +public: + int parse_args (int argc, ACE_TCHAR *argv[]); + // Parse the command-line arguments and initialize the options. + + int recurse (void) const; + // If non-0 and the link is an HTML file then recursively check all + // links that are embedded in the body of file. + + const ACE_TCHAR *hostname (void) const; + // Return the hostname of the initial Web server. + + const ACE_TCHAR *path_name (void) const; + // Return the initial URI. + + const ACE_TCHAR *url_filter (void) const; + // String used to filter out which URLs to validate. + + int debug (void) const; + // Are we debugging? + + int verbose (void) const; + // Are we being verbose? + + const ACE_TCHAR *order (void) const; + // Which order? LIFO|FIFO?? + + int port_no (void) const; + // Port # + + const ACE_Time_Value *timeout (void) const; + // Return the timeout used to prevent hanging on <recv> and + // <connect> calls to broken servers. + + // = Get/set the <Command_Processor>. + Command_Processor *command_processor (void) const; + void command_processor (Command_Processor *); + + // = Get/set the <URL_Visitor>. + URL_Visitor *visitor (void) const; + void visitor (URL_Visitor *); + + // Get the handle_limit. + int handle_limit (void); +private: + int recurse_; + // Are we recursving. + + const ACE_TCHAR *hostname_; + // Initial Web server name. + + const ACE_TCHAR *uri_; + // Initial URI name. + + int debug_; + // Are we debugging? + + int verbose_; + // Are we being verbose? + + const ACE_TCHAR *order_; + // Whether the URLs are traversed in FIFO or LIFO order. + + ACE_Time_Value timeout_; + // Timeout on <recv> and <connect> to broken Web servers. + + const ACE_TCHAR *url_filter_; + // String used to filter out which URLs to validate. + + Command_Processor *command_processor_; + // Pointer to the Command_Processor. + + URL_Visitor *visitor_; + // Pointer to the <URL_Visitor>. + + int port_no_; + // Port no. + + int handle_limit_; + // The limit of the number of descriptors to be given for this process. +}; + +// Typedef an Options Singleton. +typedef ACE_Singleton <Options, ACE_Null_Mutex> OPTIONS; + +#endif /* _OPTIONS_H */ diff --git a/ACE/examples/Web_Crawler/README b/ACE/examples/Web_Crawler/README new file mode 100644 index 00000000000..4f81809173d --- /dev/null +++ b/ACE/examples/Web_Crawler/README @@ -0,0 +1,25 @@ +Web Crawler Kirthika Parameswaran +----------- + +The Web Crawler follows the HTTP_1.1 protocol. + +This Crawler crawls in either FIFO or LIFO order over the URLs +now stored in a ACE_Unbounded_Queue. The Command Processor pattern is +used in this example. + +Also the auto-purging feature where connections are removed from the cache +when the process runs out of file descriptors, is added to this example. + +[Use the -l option to set the handle limit]. + +Run: +--- + + +> make + +> main -r -u www.cs.wustl.edu/~kirthika/test.html -o LIFO + +or + +> main -r -u www.cs.wustl.edu/~kirthika/test.html -o FIFO diff --git a/ACE/examples/Web_Crawler/URL.cpp b/ACE/examples/Web_Crawler/URL.cpp new file mode 100644 index 00000000000..ce52ed892ad --- /dev/null +++ b/ACE/examples/Web_Crawler/URL.cpp @@ -0,0 +1,39 @@ +// $Id$ + +#include "URL.h" + +ACE_RCSID(Web_Crawler, URL, "$Id$") + +Mem_Map_Stream & +URL::stream (void) +{ + return this->stream_; +} + +URL::~URL (void) +{ +} + +const URL_Status & +URL::reply_status (void) +{ + return this->reply_status_; +} + +void +URL::reply_status (const URL_Status &rs) +{ + this->reply_status_ = rs; +} + +const ACE_CString & +URL::content_type (void) +{ + return this->content_type_; +} + +void +URL::content_type (const ACE_CString &ct) +{ + this->content_type_ = ct; +} diff --git a/ACE/examples/Web_Crawler/URL.h b/ACE/examples/Web_Crawler/URL.h new file mode 100644 index 00000000000..68c41f018ad --- /dev/null +++ b/ACE/examples/Web_Crawler/URL.h @@ -0,0 +1,82 @@ +/* -*- C++ -*- */ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// examples/Web_Crawler +// +// = FILENAME +// URL.h +// +// = AUTHOR +// Douglas C. Schmidt <schmidt@cs.wustl.edu> +// +// ============================================================================ + +#ifndef _URL_H +#define _URL_H + +#include "Mem_Map_Stream.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +#pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "URL_Addr.h" +#include "URL_Status.h" + +#include "ace/SString.h" + + +// Forward declaration. +class URL_Visitor; + +class URL +{ + // = TITLE + // Base class for a URL. + // + // = DESCRIPTION + // This class plays a role in the Visitor pattern. +public: + virtual ~URL (void); + // Destructor. + + virtual int accept (URL_Visitor *visitor) = 0; + // Accept the visitor, which will then perform a particular + // visitation strategy on the URL. This method is part of the + // Visitor pattern. + + virtual ssize_t send_request (void) = 0; + // Send a <GET> command to fetch the contents in the URI from the + // server. + + virtual const ACE_URL_Addr &url_addr (void) const = 0; + // Returns the URL that we represent. + + virtual Mem_Map_Stream &stream (void); + // Returns the <Mem_Map_Stream>. + + // = Get/set the reply status. + virtual const URL_Status &reply_status (void); + virtual void reply_status (const URL_Status &); + + // = Get/set the reply status. + virtual const ACE_CString &content_type (void); + virtual void content_type (const ACE_CString &); + + + +private: + URL_Status reply_status_; + // Reply status of the URL. + + ACE_CString content_type_; + // Content-type of the URL. + + Mem_Map_Stream stream_; + // Contents of the stream. +}; + +#endif /* _URL_H */ diff --git a/ACE/examples/Web_Crawler/URL_Addr.cpp b/ACE/examples/Web_Crawler/URL_Addr.cpp new file mode 100644 index 00000000000..5a630e387fb --- /dev/null +++ b/ACE/examples/Web_Crawler/URL_Addr.cpp @@ -0,0 +1,234 @@ +// $Id$ + +#include "URL_Addr.h" +#include "ace/Log_Msg.h" +#include "ace/OS_NS_string.h" +#include "ace/OS_NS_stdio.h" +#include "ace/OS_NS_stdlib.h" +#include "ace/OS_Memory.h" + +ACE_RCSID (Web_Crawler, + URL_Addr, + "$Id$") + + +ACE_URL_Addr::ACE_URL_Addr (void) + : path_name_ (0), + addr_string_ (0), + addr_string_len_ (0) +{ +} + +int +ACE_URL_Addr::addr_to_string (ACE_TCHAR *s, + size_t size, + int ipaddr_format) const +{ + const size_t total_len = + ACE_OS::strlen (ipaddr_format == 0 ? + this->get_host_name () : + this->get_host_addr ()) + + ACE_OS::strlen ("65536") // Assume the max port number. + + ACE_OS::strlen (this->get_path_name ()) + + sizeof (':') + + sizeof ('/') + + sizeof ('\0'); // For trailing '\0'. + + if (size < total_len) + return -1; + else + { + ACE_OS::sprintf (s, ACE_TEXT ("%s:%d/%s"), + ACE_TEXT_CHAR_TO_TCHAR (ipaddr_format == 0 + ? this->get_host_name () + : this->get_host_addr ()), + this->get_port_number (), + this->get_path_name ()); + return 0; + } +} + +const ACE_TCHAR * +ACE_URL_Addr::addr_to_string (int ipaddr_format) const +{ + ACE_URL_Addr *this_ptr = const_cast<ACE_URL_Addr *> (this); + + size_t size = + ACE_OS::strlen (ipaddr_format == 0 ? + this->get_host_name () : + this->get_host_addr ()) + + ACE_OS::strlen ("65536") // Assume the max port number. + + ACE_OS::strlen (this->get_path_name ()) + + sizeof (':') + + sizeof ('/') + + sizeof ('\0'); // For trailing '\0'. + + if (size > this->addr_string_len_) + { + ACE_ALLOCATOR_RETURN (this_ptr->addr_string_, + (ACE_TCHAR *) ACE_OS::realloc ((void *) this->addr_string_, + size), + 0); + this_ptr->addr_string_len_ = size; + } + ACE_OS::sprintf (this->addr_string_, + ACE_TEXT ("%s:%d/%s"), + ACE_TEXT_CHAR_TO_TCHAR (ipaddr_format == 0 + ? this->get_host_name () + : this->get_host_addr ()), + this->get_port_number (), + this->get_path_name ()); + return this->addr_string_; +} + +int +ACE_URL_Addr::string_to_addr (const ACE_TCHAR *s) +{ + int result; + ACE_TCHAR *t; + + // Need to make a duplicate since we'll be overwriting the string. + ACE_ALLOCATOR_RETURN (t, + ACE_OS::strdup (s), + -1); + + + // First split off the path_name. + + ACE_TCHAR *path_name = ACE_OS::strchr (t, ACE_TEXT ('/')); + const ACE_TCHAR *name = ACE_TEXT ("index.html"); + if (path_name != 0) + { + if (ACE_OS::strlen (path_name + 1) > 0) + name = path_name + 1; + + *path_name = '\0'; + } + + ACE_ALLOCATOR_RETURN (this->path_name_, + // Skip over '/' + ACE_OS::strdup (name), + -1); + + // Now handle the host address and port number. + ACE_TCHAR *port_number = ACE_OS::strchr (t, ':'); + + if (port_number == 0) + { + // Assume it's an ip-address or ip-number. + result = this->ACE_INET_Addr::set (ACE_DEFAULT_HTTP_PORT, + t); + } + else + { + *port_number = '\0'; + u_short port = (u_short) ACE_OS::atoi (port_number + 1); // Skip over ':' + result = this->ACE_INET_Addr::set (port, t); + } + + ACE_OS::free (ACE_MALLOC_T (t)); + return result; +} + +ACE_URL_Addr::ACE_URL_Addr (const ACE_URL_Addr &addr) + : ACE_INET_Addr (), + path_name_ (0), + addr_string_ (0), + addr_string_len_ (0) +{ + if (this->set (addr) == -1) + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("ACE_URL_Addr::ACE_URL_Addr"))); +} + +int +ACE_URL_Addr::set (const ACE_URL_Addr &addr) +{ + ACE_OS::free (reinterpret_cast<void *> (const_cast<ACE_TCHAR *> + (this->path_name_))); + ACE_OS::free (reinterpret_cast<void *> (const_cast<ACE_TCHAR *> + (this->addr_string_))); + if (this->ACE_INET_Addr::set (addr) == -1) + return -1; + else + { + if (addr.path_name_) + ACE_ALLOCATOR_RETURN (this->path_name_, + ACE_OS::strdup (addr.path_name_), + -1); + if (addr.addr_string_) + ACE_ALLOCATOR_RETURN (this->addr_string_, + ACE_OS::strdup (addr.addr_string_), + -1); + this->addr_string_len_ = + addr.addr_string_len_; + return 0; + } +} + +void +ACE_URL_Addr::operator= (const ACE_URL_Addr &addr) +{ + if (this->set (addr) == -1) + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("ACE_URL_Addr::ACE_URL_Addr"))); +} + +u_long +ACE_URL_Addr::hash (void) const +{ + u_long result = this->ACE_INET_Addr::hash () + + ACE::hash_pjw (this->get_path_name ()); + + return result; +} + +bool +ACE_URL_Addr::operator== (const ACE_URL_Addr &addr) const +{ + return ACE_OS::strcmp (addr.get_path_name (), + this->get_path_name ()) == 0 + && addr.get_port_number () == this->get_port_number () + && addr.get_ip_address () == this->get_ip_address (); +} + +bool +ACE_URL_Addr::operator!= (const ACE_URL_Addr &addr) const +{ + return !(*this == addr); +} + +ACE_URL_Addr::ACE_URL_Addr (const ACE_TCHAR *host_name, + const ACE_TCHAR *path_name, + u_short port) + : ACE_INET_Addr (port, host_name), + path_name_ (ACE_OS::strdup (path_name)), + addr_string_ (0), + addr_string_len_ (0) +{ +} + +const ACE_TCHAR * +ACE_URL_Addr::get_path_name (void) const +{ + return this->path_name_; +} + +ACE_URL_Addr::~ACE_URL_Addr (void) +{ + ACE_OS::free (reinterpret_cast<void *> (const_cast<ACE_TCHAR *> + (this->path_name_))); + ACE_OS::free (reinterpret_cast<void *> (const_cast<ACE_TCHAR *> + (this->addr_string_))); + this->path_name_ = 0; +} + +int +ACE_URL_Addr::destroy (void) +{ + // Commit suicide. + delete this; + return 0; +} diff --git a/ACE/examples/Web_Crawler/URL_Addr.h b/ACE/examples/Web_Crawler/URL_Addr.h new file mode 100644 index 00000000000..9792e1bb390 --- /dev/null +++ b/ACE/examples/Web_Crawler/URL_Addr.h @@ -0,0 +1,111 @@ +// -*- C++ -*- + +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// examples/Web_Crawler +// +// = FILENAME +// URL_Addr.h +// +// = AUTHOR +// Douglas C. Schmidt <schmidt@cs.wustl.edu> +// +// ============================================================================ + +#ifndef ACE_URL_ADDR_H +#define ACE_URL_ADDR_H + +#include "ace/INET_Addr.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +#pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/ACE.h" + +class ACE_URL_Addr : public ACE_INET_Addr +{ + // = TITLE + // Defines a URL address family address format. +public: + // = Initialization and termination methods. + ACE_URL_Addr (void); + // Constructor. + + ACE_URL_Addr (const ACE_TCHAR *host_name, + const ACE_TCHAR *path_name, + u_short port = ACE_DEFAULT_HTTP_PORT); + + ACE_URL_Addr (const ACE_URL_Addr &addr); + // Copy constructor. + + int set (const ACE_URL_Addr &addr); + // Essentially the copy constructor. + + virtual int string_to_addr (const ACE_TCHAR *address); + // Initializes an <ACE_URL_Addr> from the <address>, which can be + // "ip-number:port-number/path-name" (e.g., + // "www.cs.wustl.edu:1234/~schmidt/" "ip-number:port-number/path-name" + // (e.g., "128.252.166.57:1234/~schmidt"). If there is no ':' in + // the <address> it is assumed to be an ip-number or ip-address + // number, with the port number <ACE_DEFAULT_HTTP_PORT>. + + virtual int addr_to_string (ACE_TCHAR *s, + size_t size, + int ipaddr_format = 1) const; + // Transform the current <ACE_INET_Addr> address into string format. + // If <ipaddr_format> is non-0 this produces + // "ip-number:port-number/path-name" (e.g., + // "128.252.166.57:80/~schmidt/"), whereas if <ipaddr_format> is 0 + // this produces "ip-name:port-number" (e.g., + // "www.cs.wustl.edu:80/~schmidt/"). Returns -1 if the <size> of + // the <buffer> is too small, else 0. + + virtual const ACE_TCHAR *addr_to_string (int ipaddr_format = 1) const; + // Transform the current <ACE_INET_Addr> address into string format. + // If <ipaddr_format> is non-0 this produces + // "ip-number:port-number/path-name" (e.g., + // "128.252.166.57:80/~schmidt/"), whereas if <ipaddr_format> is 0 + // this produces "ip-name:port-number" (e.g., + // "www.cs.wustl.edu:80/~schmidt/"). Uses dynamic memory, which + // is allocated on demand and deallocated when the object is + // destroyed. Returns -1 if dynamic memory fails, else 0. + + void operator= (const ACE_URL_Addr &addr); + // Assignment operator. + + ~ACE_URL_Addr (void); + // Destructor. + + bool operator == (const ACE_URL_Addr &SAP) const; + // Compare two addresses for equality. The addresses are considered + // equal if they contain the same IP address, port number, and path + // name. + + bool operator != (const ACE_URL_Addr &SAP) const; + // Compare two addresses for inequality. + + virtual u_long hash (void) const; + // Computes and returns hash value. + + const ACE_TCHAR *get_path_name (void) const; + // Return the path name. + + int destroy (void); + // Commit suicide. +private: + ACE_TCHAR *path_name_; + // Our path name. + + ACE_TCHAR *addr_string_; + // The dynamically address string that's used for the + // <addr_to_string> method. + + size_t addr_string_len_; + // Current length of the <addr_string_> +}; + +#endif /* ACE_URL_ADDR_H */ diff --git a/ACE/examples/Web_Crawler/URL_Status.cpp b/ACE/examples/Web_Crawler/URL_Status.cpp new file mode 100644 index 00000000000..35a57420593 --- /dev/null +++ b/ACE/examples/Web_Crawler/URL_Status.cpp @@ -0,0 +1,40 @@ +/* -*- C++ -*- */ +// $Id$ + +#include "URL_Status.h" + +ACE_RCSID(Web_Crawler, URL_Status, "$Id$") + +URL_Status::URL_Status (STATUS_CODE code) + : status_ (code) +{ +} + +URL_Status::URL_Status (const URL_Status &s) + : status_ (s.status_) +{ +} + +URL_Status::STATUS_CODE +URL_Status::status (void) const +{ + return this->status_; +} + +void +URL_Status::status (int s) +{ + this->status_ = URL_Status::STATUS_CODE (s); +} + +void +URL_Status::status (URL_Status::STATUS_CODE s) +{ + this->status_ = s; +} + +int URL_Status::destroy (void) +{ + delete this; + return 0; +} diff --git a/ACE/examples/Web_Crawler/URL_Status.h b/ACE/examples/Web_Crawler/URL_Status.h new file mode 100644 index 00000000000..672c5e4f240 --- /dev/null +++ b/ACE/examples/Web_Crawler/URL_Status.h @@ -0,0 +1,61 @@ +/* -*- C++ -*- */ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// examples/Web_Crawler +// +// = FILENAME +// URL_Status.h +// +// = AUTHOR +// Douglas C. Schmidt <schmidt@cs.wustl.edu> +// +// ============================================================================ + +#ifndef _URL_STATUS_H +#define _URL_STATUS_H + +#include "ace/config-all.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +#pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +class URL_Status +{ + // = TITLE +public: + enum STATUS_CODE + { + STATUS_OK = 200, + STATUS_CREATED = 201, + STATUS_ACCEPTED = 202, + STATUS_NO_CONTENT = 204, + STATUS_MOVED_PERMANENTLY = 301, + STATUS_MOVED_TEMPORARILY = 302, + STATUS_NOT_MODIFIED = 304, + STATUS_BAD_REQUEST = 400, + STATUS_UNAUTHORIZED = 401, + STATUS_FORBIDDEN = 403, + STATUS_ITEM_NOT_FOUND = 404, + STATUS_INTERNAL_SERVER_ERROR = 500, + STATUS_OP_NOT_IMPLEMENTED = 501, + STATUS_BAD_GATEWAY = 502, + STATUS_SERVICE_UNAVAILABLE = 503, + STATUS_INSUFFICIENT_DATA = 399 + }; + + URL_Status (STATUS_CODE = STATUS_INSUFFICIENT_DATA); + URL_Status (const URL_Status &); + + STATUS_CODE status (void) const; + void status (int); + void status (STATUS_CODE); + int destroy (void); +private: + STATUS_CODE status_; +}; + +#endif /* _URL_STATUS_H */ diff --git a/ACE/examples/Web_Crawler/URL_Visitor.cpp b/ACE/examples/Web_Crawler/URL_Visitor.cpp new file mode 100644 index 00000000000..481a7140089 --- /dev/null +++ b/ACE/examples/Web_Crawler/URL_Visitor.cpp @@ -0,0 +1,543 @@ +// $Id$ + +#include "ace/OS_NS_string.h" +#include "URL_Visitor.h" +#include "Command_Processor.h" + +ACE_RCSID(Web_Crawler, URL_Visitor, "$Id$") + +URL_Processing_Strategy::URL_Processing_Strategy (URL &url, + URL_Iterator &iterator) + : url_ (url), + iterator_ (iterator) +{ +} + +URL_Processing_Strategy::~URL_Processing_Strategy (void) +{ +} + +int +URL_Processing_Strategy::destroy (void) +{ + // Commit suicide. + delete this; + return 0; +} + +URL_Download_Strategy::URL_Download_Strategy (URL &url, + URL_Iterator &iterator) + : URL_Processing_Strategy (url, iterator) +{ +} + +int +URL_Download_Strategy::execute (void) +{ + ACE_CString buffer; + + // Extract all the contents of the Stream and print them to the + // file. + while (this->iterator_.next (buffer) != 0) + ACE_DEBUG ((LM_DEBUG, + "%s", + buffer.c_str ())); + + return 0; +} + +HTTP_Header_Processing_Strategy::HTTP_Header_Processing_Strategy (URL &url, + URL_Iterator &iterator) + : URL_Processing_Strategy (url, iterator) +{ +} + +int +HTTP_Header_Processing_Strategy::execute (void) +{ + // Set the get() position.Necessary since later a peek is done. + if (this->url_.stream ().get_char () == 0) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n","Header Not Found"), + -1); + char line_buf[BUFSIZ + 1]; + ACE_CString line (line_buf); + // Get the lines in the header iteratively and check for status info. + int result = 1, i = 0; + for (i = 0, result = this->iterator_.next (line); + result > 0; + ++i, result = this->iterator_.next (line)) + { + if (i == 0) + { + // Assuming that the status-no is a space away. + int status_index = line.find ("HTTP", 0); + ACE_CString status = line.substring (status_index + 9, //HTTP/1.1 200 + 3); + + URL_Status *url_status = 0; + ACE_NEW_RETURN (url_status, + URL_Status, + 0); + Auto_Destroyer<URL_Status> url_status_ptr (url_status); + url_status_ptr->status (ACE_OS::atoi (status.c_str ())); + this->url_.reply_status (**url_status_ptr); + // Invalid url. + if (url_status_ptr->status () != 200) + return -1; + } + else + { + + if (line.find ("text/html") != ACE_CString::npos) + { + ACE_CString url_content_type("text/html"); + this->url_.content_type (url_content_type); + } + } + } + return 0; + +} + +HTML_Body_Validation_Strategy::HTML_Body_Validation_Strategy (URL &url, + URL_Iterator &iterator, + URL_Validation_Visitor &context) + : URL_Processing_Strategy (url, iterator), + visitor_context_ (context) +{ +} + +int +HTML_Body_Validation_Strategy::execute (void) +{ + char host_name_buf[BUFSIZ + 1]; + ACE_CString host_name (host_name_buf); + host_name.set (url_.url_addr ().get_host_name (),1); + + // All to facilitate relative paths + char temp[BUFSIZ + 1]; + ACE_CString prev_location (temp); + + prev_location.set (ACE_TEXT_ALWAYS_CHAR (this->url_.url_addr ().get_path_name ()), + ACE_OS::strlen (this->url_.url_addr ().get_path_name ()), + 1); + int index = prev_location.rfind ('/', prev_location.length ()); + ACE_CString str = prev_location.substring (0, index + 1); + prev_location.set (str.c_str (), 1); + + // Note: prev_location always ends with '/' + if (prev_location[0] != '/') + prev_location = "/" + prev_location; + + // Build the url portion which can be attached to teh relative paths. + prev_location = host_name + prev_location; + + char url_string[BUFSIZ + 1]; + ACE_CString url (url_string); + + while (this->iterator_.next (url) > 0) + { + // Check for relative urls.Strip out "http://" if its there. + if (url.find ("http") == url.npos) + { + if (url[0] == '.' && url[1] == '.') + { + url.set (&url[3], 1); + int i = prev_location.rfind ('/', prev_location.length () - 1); + prev_location = prev_location.substring (0, i+1); + } + if (url[0] == '.' && url[1] == '/') + url.set (&url[2], 1); + + url = prev_location + url; + } + else + url.set (&url[7], 1); + // Double slash at the end works!e.g www.cs.wustl.edu/~kirthika// + if (url.find (".html") == url.npos) + url = url + "/"; + + // Create the new URL address. + ACE_URL_Addr *url_addr; + ACE_NEW_RETURN (url_addr, + ACE_URL_Addr, + 0); + Auto_Destroyer<ACE_URL_Addr> url_addr_ptr (url_addr); + if (url_addr_ptr->string_to_addr (ACE_TEXT_CHAR_TO_TCHAR (url.c_str ())) == 0) + { + HTTP_URL *http_url; + ACE_NEW_RETURN (http_url, + HTTP_URL (**url_addr_ptr, + dynamic_cast<HTTP_URL *> (&this->url_)), + 0); + URL_Command *url_command; + ACE_NEW_RETURN (url_command, + URL_Command (http_url), + 0); + + OPTIONS::instance ()->command_processor ()->insert (url_command); + } + } + return 0; +} + +URL_Iterator * +URL_Validation_Visitation_Strategy_Factory::make_header_iterator (void) +{ + URL_Iterator *i; + ACE_NEW_RETURN (i, + HTTP_Header_Iterator (*this->url_), + 0); + return i; +} + +URL_Iterator * +URL_Validation_Visitation_Strategy_Factory::make_body_iterator (void) +{ + URL_Iterator *i; + ACE_NEW_RETURN (i, + HTML_Body_Iterator (*this->url_), + 0); + return i; +} + +URL_Processing_Strategy * +URL_Validation_Visitation_Strategy_Factory::make_header_strategy (URL_Iterator &iterator) +{ + URL_Processing_Strategy *ps; + ACE_NEW_RETURN (ps, + HTTP_Header_Processing_Strategy (*this->url_, + iterator), + 0); + return ps; +} + +URL_Processing_Strategy * +URL_Validation_Visitation_Strategy_Factory::make_body_strategy (URL_Iterator &iterator) +{ + URL_Processing_Strategy *ps; + ACE_NEW_RETURN (ps, + HTML_Body_Validation_Strategy (*this->url_, + iterator, + this->visitor_context_), + 0); + return ps; +} + +int +URL_Validation_Visitation_Strategy_Factory::destroy (void) +{ + // Commit suicide. + delete this; + return 0; +} + +URL_Visitor::~URL_Visitor (void) +{ +} + +URL_Validation_Visitor::URL_Validation_Visitor (void) +{ + ACE_NEW (this->caching_connect_strategy_, + CACHED_CONNECT_STRATEGY (this->caching_strategy_)); + ACE_NEW (this->strat_connector_, + STRATEGY_CONNECTOR(0, + &creation_strategy_, + caching_connect_strategy_, + &activation_strategy_)); + if (strat_connector_ == 0) + ACE_ERROR ((LM_ERROR, + "%p %s\n" + "strategy connector creation failed")); + + +} + +URL_Validation_Visitor::~URL_Validation_Visitor (void) +{ + this->strat_connector_ = 0; + if (this->caching_connect_strategy_ != 0) + delete this->caching_connect_strategy_; +} + +URL_Validation_Visitor::URL_CACHE & +URL_Validation_Visitor::url_cache (void) +{ + return this->url_cache_; +} + +int +URL_Validation_Visitor::in_cache (const ACE_URL_Addr &url_addr) +{ + URL_Status reply_status (URL_Status::STATUS_CODE (1)); + + if (this->url_cache_.find (url_addr, reply_status) == 0) + { + ACE_DEBUG ((LM_DEBUG, + "status %d for URL %s (cached)\n", + reply_status.status (), + url_addr.addr_to_string (0))); + + // Invalid status. + if (reply_status.status () != 200) + return -1; + + return 1; + } + else + return 0; +} + +URL_Visitation_Strategy_Factory * +URL_Validation_Visitor::make_visitation_strategy_factory (URL &url) +{ + // Since this is HTTP 1.1 we'll need to establish a connection + // only once. Trying for relative paths. + + if (url.stream ().open (this->strat_connector_, + url.url_addr ()) == -1) + return 0; + + // See if we can get connected and send the GET request via the + // <HTTP_URL>. + int result = url.send_request (); + if (result == -1) + { + ACE_ERROR ((LM_ERROR, + "%p\n", + "send_request")); + if (this->url_cache_.bind (url.url_addr (), + URL_Status (URL_Status::STATUS_SERVICE_UNAVAILABLE)) == -1) + ACE_ERROR ((LM_ERROR, + "%p\n", + "bind")); + return 0; + } + // @@ Here's where we could check to see if the <url> was HTTP or + // FTP, etc. But for now we'll just assume that everything is an + // HTTP URL. + else + { + + URL_Visitation_Strategy_Factory *vs; + ACE_NEW_RETURN (vs, + URL_Validation_Visitation_Strategy_Factory (&url, + *this), + 0); + return vs; + } +} + +int +URL_Validation_Visitor::destroy (void) +{ + delete this->strat_connector_; + // Commit suicide. + delete this; + return 0; +} + +int +URL_Validation_Visitor::visit (HTTP_URL &http_url) +{ + int result = this->in_cache (http_url.url_addr ()); + if (result == 0) + { + Auto_Destroyer <URL_Visitation_Strategy_Factory> vs (this->make_visitation_strategy_factory (http_url)); + + if (*vs == 0) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "make_visitation_strategy_factory"), + -1); + + Auto_Destroyer <URL_Iterator> ihs (vs->make_header_iterator ()); + if (*ihs == 0) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "make_header_iterator"), + -1); + Auto_Destroyer <URL_Processing_Strategy> phs (vs->make_header_strategy (**ihs)); + if (*phs == 0) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "make_header_strategy"), + -1); + int phs_result = phs->execute (); + if (phs_result == -1) + ACE_DEBUG ((LM_DEBUG, + "Invalid ")); + + ACE_DEBUG ((LM_DEBUG, + "URL with status %d %s\n", + http_url.reply_status ().status (), + http_url.url_addr().addr_to_string (0))); + + // Store the http url in the cache. + if (this->url_cache ().bind (http_url.url_addr (), + http_url.reply_status ()) != 0) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n","url_cache.bind"), + -1); + + // Since it is invalid dont go further. + if (phs_result == -1) + return 0; + + // Get back if the recurse option isnt set. + if (OPTIONS::instance ()->recurse () != 1) + return 0; + + Auto_Destroyer <URL_Iterator> is (vs->make_body_iterator ()); + if (*is == 0) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "make_body_iterator"), + -1); + + Auto_Destroyer <URL_Processing_Strategy> ps (vs->make_body_strategy (**is)); + if (*ps == 0) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "make_body_strategy"), + -1); + + if (ps->execute () == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "body execute"), + -1); + + } + return 0; +} + +int +URL_Download_Visitation_Strategy_Factory::destroy (void) +{ + // Commit suicide. + delete this; + return 0; +} + +URL_Iterator * +URL_Download_Visitation_Strategy_Factory::make_header_iterator (void) +{ + return 0; +} + +URL_Iterator * +URL_Download_Visitation_Strategy_Factory::make_body_iterator (void) +{ + URL_Iterator *i; + ACE_NEW_RETURN (i, + URL_Download_Iterator (*this->url_), + 0); + return i; +} + +URL_Processing_Strategy * +URL_Download_Visitation_Strategy_Factory::make_header_strategy (URL_Iterator &iterator) +{ + // You fill in here. + ACE_UNUSED_ARG (iterator); + + return 0; +} + +URL_Processing_Strategy * +URL_Download_Visitation_Strategy_Factory::make_body_strategy (URL_Iterator &iterator) +{ + URL_Processing_Strategy *ps; + ACE_NEW_RETURN (ps, + URL_Download_Strategy (*this->url_, + iterator), + 0); + return ps; +} + +URL_Visitation_Strategy_Factory::URL_Visitation_Strategy_Factory (URL *url) + : url_ (url) +{ +} + +URL_Visitation_Strategy_Factory::~URL_Visitation_Strategy_Factory (void) +{ +} + +URL_Download_Visitation_Strategy_Factory::URL_Download_Visitation_Strategy_Factory (URL *url) + : URL_Visitation_Strategy_Factory (url) +{ +} + +URL_Validation_Visitation_Strategy_Factory::URL_Validation_Visitation_Strategy_Factory (URL *url, + URL_Validation_Visitor &visitor_context) + : URL_Visitation_Strategy_Factory (url), + visitor_context_ (visitor_context) +{ +} + +URL_Visitation_Strategy_Factory * +URL_Download_Visitor::make_visitation_strategy_factory (URL &url) +{ + // See if we can get connected and send the GET request via the + // <HTTP_URL>. + while (1) + { + int retval = url.send_request (); + if (retval != -1) + break; + + } + // @@ Here's where we could check to see if the <url> was HTTP or + // FTP, etc. But for now we'll just assume that everything is an + // HTTP URL. + URL_Visitation_Strategy_Factory *vs; + ACE_NEW_RETURN (vs, + URL_Download_Visitation_Strategy_Factory (&url), + 0); + return vs; + +} + +int +URL_Download_Visitor::destroy (void) +{ + // Commit suicide. + delete this; + return 0; +} + +int +URL_Download_Visitor::visit (HTTP_URL &http_url) +{ + Auto_Destroyer <URL_Visitation_Strategy_Factory> vs (this->make_visitation_strategy_factory (http_url)); + + if (*vs == 0) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "make_visitation_strategy_factory"), + -1); + + Auto_Destroyer <URL_Iterator> is (vs->make_body_iterator ()); + if (*is == 0) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "make_body_iterator"), + -1); + + Auto_Destroyer <URL_Processing_Strategy> ps (vs->make_body_strategy (**is)); + if (*ps == 0) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "make_body_strategy"), + -1); + + if (ps->execute () == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "body execute"), + -1); + return 0; +} diff --git a/ACE/examples/Web_Crawler/URL_Visitor.h b/ACE/examples/Web_Crawler/URL_Visitor.h new file mode 100644 index 00000000000..9f68612d629 --- /dev/null +++ b/ACE/examples/Web_Crawler/URL_Visitor.h @@ -0,0 +1,436 @@ +/* -*- C++ -*- */ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// examples/Web_Crawler +// +// = FILENAME +// URL_Visitor.h +// +// = AUTHOR +// Douglas C.Schmidt <schmidt@cs.wustl.edu> +// Kirthika Parameswaran <kirthika@cs.wustl.edu> +// ============================================================================ + +#ifndef _URL_VISITOR_H +#define _URL_VISITOR_H +#include /**/ "ace/pre.h" + +#include "ace/Strategies_T.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +#pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + + +#include "HTTP_URL.h" +#include "Iterators.h" +#include "ace/Hash_Map_Manager_T.h" +#include "ace/Caching_Strategies_T.h" +#include "ace/Cached_Connect_Strategy_T.h" +#include "Options.h" +#include "ace/Pair_T.h" + +// Forward declarations. +class URL_Validation_Visitor; + +class URL_Processing_Strategy +{ + // = TITLE + // Abstract base class for the URL processing strategy. + // + // = DESCRIPTION +public: + URL_Processing_Strategy (URL &, + URL_Iterator &); + // Constructor. + + virtual ~URL_Processing_Strategy (void); + + virtual int execute (void) = 0; + // Perform the strategy. + + virtual int destroy (void); + + // Close down the resources. + +protected: + URL &url_; + // A reference to the URL "context" that we're processing. + + URL_Iterator &iterator_; + // Iterator for the URL that we're processing. +}; + +class HTTP_Header_Processing_Strategy : public URL_Processing_Strategy +{ + // = TITLE + // Defines the HTTP header processing strategy. + // + // = DESCRIPTION +public: + HTTP_Header_Processing_Strategy (URL &, + URL_Iterator &); + // Constructor. + + virtual int execute (void); + // Perform the strategy for processing an HTTP header. +}; + +class HTML_Body_Validation_Strategy : public URL_Processing_Strategy +{ + // = TITLE + // Defines the HTML body processing strategy. + // + // = DESCRIPTION + // This class iterates through the body of an HTML file and + // recursively visits embedded links. +public: + HTML_Body_Validation_Strategy (URL &, + URL_Iterator &, + URL_Validation_Visitor &); + // Constructor. + + virtual int execute (void); + // Perform the strategy for processing an HTML file. This strategy + // iterates over the HTML file and recursively visits embedded links + // to process them, as well. + +private: + URL_Validation_Visitor &visitor_context_; + // This is the context of the visit. +}; + +class URL_Download_Strategy : public URL_Processing_Strategy +{ + // = TITLE + // Defines a URL downloading strategy. + // + // = DESCRIPTION + // This class downloads a URL's contents into a temporary file. +public: + URL_Download_Strategy (URL &, + URL_Iterator &); + // Constructor. + + virtual int execute (void); + // Perform the strategy for downloading a URL to a temporary file. +}; + +class URL_Visitation_Strategy_Factory +{ + // = TITLE + // Abstract Factory for the URL visitation strategy. + // + // = DESCRIPTION +public: + URL_Visitation_Strategy_Factory (URL *); + + /// Destructor. + virtual ~URL_Visitation_Strategy_Factory (void); + + // = Factory Methods. + virtual URL_Iterator *make_header_iterator (void) = 0; + // Factory Method that makes the header iterator. + + virtual URL_Iterator *make_body_iterator (void) = 0; + // Factory Method that makes the body iterator. + + virtual URL_Processing_Strategy *make_header_strategy (URL_Iterator &) = 0; + // Factory Method that makes the header processing strategy. + + virtual URL_Processing_Strategy *make_body_strategy (URL_Iterator &) = 0; + // Factory Method that makes the body processing strategy . + + virtual int destroy (void) = 0; + // Close down the resources. + +protected: + URL *url_; + // Stash the URL so we don't have to pass it around. +}; + +class URL_Download_Visitation_Strategy_Factory : public URL_Visitation_Strategy_Factory +{ + // = TITLE + // Concrete Factory for the URL validation visitation strategy. + // + // = DESCRIPTION +public: + URL_Download_Visitation_Strategy_Factory (URL *); + // Constructor. + + // = Factory Methods. + virtual URL_Iterator *make_header_iterator (void); + // Factory Method that makes an <HTTP_Header_Iterator>. + + virtual URL_Iterator *make_body_iterator (void); + // Factory Method that makes an <HTML_Body_Iterator>. + + virtual URL_Processing_Strategy *make_header_strategy (URL_Iterator &); + // Factory Method that makes the header processing strategy. + + virtual URL_Processing_Strategy *make_body_strategy (URL_Iterator &); + // Factory Method that makes the body processing strategy . + + virtual int destroy (void); + // Close down the resources. +}; + +class URL_Validation_Visitation_Strategy_Factory : public URL_Visitation_Strategy_Factory +{ + // = TITLE + // Concrete Factory for the URL validation visitation strategy. + // + // = DESCRIPTION +public: + URL_Validation_Visitation_Strategy_Factory (URL *, + URL_Validation_Visitor &); + // Constructor. + + // = Factory Methods. + virtual URL_Iterator *make_header_iterator (void); + // Factory Method that makes an <HTTP_Header_Iterator>. + + virtual URL_Iterator *make_body_iterator (void); + // Factory Method that makes an <HTML_Body_Iterator>. + + virtual URL_Processing_Strategy *make_header_strategy (URL_Iterator &); + // Factory Method that makes the header processing strategy. + + virtual URL_Processing_Strategy *make_body_strategy (URL_Iterator &); + // Factory Method that makes the body processing strategy . + + virtual int destroy (void); + // Close down the resources. + +private: + URL_Validation_Visitor &visitor_context_; + // Context of the visitor. +}; + +class URL_Visitor +{ + // = TITLE + // Base class for the URL Visitor. + // + // = DESCRIPTION + // This class plays the "visitor" role in the Visitor pattern. +public: + + virtual ~URL_Visitor (void); + + virtual int visit (HTTP_URL &http_url) = 0; + // Visit an <HTTP_URL>. + + // @@ + // virtual int visit (FTP_URL &http_url) = 0; + + virtual int destroy (void) = 0; + // Cleanup the resources. + +protected: + virtual URL_Visitation_Strategy_Factory *make_visitation_strategy_factory (URL &) = 0; + // Make the appropriate <URL_Visitation_Strategy_Factory>. +}; + +typedef int ATTRIBUTES; +typedef ACE_Svc_Handler <ACE_SOCK_STREAM, ACE_NULL_SYNCH> + Client_Svc_Handler; +typedef ACE_Pair<Client_Svc_Handler *, ATTRIBUTES> + CACHED_HANDLER; +typedef ACE_Refcounted_Hash_Recyclable<ACE_INET_Addr> + ACE_ADDR; +typedef ACE_Hash<ACE_ADDR> H_KEY; +typedef ACE_Equal_To<ACE_ADDR> C_KEYS; + +typedef ACE_Hash_Map_Manager_Ex<ACE_ADDR, CACHED_HANDLER, H_KEY, C_KEYS, ACE_Null_Mutex> + HASH_MAP; +typedef ACE_Hash_Map_Iterator_Ex<ACE_ADDR, CACHED_HANDLER, H_KEY, C_KEYS, ACE_Null_Mutex> + HASH_MAP_ITERATOR; +typedef ACE_Hash_Map_Reverse_Iterator_Ex<ACE_ADDR, CACHED_HANDLER, H_KEY, C_KEYS, ACE_Null_Mutex> + HASH_MAP_REVERSE_ITERATOR; + +typedef ACE_Recyclable_Handler_Cleanup_Strategy<ACE_ADDR, CACHED_HANDLER, HASH_MAP> + CLEANUP_STRATEGY; +typedef ACE_Recyclable_Handler_Caching_Utility<ACE_ADDR, CACHED_HANDLER, HASH_MAP, HASH_MAP_ITERATOR, ATTRIBUTES> + CACHING_UTILITY; + +typedef ACE_LRU_Caching_Strategy<ATTRIBUTES, CACHING_UTILITY> + LRU_CACHING_STRATEGY; + +typedef LRU_CACHING_STRATEGY + CACHING_STRATEGY; + +typedef ACE_Strategy_Connector<Client_Svc_Handler, ACE_SOCK_CONNECTOR> + STRATEGY_CONNECTOR; + +typedef ACE_NOOP_Creation_Strategy<Client_Svc_Handler> + NULL_CREATION_STRATEGY; + +typedef ACE_NOOP_Concurrency_Strategy<Client_Svc_Handler> + NULL_ACTIVATION_STRATEGY; + +typedef ACE_Cached_Connect_Strategy_Ex<Client_Svc_Handler, ACE_SOCK_CONNECTOR, CACHING_STRATEGY, ATTRIBUTES, ACE_SYNCH_NULL_MUTEX> + CACHED_CONNECT_STRATEGY; + +class URL_Validation_Visitor : public URL_Visitor +{ + // = TITLE + // Subclass that defines the URL validation visitor. + // + // = DESCRIPTION + // This class checks to make sure that the <HTTP_URL> is valid. + // If the <HTTP_URL> is an <HTML> file, it can also be used to + // recursively check that all embedded links in this file are + // valid. +public: + typedef ACE_Hash_Map_Manager <ACE_URL_Addr, URL_Status, ACE_Null_Mutex> + URL_CACHE; + + virtual int visit (HTTP_URL &http_url); + // Visit an <HTTP_URL> to make sure that it's valid. If the content + // type of the <HTTP_URL> is "text/html" and the <recursion> option + // is enabled then <visit> recursively checks each link embedded in + // the HTML page. + + // @@ + // virtual int visit (FTP_URL &http_url); + + URL_Validation_Visitor (void); + virtual int destroy (void); + // Cleanup the resources. + + URL_CACHE &url_cache (void); + // Returns a reference to the URL cache. + + + /* + + + typedef ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH> + Svc_Handler; + typedef ACE_Strategy_Connector<Svc_Handler, ACE_SOCK_CONNECTOR> + STRAT_CONNECTOR; + typedef ACE_Refcounted_Hash_Recyclable<ACE_INET_Addr> + REFCOUNTED_HASH_RECYCLABLE_ADDRESS; + typedef ACE_NOOP_Creation_Strategy<Svc_Handler> + NULL_CREATION_STRATEGY; + typedef ACE_NOOP_Concurrency_Strategy<Svc_Handler> + NULL_ACTIVATION_STRATEGY; + + typedef ACE_Hash_Map_Manager_Ex<REFCOUNTED_HASH_RECYCLABLE_ADDRESS,\ + ACE_Pair<Svc_Handler *, int>,\ + ACE_Hash<REFCOUNTED_HASH_RECYCLABLE_ADDRESS>, \ + ACE_Equal_To<REFCOUNTED_HASH_RECYCLABLE_ADDRESS>,\ + ACE_Null_Mutex> + CONNECTION_HASH_MAP; + typedef ACE_Hash_Map_Iterator_Ex<REFCOUNTED_HASH_RECYCLABLE_ADDRESS,\ + ACE_Pair<Svc_Handler *, int>,\ + ACE_Hash<REFCOUNTED_HASH_RECYCLABLE_ADDRESS>, \ + ACE_Equal_To<REFCOUNTED_HASH_RECYCLABLE_ADDRESS>,\ + ACE_Null_Mutex> + CONNECTION_HASH_MAP_ITERATOR; + typedef ACE_Hash_Map_Reverse_Iterator_Ex<REFCOUNTED_HASH_RECYCLABLE_ADDRESS,\ + ACE_Pair<Svc_Handler *, int>,\ + ACE_Hash<REFCOUNTED_HASH_RECYCLABLE_ADDRESS>, \ + ACE_Equal_To<REFCOUNTED_HASH_RECYCLABLE_ADDRESS>,\ + ACE_Null_Mutex> + CONNECTION_HASH_MAP_REVERSE_ITERATOR; + typedef ACE_Pair_Caching_Utility <REFCOUNTED_HASH_RECYCLABLE_ADDRESS, \ + ACE_Pair<Svc_Handler *, int>, \ + CONNECTION_HASH_MAP, CONNECTION_HASH_MAP_ITERATOR, int > + CACHING_STRATEGY_UTILITY; + typedef ACE_LRU_Caching_Strategy<REFCOUNTED_HASH_RECYCLABLE_ADDRESS,\ + ACE_Pair<Svc_Handler *, int>,\ + CONNECTION_HASH_MAP, int,\ + CACHING_STRATEGY_UTILITY > + LRU; + typedef ACE_Cached_Connect_Strategy_Ex<Svc_Handler,ACE_SOCK_CONNECTOR, LRU,int, ACE_SYNCH_NULL_MUTEX> + CACHED_CONNECT_STRATEGY; + */ +protected: + virtual ~URL_Validation_Visitor (void); + virtual URL_Visitation_Strategy_Factory *make_visitation_strategy_factory (URL &); + // Factory Method that makes a + // <URL_Validation_Visitation_Strategy_Factory>. + + URL_CACHE url_cache_; + // Cache the status of URLs we've already validated. + + int in_cache (const ACE_URL_Addr &url_addr); + // Check to see if the reply status of this <url_addr> is in the + // cache. Returns 1 if so, 0 if not. + + NULL_CREATION_STRATEGY creation_strategy_; + NULL_ACTIVATION_STRATEGY activation_strategy_; + + // Configure the Strategy Connector with a strategy that caches + // connection. + CACHED_CONNECT_STRATEGY *caching_connect_strategy_; + + STRATEGY_CONNECTOR *strat_connector_; + + CACHING_STRATEGY caching_strategy_; +}; + + +class URL_Download_Visitor : public URL_Visitor +{ + // = TITLE + // Subclass for the URL validtion visitor. + // + // = DESCRIPTION + // This class checks to make sure that the <HTTP_URL> is valid. +public: + virtual int visit (HTTP_URL &http_url); + // Visit an <HTTP_URL> to make sure that it's valid. If the content + // type of the <HTTP_URL> is "text/html" and the <recursion> option + // is enabled then <visit> recursively checks each link embedded in + // the HTML page. + + // @@ + // virtual int visit (FTP_URL &http_url); + + virtual int destroy (void); + // Cleanup the resources. + +protected: + URL_Visitation_Strategy_Factory *make_visitation_strategy_factory (URL &); + // Factory Method that makes a <URL_Download_Visitation_Strategy_Factory>. +}; + +template <class T> +class Auto_Destroyer +{ + // = TITLE + // Simple class that ensures the <destroy> method is called on our + // <URL_*> objects when they go out of scope. + // + // = DESCRIPTION + // This class is similar to an auto_ptr<> and should be used to + // simplify blocks of code that must create/destroy pointers to + // various <URL_*> related strategies and iterators. +public: + Auto_Destroyer (T *t): t_ (t) {} + T *operator-> (void) { return this->t_; } + T *operator *(void) { return this->t_; } + void operator= (T *t) + { + if (this->t_ != 0) + this->t_->destroy (); + this->t_ = t; + } + ~Auto_Destroyer (void) + { + if (this->t_ != 0) + t_->destroy (); + } +private: + T *t_; +}; + +#include /**/ "ace/post.h" +#endif /* _URL_VISITOR_H */ diff --git a/ACE/examples/Web_Crawler/URL_Visitor_Factory.cpp b/ACE/examples/Web_Crawler/URL_Visitor_Factory.cpp new file mode 100644 index 00000000000..1b8a316b219 --- /dev/null +++ b/ACE/examples/Web_Crawler/URL_Visitor_Factory.cpp @@ -0,0 +1,53 @@ +/* -*- C++ -*- */ +// $Id$ + +#include "URL_Visitor_Factory.h" + +ACE_RCSID (Web_Crawler, + URL_Visitor_Factory, + "$Id$") + + +URL_Visitor_Factory::~URL_Visitor_Factory (void) +{ +} + +URL_Visitor * +URL_Validation_Visitor_Factory::make_visitor (void) +{ + URL_Visitor *v; + + ACE_NEW_RETURN (v, + URL_Validation_Visitor, + 0); + + return v; +} + +Command_Processor * +URL_Validation_Visitor_Factory::make_command_processor (void) +{ + Command_Processor *cp; + + ACE_NEW_RETURN (cp, + Command_Processor, + 0); + return cp; +} + +URL_Visitor * +URL_Download_Visitor_Factory::make_visitor (void) +{ + URL_Visitor *v; + + ACE_NEW_RETURN (v, + URL_Download_Visitor, + 0); + return v; +} + +Command_Processor * +URL_Download_Visitor_Factory::make_command_processor (void) +{ + return 0; +} diff --git a/ACE/examples/Web_Crawler/URL_Visitor_Factory.h b/ACE/examples/Web_Crawler/URL_Visitor_Factory.h new file mode 100644 index 00000000000..9f484afe9f0 --- /dev/null +++ b/ACE/examples/Web_Crawler/URL_Visitor_Factory.h @@ -0,0 +1,74 @@ +/* -*- C++ -*- */ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// examples/Web_Crawler +// +// = FILENAME +// URL_Visitor_Factory.h +// +// = AUTHOR +// Douglas C. Schmidt <schmidt@cs.wustl.edu> +// +// ============================================================================ + +#ifndef _URL_VISITOR_FACTORY_H +#define _URL_VISITOR_FACTORY_H + +#include "URL_Visitor.h" +#include "Command_Processor.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +#pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +class URL_Visitor_Factory +{ + // = TITLE + // Abstract base class that creates URL visitors. + // + // = DESCRIPTION + // Subclasses define each of the Factory Methods to + // make the right objects, which all "vary" together. +public: + + /// Destructor. + virtual ~URL_Visitor_Factory (void); + + virtual URL_Visitor *make_visitor (void) = 0; + // Factory Method that makes the appropriate type of <URL_Visitor>. + + virtual Command_Processor *make_command_processor (void) = 0; + // Factory Method that makes the appropriate type of + // <Command_Processor>. +}; + +class URL_Validation_Visitor_Factory : public URL_Visitor_Factory +{ + // = TITLE + // Create a URL visitor that validates URL links. +public: + virtual URL_Visitor *make_visitor (void); + // Factory Method that makes a <URL_Validation_Visitor>. + + virtual Command_Processor *make_command_processor (void); + // Factory Method that makes a <FIFO_Command_Processor>. + + +}; + +class URL_Download_Visitor_Factory : public URL_Visitor_Factory +{ + // = TITLE + // Create a URL visitor that downloads URL links. +public: + virtual URL_Visitor *make_visitor (void); + // Factory Method that makes a <URL_Download_Visitor>. + + virtual Command_Processor *make_command_processor (void); + // Factory Method that makes a <FIFO_Command_Processor>. +}; + +#endif /* _URL_VISITOR_FACTORY_H */ diff --git a/ACE/examples/Web_Crawler/Web_Crawler.cpp b/ACE/examples/Web_Crawler/Web_Crawler.cpp new file mode 100644 index 00000000000..16639a38d73 --- /dev/null +++ b/ACE/examples/Web_Crawler/Web_Crawler.cpp @@ -0,0 +1,95 @@ +// $Id$ + +#include "Options.h" +#include "URL_Visitor_Factory.h" +#include "Web_Crawler.h" + +ACE_RCSID(Web_Crawler, Web_Crawler, "$Id$") + +Web_Crawler::~Web_Crawler (void) +{ + delete this->url_visitor_factory_; +} + +Web_Crawler::Web_Crawler (void) + : url_visitor_factory_ (0) +{ +} + +int +Web_Crawler::open (int argc, ACE_TCHAR *argv[]) +{ + if (OPTIONS::instance ()->parse_args (argc, argv) == -1) + return -1; + // @@ Put the ACE_Service_Config::open() stuff here somewhere... + else + { + // For now just hardcode this to create "validation" visitors. + ACE_NEW_RETURN (this->url_visitor_factory_, + URL_Validation_Visitor_Factory, + -1); + return 0; + } +} + +int +Web_Crawler::run (void) +{ + // Make the appropriate <URL_Visitor>. + Auto_Destroyer<URL_Visitor> visitor (this->url_visitor_factory_->make_visitor ()); + + if (*visitor == 0) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "make_visitor"), + -1); + + // Make the appropriate <Command_Processor>. + Auto_Destroyer<Command_Processor> cp (this->url_visitor_factory_->make_command_processor ()); + + if (*cp == 0) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "make_command_processor"), + -1); + + // Set the <Command_Processor> in the <Options> to make it visible. + OPTIONS::instance ()->command_processor (*cp); + + // Set the <URL_Visitor> in the <Options> to make it visible. + OPTIONS::instance ()->visitor (*visitor); + + // @@ You fill in here... + ACE_URL_Addr *url_addr; + ACE_NEW_RETURN (url_addr, + ACE_URL_Addr (OPTIONS::instance()->hostname (), + OPTIONS::instance()->path_name (), + OPTIONS::instance()->port_no ()), //KIRTHIKA + 0); + Auto_Destroyer<ACE_URL_Addr> url_addr_ptr (url_addr); + + HTTP_URL *http_url; + ACE_NEW_RETURN (http_url, + HTTP_URL (**url_addr_ptr), + 0); + + Auto_Destroyer<HTTP_URL> http_url_ptr (http_url); + + URL_Command *url_command; + ACE_NEW_RETURN (url_command, + URL_Command (*http_url_ptr), + 0); + // Auto_Destroyer<URL_Command> url_command_ptr (url_command); + + if (cp->insert (url_command) != 0) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", "insert"), + -1); + + if (cp->execute () != 0) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", "execute"), + -1); + return 0; +} + diff --git a/ACE/examples/Web_Crawler/Web_Crawler.h b/ACE/examples/Web_Crawler/Web_Crawler.h new file mode 100644 index 00000000000..01e275e2187 --- /dev/null +++ b/ACE/examples/Web_Crawler/Web_Crawler.h @@ -0,0 +1,62 @@ +/* -*- C++ -*- */ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// examples/Web_Crawler +// +// = FILENAME +// Web_Crawler.h +// +// = AUTHOR +// Douglas C. Schmidt <schmidt@cs.wustl.edu> +// +// ============================================================================ + +#ifndef _WEB_CRAWLER_H +#define _WEB_CRAWLER_H + +#include "URL_Addr.h" +#include "HTTP_URL.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +#pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +// Forward declaration. +class URL_Visitor_Factory; + +class Web_Crawler +{ + // = TITLE + // An abstraction for a Web Crawler. + // + // = DESCRIPTION + // This class is a Facade that organizes the other classes in the + // solution, which include a factory that creates a visitor, + // which in turn embodies the appropriate visitation strategy. +public: + // = Initialization and termination methods. + Web_Crawler (void); + // Constructor. + + ~Web_Crawler (void); + // Destructor. + + int open (int argc, ACE_TCHAR *argv[]); + // Parses the command-line options and initializes the + // <URL_Visitor_Factory>. + + int run (void); + // Run the Web Crawler and carries out whatever visitation strategy + // is configured. Returns -1 on failure and 0 on success. + +private: + URL_Visitor_Factory *url_visitor_factory_; + // Pointer to a factory that creates visitors that explore URLs and + // perform various tasks. Subclasses of <URL_Visitor_Factory> + // determine what happens during a visitation. +}; + +#endif /* _WEB_CRAWLER_H */ diff --git a/ACE/examples/Web_Crawler/Web_Crawler.mpc b/ACE/examples/Web_Crawler/Web_Crawler.mpc new file mode 100644 index 00000000000..7750d7cbd5d --- /dev/null +++ b/ACE/examples/Web_Crawler/Web_Crawler.mpc @@ -0,0 +1,7 @@ +// -*- MPC -*- +// $Id$ + +project : aceexe { + avoids += ace_for_tao + exename = main +} diff --git a/ACE/examples/Web_Crawler/main.cpp b/ACE/examples/Web_Crawler/main.cpp new file mode 100644 index 00000000000..1735f811b78 --- /dev/null +++ b/ACE/examples/Web_Crawler/main.cpp @@ -0,0 +1,51 @@ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// examples/Web_Crawler +// +// = FILENAME +// main.cpp +// +// = DESCRIPTION +// This program implements a Web crawler that can be configured to +// apply various strategies to URLs that it visits. +// +// = AUTHOR +// Doug Schmidt <schmidt@cs.wustl.edu> +// +// ============================================================================ + +#include "ace/OS_main.h" +#include "ace/Signal.h" +#include "Web_Crawler.h" +#include "Options.h" + +ACE_RCSID(Web_Crawler, main, "$Id$") + +void sig_handler (int) +{ + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("aborting!\n"))); + ACE_OS::abort (); +} + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ +#if !defined (ACE_HAS_WINCE) + ACE_Sig_Action sa ((ACE_SignalHandler) sig_handler, SIGFPE); +#endif + Web_Crawler crawler; + + if (crawler.open (argc, argv) == -1) + return 1; + else if (crawler.run () == -1) + return 1; + else + return 0; +} + + + diff --git a/ACE/examples/example_base.mpb b/ACE/examples/example_base.mpb new file mode 100644 index 00000000000..71b8b3452c6 --- /dev/null +++ b/ACE/examples/example_base.mpb @@ -0,0 +1,8 @@ +// -*- MPC -*- +// $Id$ + +// Anything specific to examples could be added here. +// examples.mwc uses the implicit keyword to cause this +// project to be used as the base for all examples, +project : aceexe { +}
\ No newline at end of file diff --git a/ACE/examples/examples.mwc b/ACE/examples/examples.mwc new file mode 100644 index 00000000000..975ad4e462d --- /dev/null +++ b/ACE/examples/examples.mwc @@ -0,0 +1,14 @@ +// -*- MPC -*- +// $Id$ + +workspace { + // This doesn't work quite yet, because not all the projects + // can be created implicitly. To fix this, we can either create + // a separate directory for each separate project, or we can + // add mpc files for C++NPv1/2 and other problem directories. + // The nice thing about splitting up into separate directories is + // that it completely eliminates mpc maintenance. + + implicit = example_base + cmdline += -include $PWD +} |