summaryrefslogtreecommitdiff
path: root/ACE/ace/Service_Config.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'ACE/ace/Service_Config.cpp')
-rw-r--r--ACE/ace/Service_Config.cpp632
1 files changed, 632 insertions, 0 deletions
diff --git a/ACE/ace/Service_Config.cpp b/ACE/ace/Service_Config.cpp
new file mode 100644
index 00000000000..8d0b1d8da4d
--- /dev/null
+++ b/ACE/ace/Service_Config.cpp
@@ -0,0 +1,632 @@
+// $Id$
+
+#include "ace/Service_Config.h"
+
+#if !defined (__ACE_INLINE__)
+#include "ace/Service_Config.inl"
+#endif /* __ACE_INLINE__ */
+
+#include "ace/ACE.h"
+#include "ace/Guard_T.h"
+#include "ace/Log_Msg.h"
+#include "ace/Service_Types.h"
+#include "ace/Reactor.h"
+
+#ifndef ACE_LACKS_UNIX_SIGNALS
+# include "ace/Sig_Adapter.h"
+#endif /* !ACE_LACKS_UNIX_SIGNALS */
+
+#include "ace/OS_NS_stdio.h"
+#include "ace/OS_NS_time.h"
+#include "ace/OS_NS_unistd.h"
+#include "ace/Get_Opt.h"
+#include "ace/Static_Object_Lock.h"
+
+ACE_RCSID (ace,
+ Service_Config,
+ "$Id$")
+
+ ACE_BEGIN_VERSIONED_NAMESPACE_DECL
+
+///
+ACE_Service_Config_Guard::ACE_Service_Config_Guard (ACE_Service_Gestalt * psg)
+ : saved_ (ACE_Service_Config::current ())
+{
+ if (ACE::debug ())
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_LIB_TEXT ("(%P|%t) SCG::ctor, repo=%@ - guard with %@\n"),
+ this->saved_->repo_,
+ psg->repo_));
+
+ // Modify the TSS - no locking needed
+ if (saved_ != psg)
+ (void)ACE_Service_Config::current (psg);
+}
+
+///
+ACE_Service_Config_Guard::~ACE_Service_Config_Guard (void)
+{
+ ACE_Service_Config::current (this->saved_);
+
+ if (ACE::debug ())
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_LIB_TEXT ("(%P|%t) SCG::dtor, repo=%@ - un-guard\n"),
+ this->saved_->repo_));
+}
+
+
+ACE_ALLOC_HOOK_DEFINE (ACE_Service_Config)
+
+// Set the signal handler to point to the handle_signal() function.
+ACE_Sig_Adapter *ACE_Service_Config::signal_handler_ = 0;
+
+// Trigger a reconfiguration.
+sig_atomic_t ACE_Service_Config::reconfig_occurred_ = 0;
+
+// = Set by command-line options.
+
+/// Pathname of file to write process id.
+ACE_TCHAR *ACE_Service_Config::pid_file_name_ = 0;
+
+/// Shall we become a daemon process?
+int ACE_Service_Config::be_a_daemon_ = 0;
+
+// Number of the signal used to trigger reconfiguration.
+int ACE_Service_Config::signum_ = SIGHUP;
+
+
+void
+ACE_Service_Config::dump (void) const
+{
+#if defined (ACE_HAS_DUMP)
+ ACE_TRACE ("ACE_Service_Config::dump");
+#endif /* ACE_HAS_DUMP */
+}
+
+int
+ACE_Service_Config::parse_args_i (int argc, ACE_TCHAR *argv[])
+{
+ ACE_TRACE ("ACE_Service_Config::parse_args_i");
+ ACE_Get_Opt getopt (argc,
+ argv,
+ ACE_LIB_TEXT ("bs:p:"),
+ 1); // Start at argv[1].
+
+ for (int c; (c = getopt ()) != -1; )
+ switch (c)
+ {
+ case 'p':
+ ACE_Service_Config::pid_file_name_ = getopt.opt_arg ();
+ break;
+ case 'b':
+ ACE_Service_Config::be_a_daemon_ = 1;
+ break;
+ case 's':
+ {
+ // There's no point in dealing with this on NT since it
+ // doesn't really support signals very well...
+#if !defined (ACE_LACKS_UNIX_SIGNALS)
+ ACE_Service_Config::signum_ =
+ ACE_OS::atoi (getopt.opt_arg ());
+
+ if (ACE_Reactor::instance ()->register_handler
+ (ACE_Service_Config::signum_,
+ ACE_Service_Config::signal_handler_) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_LIB_TEXT ("cannot obtain signal handler\n")),
+ -1);
+#endif /* ACE_LACKS_UNIX_SIGNALS */
+ break;
+ }
+ }
+
+ return ACE_Service_Gestalt::parse_args_i (argc, argv);
+
+} /* parse_args_i () */
+
+
+int
+ACE_Service_Config::open_i (const ACE_TCHAR program_name[],
+ const ACE_TCHAR *logger_key,
+ bool ignore_static_svcs,
+ bool ignore_default_svc_conf_file,
+ bool ignore_debug_flag)
+{
+ int result = 0;
+ ACE_TRACE ("ACE_Service_Config::open_i");
+ ACE_Log_Msg *log_msg = ACE_LOG_MSG;
+
+ if (ACE::debug ())
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) SC::open_i - this=%@, opened=%d, ")
+ ACE_TEXT ("loadstatics=%d\n"),
+ this, this->is_opened_, this->no_static_svcs_));
+
+ // Guard against reentrant processing. For example,
+ // if the singleton gestalt (ubergestalt) was already open,
+ // do not open it again...
+ // The base class open_i increments this and we are
+ // forwarding to it, so we don't have to increment here.
+ if (this->is_opened_ != 0)
+ return 0;
+
+ // Check for things we need to do on a per-process basis and which
+ // may not be safe, or wise to do an a per instance basis
+
+ // Override any defaults, if required
+ this->no_static_svcs_ = ignore_static_svcs;
+
+ // Become a daemon before doing anything else.
+ if (this->be_a_daemon_)
+ ACE::daemonize ();
+
+ // Write process id to file.
+ if (this->pid_file_name_ != 0)
+ {
+ FILE* pidf = ACE_OS::fopen (this->pid_file_name_,
+ ACE_LIB_TEXT("w"));
+
+ if (pidf != 0)
+ {
+ ACE_OS::fprintf (pidf,
+ "%ld\n",
+ static_cast<long> (ACE_OS::getpid()));
+ ACE_OS::fclose (pidf);
+ }
+ }
+
+ u_long flags = log_msg->flags ();
+
+ // Only use STDERR if the caller hasn't already set the flags.
+ if (flags == 0)
+ flags = (u_long) ACE_Log_Msg::STDERR;
+
+ const ACE_TCHAR *key = logger_key;
+
+ if (key == 0 || ACE_OS::strcmp (key, ACE_DEFAULT_LOGGER_KEY) == 0)
+ // Only use the static <logger_key_> if the caller doesn't
+ // override it in the parameter list or if the key supplied is
+ // equal to the default static logger key.
+ key = this->logger_key_;
+ else
+ ACE_SET_BITS (flags, ACE_Log_Msg::LOGGER);
+
+ if (log_msg->open (program_name,
+ flags,
+ key) == -1)
+ result = -1;
+ else
+ {
+ if (ACE::debug ())
+ ACE_DEBUG ((LM_STARTUP,
+ ACE_LIB_TEXT ("starting up daemon %n\n")));
+
+ // Initialize the Service Repository (this will still work if
+ // user forgets to define an object of type ACE_Service_Config).
+ ACE_Service_Repository::instance (ACE_Service_Config::MAX_SERVICES);
+
+ // Initialize the ACE_Reactor (the ACE_Reactor should be the
+ // same size as the ACE_Service_Repository).
+ ACE_Reactor::instance ();
+
+ // There's no point in dealing with this on NT since it doesn't
+ // really support signals very well...
+#if !defined (ACE_LACKS_UNIX_SIGNALS)
+ // Only attempt to register a signal handler for positive
+ // signal numbers.
+ if (ACE_Service_Config::signum_ > 0)
+ {
+ ACE_Sig_Set ss;
+ ss.sig_add (ACE_Service_Config::signum_);
+ if (ACE_Reactor::instance ()->register_handler
+ (ss, ACE_Service_Config::signal_handler_) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("can't register signal handler\n")));
+ }
+#endif /* ACE_LACKS_UNIX_SIGNALS */
+ }
+
+ if (result == -1)
+ return -1;
+
+ if (this->init_svc_conf_file_queue () == -1)
+ return -1;
+
+ // Check if the default file exists before attempting to queue it
+ // for processing
+ if (!ignore_default_svc_conf_file)
+ {
+ FILE *fp = ACE_OS::fopen (ACE_DEFAULT_SVC_CONF,
+ ACE_LIB_TEXT ("r"));
+ ignore_default_svc_conf_file = (fp == 0);
+ if (fp != 0)
+ ACE_OS::fclose (fp);
+ }
+
+ if (!ignore_default_svc_conf_file
+ && this->svc_conf_file_queue_->is_empty ())
+ {
+ // Load the default "svc.conf" entry here if there weren't
+ // overriding -f arguments in <parse_args>.
+ if (this->svc_conf_file_queue_->enqueue_tail
+ (ACE_TString (ACE_DEFAULT_SVC_CONF)) == -1)
+ {
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_LIB_TEXT ("%p\n"),
+ ACE_LIB_TEXT ("enqueuing ")
+ ACE_DEFAULT_SVC_CONF
+ ACE_LIB_TEXT(" file")),
+ -1);
+ }
+ }
+
+ return ACE_Service_Gestalt::open_i (program_name,
+ logger_key,
+ ignore_static_svcs,
+ ignore_default_svc_conf_file,
+ ignore_debug_flag);
+}
+
+/// Return the global configuration instance. Allways returns the same
+/// instance
+ACE_Service_Gestalt *
+ACE_Service_Config::global (void)
+{
+ return ACE_Singleton<ACE_Service_Config, ACE_SYNCH_MUTEX>::instance ();
+}
+
+
+///
+ACE_Service_Gestalt *
+ACE_Service_Config::instance (void)
+{
+ return ACE_Service_Config::current ();
+}
+
+
+// A thread-specific storage to keep a pointer to the (current) global
+// configuration. Using a pointer to avoid the order of initialization
+// debacle possible when using static class instances. The memory is
+// dynamicaly allocated and leaked from current()
+
+/// Provides access to the static ptr, containing the TSS
+/// accessor. Ensures the desired order of initialization, even when
+/// other static initializers need the value.
+ACE_Service_Config::TSS_Service_Gestalt_Ptr *& ACE_Service_Config::impl_ (void)
+{
+ /// A "straight" static ptr does not work in static builds, because
+ /// some static initializer may call current() method and assign
+ /// value to instance_ *before* the startup code has had a chance to
+ /// initialize it . This results in instance_ being "zeroed" out
+ /// after it was assigned the correct value. Having a method scoped
+ /// static guarantees that the first time the method is invoked, the
+ /// instance_ will be initialized before returning.
+
+ static TSS_Service_Gestalt_Ptr *instance_ = 0;
+
+ return instance_;
+}
+
+/// Return the configuration instance, considered "global" in the
+/// current thread. This may be the same as instance(), but on some
+/// occasions, it may be a different one. For example,
+/// ACE_Service_Config_Guard provides a way of temporarily replacing
+/// the "current" configuration instance in the context of a thread.
+ACE_Service_Gestalt *
+ACE_Service_Config::current (void)
+{
+
+ if (ACE_Service_Config::impl_ () != 0)
+ {
+ // TSS already initialized, but a new thread may need its own
+ // ptr to the process-wide gestalt.
+ if (ACE_TSS_GET (ACE_Service_Config::impl_ (), TSS_Resources)->ptr_ == 0)
+ return current_i (global ());
+
+ return ACE_TSS_GET (ACE_Service_Config::impl_ (), TSS_Resources)->ptr_;
+ }
+ else
+ {
+ // TSS not initialized yet - first thread to hit this, so doing
+ // the double-checked locking thing
+ ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon,
+ *ACE_Static_Object_Lock::instance (), 0));
+
+ if (ACE_Service_Config::impl_ () != 0)
+ {
+ // Another thread snuck in and initialized the TSS, but we
+ // still need ow own ptr to the process-wide gestalt.
+ if (ACE_TSS_GET (ACE_Service_Config::impl_ (), TSS_Resources)->ptr_ == 0)
+ return current_i (global ());
+
+ return ACE_TSS_GET (ACE_Service_Config::impl_ (), TSS_Resources)->ptr_;
+ }
+
+ return current_i (global ());
+ }
+}
+
+/// A mutator to set the "current" (TSS) gestalt instance.
+ACE_Service_Gestalt*
+ACE_Service_Config::current (ACE_Service_Gestalt *newcurrent)
+{
+ ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon,
+ *ACE_Static_Object_Lock::instance (), 0));
+
+ return current_i (newcurrent);
+}
+
+/// A private, non-locking mutator to set the "current" (TSS) gestalt instance.
+/// Make sure to call with the proper locks held!
+ACE_Service_Gestalt*
+ACE_Service_Config::current_i (ACE_Service_Gestalt *newcurrent)
+{
+ if (ACE_Service_Config::impl_ () == 0)
+ {
+ ACE_NEW_RETURN (ACE_Service_Config::impl_ (), TSS_Service_Gestalt_Ptr, 0);
+ }
+
+ ACE_TSS_GET (ACE_Service_Config::impl_ (), TSS_Resources)->ptr_ = newcurrent;
+ return newcurrent;
+}
+
+
+// This method has changed to return the gestalt instead of the
+// container, underlying the service repository and defined
+// ACE_Service_Gestalt::insert (ACE_Static_Svc_Descriptor*). This way
+// the existing source code can keep using
+// ACE_Service_Config::static_svcs(), however now it is not necessary
+// to expose the repository storage *and* it is much easier to debug
+// service registration problems.
+
+ACE_Service_Gestalt *
+ACE_Service_Config::static_svcs (void)
+{
+ return ACE_Service_Config::current ();
+}
+
+///
+int
+ACE_Service_Config::insert (ACE_Static_Svc_Descriptor* stsd)
+{
+ return ACE_Service_Config::current ()->insert (stsd);
+}
+
+
+// Totally remove <svc_name> from the daemon by removing it from the
+// ACE_Reactor, and unlinking it if necessary.
+
+int
+ACE_Service_Config::remove (const ACE_TCHAR svc_name[])
+{
+ ACE_TRACE ("ACE_Service_Config::remove");
+ return ACE_Service_Repository::instance ()->remove (svc_name);
+}
+
+// Suspend <svc_name>. Note that this will not unlink the service
+// from the daemon if it was dynamically linked, it will mark it as
+// being suspended in the Service Repository and call the <suspend>
+// member function on the appropriate <ACE_Service_Object>. A service
+// can be resumed later on by calling the <resume> method...
+
+int
+ACE_Service_Config::suspend (const ACE_TCHAR svc_name[])
+{
+ ACE_TRACE ("ACE_Service_Config::suspend");
+ return ACE_Service_Repository::instance ()->suspend (svc_name);
+}
+
+// Resume a SVC_NAME that was previously suspended or has not yet
+// been resumed (e.g., a static service).
+
+int
+ACE_Service_Config::resume (const ACE_TCHAR svc_name[])
+{
+ ACE_TRACE ("ACE_Service_Config::resume");
+ return ACE_Service_Repository::instance ()->resume (svc_name);
+}
+
+// Initialize the Service Repository. Note that this *must* be
+// performed in the constructor (rather than <open>) since otherwise
+// the repository will not be properly initialized to allow static
+// configuration of services...
+
+ACE_Service_Config::ACE_Service_Config (int ignore_static_svcs,
+ size_t size,
+ int signum)
+ : ACE_Service_Gestalt (size, false, ignore_static_svcs)
+{
+ ACE_TRACE ("ACE_Service_Config::ACE_Service_Config");
+
+ // this->no_static_svcs_ = (ignore_static_svcs);
+
+ ACE_Service_Config::signum_ = signum;
+
+ // Initialize the Service Repository.
+ // ACE_Service_Repository::instance (static_cast<int> (size));
+
+ // Initialize the ACE_Reactor (the ACE_Reactor should be the same
+ // size as the ACE_Service_Repository).
+ (void)ACE_Reactor::instance ();
+}
+
+
+#if (ACE_USES_CLASSIC_SVC_CONF == 0)
+ACE_Service_Type *
+ACE_Service_Config::create_service_type (const ACE_TCHAR *n,
+ ACE_Service_Type_Impl *o,
+ ACE_DLL &dll,
+ int active)
+{
+ ACE_Service_Type *sp = 0;
+ ACE_NEW_RETURN (sp,
+ ACE_Service_Type (n, o, dll, active),
+ 0);
+ return sp;
+}
+#endif /* ACE_USES_CLASSIC_SVC_CONF == 0 */
+
+ACE_Service_Type_Impl *
+ACE_Service_Config::create_service_type_impl (const ACE_TCHAR *name,
+ int type,
+ void *symbol,
+ u_int flags,
+ ACE_Service_Object_Exterminator gobbler)
+{
+ ACE_Service_Type_Impl *stp = 0;
+
+ // Note, the only place we need to put a case statement. This is
+ // also the place where we'd put the RTTI tests, if the compiler
+ // actually supported them!
+
+ switch (type)
+ {
+ case ACE_Service_Type::SERVICE_OBJECT:
+ ACE_NEW_RETURN (stp,
+ ACE_Service_Object_Type ((ACE_Service_Object *) symbol,
+ name, flags,
+ gobbler),
+ 0);
+ break;
+ case ACE_Service_Type::MODULE:
+ ACE_NEW_RETURN (stp,
+ ACE_Module_Type (symbol, name, flags),
+ 0);
+ break;
+ case ACE_Service_Type::STREAM:
+ ACE_NEW_RETURN (stp,
+ ACE_Stream_Type (symbol, name, flags),
+ 0);
+ break;
+ default:
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("unknown case\n")));
+ break;
+ }
+ return stp;
+
+}
+
+
+ACE_Service_Config::ACE_Service_Config (const ACE_TCHAR program_name[],
+ const ACE_TCHAR *logger_key)
+ : ACE_Service_Gestalt (ACE_Service_Repository::DEFAULT_SIZE, false)
+{
+ ACE_TRACE ("ACE_Service_Config::ACE_Service_Config");
+
+ if (this->open (program_name,
+ logger_key) == -1 && errno != ENOENT)
+ {
+
+ // Only print out an error if it wasn't the svc.conf file that was
+ // missing.
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("(%P|%t) SC failed to open: %p\n"),
+ program_name));
+ }
+}
+
+// Signal handling API to trigger dynamic reconfiguration.
+
+void
+ACE_Service_Config::handle_signal (int sig,
+ siginfo_t *,
+ ucontext_t *)
+{
+#if defined (ACE_NDEBUG)
+ ACE_UNUSED_ARG (sig);
+#else /* ! ACE_NDEBUG */
+ ACE_ASSERT (ACE_Service_Config::signum_ == sig);
+#endif /* ! ACE_NDEBUG */
+
+ ACE_Service_Config::reconfig_occurred_ = 1;
+}
+
+// Trigger the reconfiguration process.
+
+void
+ACE_Service_Config::reconfigure (void)
+{
+ ACE_TRACE ("ACE_Service_Config::reconfigure");
+
+ ACE_Service_Config::reconfig_occurred_ = 0;
+
+ if (ACE::debug ())
+ {
+#if !defined (ACE_NLOGGING)
+ time_t t = ACE_OS::time (0);
+#endif /* ! ACE_NLOGGING */
+ if (ACE::debug ())
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_LIB_TEXT ("beginning reconfiguration at %s"),
+ ACE_OS::ctime (&t)));
+ }
+ if (ACE_Service_Config::process_directives () == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("%p\n"),
+ ACE_LIB_TEXT ("process_directives")));
+}
+
+// Tidy up and perform last rites on a terminating ACE_Service_Config.
+int
+ACE_Service_Config::close (void)
+{
+ return ACE_Service_Config::current ()->close ();
+}
+
+int
+ACE_Service_Config::close_svcs (void)
+{
+ ACE_TRACE ("ACE_Service_Config::close_svcs");
+
+ ACE_Service_Repository::close_singleton ();
+
+ return 0;
+}
+
+int
+ACE_Service_Config::fini_svcs (void)
+{
+ ACE_TRACE ("ACE_Service_Config::fini_svcs");
+
+ // Clear the LM_DEBUG bit from log messages if appropriate
+ if (ACE::debug ())
+ ACE_Log_Msg::disable_debug_messages ();
+
+ int result = 0;
+ if (ACE_Service_Repository::instance () != 0)
+ result = ACE_Service_Repository::instance ()->fini ();
+
+ if (ACE::debug ())
+ ACE_Log_Msg::enable_debug_messages ();
+
+ return result;
+}
+
+// Perform user-specified close activities and remove dynamic memory.
+
+ACE_Service_Config::~ACE_Service_Config (void)
+{
+ ACE_TRACE ("ACE_Service_Config::~ACE_Service_Config");
+}
+
+// ************************************************************
+
+/* static */
+int
+ACE_Service_Config::reconfig_occurred (void)
+{
+ ACE_TRACE ("ACE_Service_Config::reconfig_occurred");
+ return ACE_Service_Config::reconfig_occurred_ != 0;
+}
+
+void
+ACE_Service_Config::reconfig_occurred (int config_occurred)
+{
+ ACE_TRACE ("ACE_Service_Config::reconfig_occurred");
+ ACE_Service_Config::reconfig_occurred_ = config_occurred;
+}
+
+// ************************************************************
+
+ACE_END_VERSIONED_NAMESPACE_DECL