Service_Gestalt.cpp

Go to the documentation of this file.
00001 // $Id: Service_Gestalt.cpp 81673 2008-05-09 19:09:43Z iliyan $
00002 
00003 #include "ace/Svc_Conf.h"
00004 #include "ace/Get_Opt.h"
00005 #include "ace/ARGV.h"
00006 #include "ace/Malloc.h"
00007 #include "ace/Service_Manager.h"
00008 #include "ace/Service_Types.h"
00009 #include "ace/Containers.h"
00010 #include "ace/Auto_Ptr.h"
00011 #include "ace/Reactor.h"
00012 #include "ace/Thread_Manager.h"
00013 #include "ace/DLL.h"
00014 #include "ace/XML_Svc_Conf.h"
00015 #include "ace/SString.h"
00016 
00017 #ifndef ACE_LACKS_UNIX_SIGNALS
00018 # include "ace/Signal.h"
00019 #endif  /* !ACE_LACKS_UNIX_SIGNALS */
00020 
00021 #include "ace/OS_NS_stdio.h"
00022 #include "ace/OS_NS_string.h"
00023 #include "ace/OS_NS_time.h"
00024 #include "ace/OS_NS_unistd.h"
00025 #include "ace/OS_NS_sys_stat.h"
00026 
00027 #include "ace/TSS_T.h"
00028 #include "ace/Service_Gestalt.h"
00029 
00030 #include "ace/Svc_Conf_Param.h"
00031 
00032 ACE_RCSID (ace,
00033            Service_Gestalt,
00034            "$Id: Service_Gestalt.cpp 81673 2008-05-09 19:09:43Z iliyan $")
00035 
00036 ACE_BEGIN_VERSIONED_NAMESPACE_DECL
00037 
00038 ACE_Service_Type_Dynamic_Guard::ACE_Service_Type_Dynamic_Guard
00039   (ACE_Service_Repository &r, const ACE_TCHAR *name)
00040     : repo_ (r)
00041     // Relocation starts where the next service will be inserted (if any)
00042     , repo_begin_ (r.current_size ())
00043     , name_ (name)
00044 # if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0)
00045   // On this thread (for the duration of the initialize() method),
00046   // we're about to do two things that require locking: (1) fiddle
00047   // with the repository and (2) load a DLL and hence lock the
00048   // DLL_Manager.
00049   //
00050   // Now if we don't lock the repo here, it is possible that two
00051   // threads may deadlock on initialization because they can acquire
00052   // locks (1) and (2) in different order, for instance:
00053   //
00054   // T1: loads a DLL (2) and registers a service (1);
00055   //
00056   // T2: may be relocating a service (1), which could lead to a
00057   // (re)opening or uping the ref count on a DLL (2);
00058   //
00059   // To prevent this, we lock the repo here, using the repo_monitor_
00060   // member guard.
00061     , repo_monitor_ (r.lock_)
00062 #endif
00063 {
00064     if (ACE::debug ())
00065         ACE_DEBUG ((LM_DEBUG,
00066                     ACE_TEXT ("ACE (%P|%t) STDG::<ctor>, repo=%@")
00067                     ACE_TEXT(", name=%s - begining at [%d]\n"),
00068                     &this->repo_,
00069                     this->name_,
00070                     this->repo_begin_));
00071 
00072   ACE_ASSERT (this->name_ != 0); // No name?
00073 }
00074 
00075 
00076 /// Destructor
00077 
00078 ACE_Service_Type_Dynamic_Guard::~ACE_Service_Type_Dynamic_Guard (void)
00079 {
00080   const ACE_Service_Type *tmp = 0;
00081 
00082   // Lookup without ignoring suspended services. Making sure
00083   // not to ignore any inactive services, since those may be forward
00084   // declarations
00085   size_t slot = 0;
00086   int const ret = this->repo_.find_i (this->name_, slot, &tmp, false);
00087 
00088   // We inserted it (as inactive), so we expect to find it, right?
00089   if ((ret < 0 && ret != -2) || tmp == 0)
00090     {
00091       if (ACE::debug ())
00092         ACE_ERROR ((LM_WARNING,
00093                     ACE_TEXT ("ACE (%P|%t) STDG::<dtor> - Failed (%d) to find %s -> %@\n"),
00094                     ret, this->name_, tmp));
00095       return;
00096     }
00097 
00098   if (tmp->type () != 0)
00099     {
00100       // Something has registered a proper (non-forward-decl) service with
00101       // the same name as our dummy.
00102 
00103       if (ACE::debug ())
00104         ACE_DEBUG ((LM_DEBUG,
00105                     ACE_TEXT ("ACE (%P|%t) STDG::<dtor>, repo=%@ [%d], ")
00106                     ACE_TEXT ("name=%s - updating dependents [%d - %d)\n"),
00107                     &this->repo_,
00108                     slot,
00109                     this->name_,
00110                     this->repo_begin_,
00111                     this->repo_.current_size ()));
00112 
00113       // Relocate any services inserted since we were created.
00114       // Any (static, i.e. DLL = 0) services registered in
00115       // the context of this guard aren't really static because
00116       // their code belongs in the DLL's code segment
00117       this->repo_.relocate_i (this->repo_begin_, this->repo_.current_size (), tmp->dll());
00118 
00119       if (ACE::debug ())
00120         ACE_DEBUG ((LM_DEBUG,
00121                     ACE_TEXT ("ACE (%P|%t) STDG::<dtor>, repo=%@ [%d], ")
00122                     ACE_TEXT ("name=%s - loaded (type=%@, impl=%@, object=%@, active=%d)\n"),
00123                     &this->repo_,
00124                     slot,
00125                     this->name_,
00126                     tmp,
00127                     tmp->type (),
00128                     tmp->type ()->object (),
00129                     tmp->active ()));
00130     }
00131 }
00132 
00133 
00134 
00135 // ----------------------------------------
00136 
00137 ACE_Service_Gestalt::Processed_Static_Svc::
00138 Processed_Static_Svc (const ACE_Static_Svc_Descriptor *assd)
00139   :name_(0),
00140    assd_(assd)
00141 {
00142   ACE_NEW_NORETURN (name_, ACE_TCHAR[ACE_OS::strlen(assd->name_)+1]);
00143   ACE_OS::strcpy(name_,assd->name_);
00144 }
00145 
00146 ACE_Service_Gestalt::Processed_Static_Svc::~Processed_Static_Svc (void)
00147 {
00148   delete [] name_;
00149 }
00150 
00151 void
00152 ACE_Service_Gestalt::intrusive_add_ref (ACE_Service_Gestalt* g)
00153 {
00154   if (g != 0)
00155     {
00156       ++g->refcnt_;
00157       ACE_ASSERT (g->refcnt_ > 0);
00158     }
00159 }
00160 
00161 void
00162 ACE_Service_Gestalt::intrusive_remove_ref (ACE_Service_Gestalt* g)
00163 {
00164   if (g != 0)
00165     {
00166       long tmp = --g->refcnt_;
00167       if (tmp <= 0)  delete g;
00168       ACE_ASSERT (tmp >= 0);
00169     }
00170 }
00171 
00172 
00173 ACE_Service_Gestalt::~ACE_Service_Gestalt (void)
00174 {
00175 
00176   if (this->svc_repo_is_owned_)
00177     delete this->repo_;
00178 
00179   this->repo_ =0;
00180 
00181   delete this->static_svcs_;
00182   this->static_svcs_ = 0;
00183 
00184   // Delete the dynamically allocated static_svcs instance.
00185 #ifndef ACE_NLOGGING
00186   if (ACE::debug ())
00187     ACE_DEBUG ((LM_DEBUG,
00188                 ACE_TEXT ("ACE (%P|%t) SG::~SG - this=%@, pss = %@\n"),
00189                 this, this->processed_static_svcs_));
00190 #endif
00191 
00192   if (this->processed_static_svcs_ &&
00193       !this->processed_static_svcs_->is_empty())
00194     {
00195       Processed_Static_Svc **pss = 0;
00196       for (ACE_PROCESSED_STATIC_SVCS_ITERATOR iter (*this->processed_static_svcs_);
00197            iter.next (pss) != 0;
00198            iter.advance ())
00199         {
00200           delete *pss;
00201         }
00202     }
00203 
00204   delete this->processed_static_svcs_;
00205   this->processed_static_svcs_ = 0;
00206 
00207   delete this->svc_conf_file_queue_;
00208   this->svc_conf_file_queue_ = 0;
00209 }
00210 
00211 ACE_Service_Gestalt::ACE_Service_Gestalt (size_t size,
00212                                           bool svc_repo_is_owned,
00213                                           bool no_static_svcs)
00214   : svc_repo_is_owned_ (svc_repo_is_owned)
00215   , svc_repo_size_ (size)
00216   , is_opened_ (0)
00217   , logger_key_ (ACE_DEFAULT_LOGGER_KEY)
00218   , no_static_svcs_ (no_static_svcs)
00219   , svc_queue_ (0)
00220   , svc_conf_file_queue_ (0)
00221   , repo_ (0)
00222   , static_svcs_ (0)
00223   , processed_static_svcs_ (0)
00224   , refcnt_ (0)
00225 {
00226   (void)this->init_i ();
00227 
00228 #ifndef ACE_NLOGGING
00229   if (ACE::debug ())
00230     ACE_DEBUG ((LM_DEBUG,
00231                 ACE_TEXT ("ACE (%P|%t) SG::ctor - this = %@, pss = %@\n"),
00232                 this, this->processed_static_svcs_));
00233 #endif
00234 }
00235 
00236 /// Performs the common initialization tasks for a new or previously
00237 /// closed instance. Must not be virtual, as it is also called from
00238 /// the constructor.
00239 int
00240 ACE_Service_Gestalt::init_i (void)
00241 {
00242   // Only initialize the repo_ if (a) we are being constructed, or;
00243   // (b) we're being open()-ed, perhaps after previously having been
00244   // close()-ed. In both cases: repo_ == 0 and we need a repository.
00245   if (this->repo_ == 0)
00246     {
00247       if (this->svc_repo_is_owned_)
00248         {
00249           ACE_NEW_RETURN (this->repo_,
00250                           ACE_Service_Repository (this->svc_repo_size_),
00251                           -1);
00252         }
00253       else
00254         {
00255           this->repo_ =
00256             ACE_Service_Repository::instance (this->svc_repo_size_);
00257         }
00258     }
00259 
00260   if (init_svc_conf_file_queue () == -1)
00261     return -1;
00262 
00263   if ( svc_conf_file_queue_->is_empty ())
00264     {
00265       // Check if the default file exists before attempting to queue it
00266       // for processing
00267       FILE *fp = ACE_OS::fopen (ACE_DEFAULT_SVC_CONF,
00268                                 ACE_TEXT ("r"));
00269       bool skip_static_svcs = (fp == 0);
00270       if (fp != 0)
00271         ACE_OS::fclose (fp);
00272 
00273       if (!skip_static_svcs) {
00274         // Load the default "svc.conf" entry here if there weren't
00275         // overriding -f arguments in <parse_args>.
00276         if (svc_conf_file_queue_->enqueue_tail
00277             (ACE_TString (ACE_DEFAULT_SVC_CONF)) == -1)
00278           {
00279             ACE_ERROR_RETURN ((LM_ERROR,
00280                                ACE_TEXT ("%p\n"),
00281                                ACE_TEXT ("enqueuing ")
00282                                ACE_DEFAULT_SVC_CONF
00283                                ACE_TEXT(" file")),
00284                               -1);
00285           }
00286       }
00287     }
00288 
00289   return 0;
00290 }
00291 
00292 
00293 // Add the default statically-linked services to the Service
00294 // Repository.
00295 
00296 int
00297 ACE_Service_Gestalt::load_static_svcs (void)
00298 {
00299   ACE_TRACE ("ACE_Service_Gestalt::load_static_svcs");
00300 
00301   if (this->static_svcs_ == 0)
00302     return 0; // Nothing to do
00303 
00304   ACE_Static_Svc_Descriptor **ssdp = 0;
00305   for (ACE_STATIC_SVCS_ITERATOR iter (*this->static_svcs_);
00306        iter.next (ssdp) != 0;
00307        iter.advance ())
00308     {
00309       ACE_Static_Svc_Descriptor *ssd = *ssdp;
00310 
00311       if (this->process_directive (*ssd, 1) == -1)
00312         return -1;
00313     }
00314   return 0;
00315 
00316 } /* load_static_svcs () */
00317 
00318 
00319 
00320 /// Find a static service descriptor by name
00321 
00322 int
00323 ACE_Service_Gestalt::find_static_svc_descriptor (const ACE_TCHAR* name,
00324                                                  ACE_Static_Svc_Descriptor **ssd) const
00325 {
00326   ACE_TRACE ("ACE_Service_Gestalt::find_static_svc_descriptor");
00327 
00328   if (this->static_svcs_ == 0)
00329     return -1;
00330 
00331   ACE_Static_Svc_Descriptor **ssdp = 0;
00332   for (ACE_STATIC_SVCS_ITERATOR iter ( *this->static_svcs_);
00333        iter.next (ssdp) != 0;
00334        iter.advance ())
00335     {
00336       if (ACE_OS::strcmp ((*ssdp)->name_, name) == 0)
00337         {
00338           if (ssd != 0)
00339             *ssd = *ssdp;
00340 
00341           return 0;
00342         }
00343     }
00344 
00345   return -1;
00346 }
00347 
00348 /// @brief
00349 
00350 const ACE_Static_Svc_Descriptor*
00351 ACE_Service_Gestalt::find_processed_static_svc (const ACE_TCHAR* name)
00352 {
00353   if (this->processed_static_svcs_ == 0 || name == 0)
00354     return 0;
00355 
00356   Processed_Static_Svc **pss = 0;
00357   for (ACE_PROCESSED_STATIC_SVCS_ITERATOR iter (*this->processed_static_svcs_);
00358        iter.next (pss) != 0;
00359        iter.advance ())
00360     {
00361       if (ACE_OS::strcmp ((*pss)->name_, name) == 0)
00362         return (*pss)->assd_;
00363     }
00364   return 0;
00365 }
00366 
00367 
00368 
00369 /// @brief Captures a list of the direcives processed (explicitely) for this
00370 /// Gestalt so that services can be replicated in other repositories
00371 /// upon their first initialization.
00372 ///
00373 /// This is part of the mechanism ensuring distinct local instances
00374 /// for static service objects, loaded in another repository.
00375 
00376 void
00377 ACE_Service_Gestalt::add_processed_static_svc
00378   (const ACE_Static_Svc_Descriptor *assd)
00379 {
00380 
00381   /// When process_directive(Static_Svc_Descriptor&) is called, it
00382   /// associates a service object with the Gestalt and makes the
00383   /// resource (a Service Object) local to the repository. This is but
00384   /// the first step in using such SO. The next is the
00385   /// "initialization" step. It is typicaly done through a "static"
00386   /// service configuration directive.
00387   ///
00388   /// In contrast a "dynamic" directive, when processed through the
00389   /// overloaded process_directives(string) both creates the SO
00390   /// locally and initializes it, where the statics directive must
00391   /// first locate the SO and then calls the init() method. This means
00392   /// that durig the "static" initialization there's no specific
00393   /// information about the hosting repository and the gestalt must
00394   /// employ some lookup strategy to find it elsewhere.
00395 
00396   if (this->processed_static_svcs_ == 0)
00397     ACE_NEW (this->processed_static_svcs_,
00398              ACE_PROCESSED_STATIC_SVCS);
00399 
00400   Processed_Static_Svc **pss = 0;
00401   for (ACE_PROCESSED_STATIC_SVCS_ITERATOR iter (*this->processed_static_svcs_);
00402        iter.next (pss) != 0;
00403        iter.advance ())
00404     {
00405       if (ACE_OS::strcmp ((*pss)->name_, assd->name_) == 0)
00406         {
00407           (*pss)->assd_ = assd;
00408           return;
00409         }
00410     }
00411   Processed_Static_Svc *tmp = 0;
00412   ACE_NEW (tmp,Processed_Static_Svc(assd));
00413   this->processed_static_svcs_->insert(tmp);
00414 
00415   if (ACE::debug ())
00416     ACE_DEBUG ((LM_DEBUG,
00417                 ACE_TEXT ("ACE (%P|%t) SG::add_processed_static_svc, ")
00418                 ACE_TEXT ("repo=%@ - %s\n"),
00419                 this->repo_,
00420                 assd->name_));
00421 }
00422 
00423 
00424 /// Queues a static service object descriptor which, during open()
00425 /// will be given to process_directive() to create the Service
00426 /// Object. Normally, only called from static initializers, prior to
00427 /// calling open() but loading a service from a DLL can cause it too.
00428 
00429 int
00430 ACE_Service_Gestalt::insert (ACE_Static_Svc_Descriptor *stsd)
00431 {
00432   if (this->static_svcs_ == 0)
00433     ACE_NEW_RETURN (this->static_svcs_,
00434                     ACE_STATIC_SVCS,
00435                     -1);
00436 
00437   return this->static_svcs_->insert (stsd);
00438 }
00439 
00440 
00441 ACE_ALLOC_HOOK_DEFINE (ACE_Service_Gestalt)
00442 
00443 
00444 void
00445 ACE_Service_Gestalt::dump (void) const
00446 {
00447 #if defined (ACE_HAS_DUMP)
00448   ACE_TRACE ("ACE_Service_Gestalt::dump");
00449 #endif /* ACE_HAS_DUMP */
00450 }
00451 
00452 
00453 
00454 ///
00455 
00456 int
00457 ACE_Service_Gestalt::initialize (const ACE_TCHAR *svc_name,
00458                                  const ACE_TCHAR *parameters)
00459 {
00460   ACE_TRACE ("ACE_Service_Gestalt_Base::initialize (repo)");
00461   ACE_ARGV args (parameters);
00462 
00463 #ifndef ACE_NLOGGING
00464   if (ACE::debug ())
00465     {
00466       ACE_DEBUG ((LM_DEBUG,
00467                   ACE_TEXT ("ACE (%P|%t) SG::initialize - () repo=%@, ")
00468                   ACE_TEXT ("looking up static ")
00469                   ACE_TEXT ("service \'%s\' to initialize\n"),
00470                   this->repo_,
00471                   svc_name));
00472     }
00473 #endif
00474 
00475   const ACE_Service_Type *srp = 0;
00476   for (int i = 0; this->find (svc_name, &srp) == -1 && i < 2; i++)
00477     //  if (this->repo_->find (svc_name, &srp) == -1)
00478     {
00479       const ACE_Static_Svc_Descriptor *assd =
00480         ACE_Service_Config::global()->find_processed_static_svc(svc_name);
00481       if (assd != 0)
00482         {
00483           this->process_directive_i(*assd, 0);
00484         }
00485       else
00486         {
00487           ACE_ERROR_RETURN ((LM_ERROR,
00488                              ACE_TEXT ("ACE (%P|%t) ERROR: SG::initialize - service \'%s\'")
00489                              ACE_TEXT (" was not located.\n"),
00490                              svc_name),
00491                             -1);
00492         }
00493     }
00494   if (srp == 0)
00495     ACE_ERROR_RETURN ((LM_ERROR,
00496                        ACE_TEXT ("ACE (%P|%t) ERROR: SG::initialize - service \'%s\'")
00497                        ACE_TEXT (" was not located.\n"),
00498                        svc_name),
00499                       -1);
00500 
00501   /// If initialization fails ...
00502   if (srp->type ()->init (args.argc (),
00503                           args.argv ()) == -1)
00504     {
00505       // ... report and remove this entry.
00506       ACE_ERROR ((LM_ERROR,
00507                   ACE_TEXT ("ACE (%P|%t) ERROR: SG::initialize - static init of \'%s\'")
00508                   ACE_TEXT (" failed (%p)\n"),
00509                   svc_name, ACE_TEXT ("error")));
00510       this->repo_->remove (svc_name);
00511       return -1;
00512     }
00513 
00514   // If everything is ok, activate it
00515   const_cast<ACE_Service_Type *>(srp)->active (1);
00516   return 0;
00517 }
00518 
00519 
00520 #if (ACE_USES_CLASSIC_SVC_CONF == 1)
00521 int
00522 ACE_Service_Gestalt::initialize (const ACE_Service_Type_Factory *stf,
00523                                  const ACE_TCHAR *parameters)
00524 {
00525   ACE_TRACE ("ACE_Service_Gestalt::initialize");
00526 
00527 #ifndef ACE_NLOGGING
00528   if (ACE::debug ())
00529     ACE_DEBUG ((LM_DEBUG,
00530                 ACE_TEXT ("ACE (%P|%t) SG::initialize - repo=%@, name=%s")
00531                 ACE_TEXT (" - looking up in the repo\n"),
00532                 this->repo_,
00533                 stf->name ()));
00534 #endif
00535 
00536   ACE_Service_Type *srp = 0;
00537   int const retv = this->repo_->find (stf->name (),
00538                                       (const ACE_Service_Type **) &srp);
00539 
00540   // If there is an active service already, remove it first
00541   // before it can be re-installed.
00542   if (retv >= 0)
00543     {
00544 #ifndef ACE_NLOGGING
00545       if (ACE::debug ())
00546         ACE_DEBUG ((LM_WARNING,
00547                     ACE_TEXT ("ACE (%P|%t) SG::initialize - repo=%@,")
00548                     ACE_TEXT (" name=%s - removing a pre-existing namesake.\n"),
00549                     this->repo_,
00550                     stf->name ()));
00551 #endif
00552       this->repo_->remove (stf->name ());
00553     }
00554 
00555   // If there is an inactive service by that name it may have been
00556   // either inactivated, or just a forward declaration for a service,
00557   // that is in the process of being initialized. If it is the latter,
00558   // then we have detected an attempt to initialize the same dynamic
00559   // service while still processing previous attempt. This can lock up
00560   // the process, because the ACE_DLL_Manager::open () is not
00561   // re-entrant - it uses a Singleton lock to serialize concurent
00562   // invocations. This use case must be handled here, because if the
00563   // DLL_Manager was re-entrant we would have entered an infinite
00564   // recursion here.
00565   if (retv == -2 && srp->type () == 0)
00566     ACE_ERROR_RETURN ((LM_WARNING,
00567                        ACE_TEXT ("ACE (%P|%t) SG::initialize - repo=%@,")
00568                        ACE_TEXT (" name=%s - forward-declared; ")
00569                        ACE_TEXT (" recursive initialization requests are")
00570                        ACE_TEXT (" ignored.\n"),
00571                        this->repo_,
00572                        stf->name ()),
00573                       -1);
00574 
00575   // Reserve a spot for the dynamic service by inserting an incomplete
00576   // service declaration, i.e. one that can not produce a service
00577   // object if asked (a forward declaration).  This declaration
00578   // ensures maintaining the proper partial ordering of the services
00579   // with respect to their finalization. For example, dependent static
00580   // services must be registered *after* the dynamic service that
00581   // loads them, so that their finalization is complete *before*
00582   // finalizing the dynamic service.
00583   ACE_Service_Type_Dynamic_Guard dummy (*this->repo_,
00584                                         stf->name ());
00585 
00586   // make_service_type() is doing the dynamic loading and also runs
00587   // any static initializers
00588   ACE_Auto_Ptr<ACE_Service_Type> tmp (stf->make_service_type (this));
00589 
00590   if (tmp.get () != 0 &&
00591       this->initialize_i (tmp.get (), parameters) == 0)
00592     {
00593       // All good. Tthe ACE_Service_Type instance is now owned by the
00594       // repository and we should make sure it is not destroyed upon
00595       // exit from this method.
00596       tmp.release ();
00597       return 0;
00598     }
00599 
00600   return -1;
00601 }
00602 #endif /* (ACE_USES_CLASSIC_SVC_CONF == 1) */
00603 
00604 
00605 // Dynamically link the shared object file and retrieve a pointer to
00606 // the designated shared object in this file.
00607 // @note This is obsolete (and error-prone) in the presense of dynamic
00608 // services with their own static services. This method will allow those
00609 // static services to register *before* the dynamic service that owns them.
00610 // Upon finalization of the static services the process may crash, because
00611 // the dynamic service's DLL may have been already released, together with
00612 // the memory in which the static services reside.
00613 // It may not crash, for instance, when the first static service to register
00614 // is the same as the dynamic service being loaded. You should be so lucky! ..
00615 
00616 int
00617 ACE_Service_Gestalt::initialize (const ACE_Service_Type *sr,
00618                                  const ACE_TCHAR *parameters)
00619 {
00620   ACE_TRACE ("ACE_Service_Gestalt::initialize");
00621 
00622   if (ACE::debug ())
00623     ACE_DEBUG ((LM_DEBUG,
00624                 ACE_TEXT ("ACE (%P|%t) SG::initialize - repo=%@, name=%s")
00625                 ACE_TEXT (" - looking up in the repo\n"),
00626                 this->repo_,
00627                 sr->name ()));
00628 
00629   ACE_Service_Type *srp = 0;
00630   if (this->repo_->find (sr->name (),
00631                          (const ACE_Service_Type **) &srp) >= 0)
00632     {
00633 #ifndef ACE_NLOGGING
00634       ACE_DEBUG ((LM_WARNING,
00635                   ACE_TEXT ("ACE (%P|%t) SG::initialize - repo=%@, name=%s")
00636                   ACE_TEXT (" - removing a pre-existing namesake.\n"),
00637                   this->repo_,
00638                   sr->name ()));
00639 #endif
00640       this->repo_->remove (sr->name ());
00641     }
00642 
00643   return this->initialize_i (sr, parameters);
00644 
00645 }
00646 
00647 // Dynamically link the shared object file and retrieve a pointer to
00648 // the designated shared object in this file.
00649 int
00650 ACE_Service_Gestalt::initialize_i (const ACE_Service_Type *sr,
00651                                    const ACE_TCHAR *parameters)
00652 {
00653   ACE_TRACE ("ACE_Service_Gestalt::initialize_i");
00654   ACE_ARGV args (parameters);
00655   if (sr->type ()->init (args.argc (),
00656                          args.argv ()) == -1)
00657     {
00658       // We just get ps to avoid having remove() delete it.
00659       ACE_Service_Type *ps = 0;
00660       this->repo_->remove (sr->name (), &ps);
00661 
00662 #ifndef ACE_NLOGGING
00663       // Not using LM_ERROR here to avoid confusing the test harness
00664       if (ACE::debug ())
00665         ACE_ERROR_RETURN ((LM_WARNING,
00666                            ACE_TEXT ("ACE (%P|%t) SG::initialize_i -")
00667                            ACE_TEXT (" repo=%@, name=%s - remove failed: %m\n"),
00668                            this->repo_,
00669                            sr->name ()),
00670                           -1);
00671 #endif
00672       return -1;
00673     }
00674 
00675   if (this->repo_->insert (sr) == -1)
00676     {
00677 #ifndef ACE_NLOGGING
00678       // Not using LM_ERROR here to avoid confusing the test harness
00679       if (ACE::debug ())
00680         ACE_ERROR_RETURN ((LM_WARNING,
00681                            ACE_TEXT ("ACE (%P|%t) SG::initialize_i -")
00682                            ACE_TEXT (" repo=%@, name=%s - insert failed: %m\n"),
00683                            this->repo_,
00684                            sr->name ()),
00685                           -1);
00686 #endif
00687         return -1;
00688     }
00689 
00690   return 0;
00691 }
00692 
00693 // Totally remove <svc_name> from the daemon by removing it from the
00694 // ACE_Reactor, and unlinking it if necessary.
00695 
00696 int
00697 ACE_Service_Gestalt::remove (const ACE_TCHAR svc_name[])
00698 {
00699   ACE_TRACE ("ACE_Service_Gestalt::remove");
00700   if (this->repo_ == 0)
00701     return -1;
00702 
00703   return this->repo_->remove (svc_name);
00704 }
00705 
00706 // Suspend <svc_name>.  Note that this will not unlink the service
00707 // from the daemon if it was dynamically linked, it will mark it as
00708 // being suspended in the Service Repository and call the <suspend>
00709 // member function on the appropriate <ACE_Service_Object>.  A service
00710 // can be resumed later on by calling the <resume> method...
00711 
00712 int
00713 ACE_Service_Gestalt::suspend (const ACE_TCHAR svc_name[])
00714 {
00715   ACE_TRACE ("ACE_Service_Gestalt::suspend");
00716   if (this->repo_ == 0)
00717     return -1;
00718 
00719   return this->repo_->suspend (svc_name);
00720 }
00721 
00722 // Resume a SVC_NAME that was previously suspended or has not yet
00723 // been resumed (e.g., a static service).
00724 
00725 int
00726 ACE_Service_Gestalt::resume (const ACE_TCHAR svc_name[])
00727 {
00728   ACE_TRACE ("ACE_Service_Gestalt::resume");
00729   if (this->repo_ == 0)
00730     return -1;
00731 
00732   return this->repo_->resume (svc_name);
00733 }
00734 
00735 
00736 int
00737 ACE_Service_Gestalt::process_directive (const ACE_Static_Svc_Descriptor &ssd,
00738                                         bool force_replace)
00739 {
00740   int const result = process_directive_i (ssd, force_replace);
00741   if (result == 0)
00742     {
00743       this->add_processed_static_svc(&ssd);
00744     }
00745   return result;
00746 }
00747 
00748 int
00749 ACE_Service_Gestalt::process_directive_i (const ACE_Static_Svc_Descriptor &ssd,
00750                                           bool force_replace)
00751 {
00752   if (this->repo_ == 0)
00753     return -1;
00754 
00755   if (!force_replace)
00756     {
00757       if (this->repo_->find (ssd.name_, 0, 0) >= 0)
00758         {
00759           // The service is already there, just return
00760           return 0;
00761         }
00762     }
00763 
00764 
00765   ACE_Service_Object_Exterminator gobbler;
00766   void *sym = (ssd.alloc_)(&gobbler);
00767 
00768   ACE_Service_Type_Impl *stp =
00769     ACE_Service_Config::create_service_type_impl (ssd.name_,
00770                                                   ssd.type_,
00771                                                   sym,
00772                                                   ssd.flags_,
00773                                                   gobbler);
00774   if (stp == 0)
00775     return 0;
00776 
00777   ACE_Service_Type *service_type = 0;
00778 
00779   // This is just a temporary to force the compiler to use the right
00780   // constructor in ACE_Service_Type. Note that, in cases where we are
00781   // called from a static initializer which is part of a DLL, there is
00782   // not enough information about the actuall DLL in this context.
00783   ACE_DLL tmp_dll;
00784 
00785   ACE_NEW_RETURN (service_type,
00786                   ACE_Service_Type (ssd.name_,
00787                                     stp,
00788                                     tmp_dll,
00789                                     ssd.active_),
00790                   -1);
00791 
00792 #ifndef ACE_NLOGGING
00793   if (ACE::debug ())
00794     ACE_DEBUG ((LM_DEBUG,
00795                 ACE_TEXT ("ACE (%P|%t) SG::process_directive_i, ")
00796                 ACE_TEXT ("repo=%@ - %s, dll=%s, force=%d\n"),
00797                 this->repo_,
00798                 ssd.name_,
00799                 (tmp_dll.dll_name_ == 0) ? ACE_TEXT ("<null>") : tmp_dll.dll_name_,
00800                 force_replace));
00801 #endif
00802 
00803   return this->repo_->insert (service_type);
00804 }
00805 
00806 #if (ACE_USES_CLASSIC_SVC_CONF == 1)
00807 
00808 int
00809 ACE_Service_Gestalt::process_directives_i (ACE_Svc_Conf_Param *param)
00810 {
00811 #ifndef ACE_NLOGGING
00812   if (ACE::debug ())
00813     ACE_DEBUG ((LM_DEBUG,
00814                 ACE_TEXT ("ACE (%P|%t) SG::process_directives_i, ")
00815                 ACE_TEXT ("repo=%@ - %s\n"),
00816                 this->repo_,
00817                 (param->type == ACE_Svc_Conf_Param::SVC_CONF_FILE)
00818                 ? ACE_TEXT ("<from file>")
00819                 : param->source.directive));
00820 #endif
00821 
00822   // AC 970827 Skip the heap check because yacc allocates a buffer
00823   // here which will be reported as a memory leak for some reason.
00824   ACE_NO_HEAP_CHECK
00825 
00826   // Were we called in the context of the current instance?
00827   ACE_ASSERT (this == param->config);
00828 
00829   // Temporarily (for the duration of this call) make sure that *any*
00830   // static service registrations will happen with this instance. Such
00831   // registrations are possible as a side-effect of dynamically
00832   // loading a DLL, which has other static services registered. Thus
00833   // this instance will own both the DLL and those static services,
00834   // which implies that their finalization will be performed in the
00835   // correct order, i.e. prior to finalizing the DLL
00836   ACE_Service_Config_Guard guard (this);
00837 
00838   ::ace_yyparse (param);
00839 
00840   // This is a hack, better errors should be provided...
00841   if (param->yyerrno > 0)
00842     {
00843       // Always set the last error if ace_yyparse() fails.
00844       // Other code may use errno to determine the type
00845       // of problem that occurred from processing directives.
00846       ACE_OS::last_error (EINVAL);
00847       return param->yyerrno;
00848     }
00849   else
00850     return 0;
00851 }
00852 
00853 #else
00854 
00855 ACE_XML_Svc_Conf *
00856 ACE_Service_Gestalt::get_xml_svc_conf (ACE_DLL &xmldll)
00857 {
00858   if (xmldll.open (ACE_TEXT ("ACEXML_XML_Svc_Conf_Parser")) == -1)
00859     ACE_ERROR_RETURN ((LM_ERROR,
00860                        ACE_TEXT ("ACE (%P|%t) Failure to open ACEXML_XML_Svc_Conf_Parser: %p\n"),
00861                        "ACE_Service_Config::get_xml_svc_conf"),
00862                       0);
00863 
00864   void * foo =
00865     xmldll.symbol (ACE_TEXT ("_ACEXML_create_XML_Svc_Conf_Object"));
00866 
00867   ACE_XML_Svc_Conf::Factory factory =
00868     reinterpret_cast<ACE_XML_Svc_Conf::Factory> (foo);
00869   if (factory == 0)
00870     ACE_ERROR_RETURN ((LM_ERROR,
00871                        ACE_TEXT ("ACE (%P|%t) Unable to resolve factory: %p\n"),
00872                        xmldll.error ()),
00873                       0);
00874 
00875   return factory ();
00876 }
00877 #endif /* ACE_USES_CLASSIC_SVC_CONF == 1 */
00878 
00879 int
00880 ACE_Service_Gestalt::process_file (const ACE_TCHAR file[])
00881 {
00882   ACE_TRACE ("ACE_Service_Gestalt::process_file");
00883 
00884   // To avoid recursive processing of the same file and the same repository
00885   // we maintain an implicit stack of dummy "services" named after the file
00886   // being processed. Anytime we have to open a new file, we then can check
00887   // to see if it is not already being processed by searching for a dummy
00888   // service with a matching name.
00889   if (this->repo_->find (file, 0, 0) >=0)
00890     {
00891       ACE_DEBUG ((LM_WARNING,
00892                   ACE_TEXT ("ACE (%P|%t) Configuration file %s is currently")
00893                   ACE_TEXT (" being processed. Ignoring recursive process_file().\n"),
00894                   file));
00895       return 0;
00896     }
00897 
00898   // Register a dummy service as a forward decl, using the file name as name.
00899   // The entry will be automaticaly removed once the thread exits this block.
00900   ACE_Service_Type_Dynamic_Guard recursion_guard (*this->repo_,
00901                                                   file);
00902 
00903   /*
00904    * @TODO: Test with ACE_USES_CLASSIC_SVC_CONF turned off!
00905    */
00906 #if (ACE_USES_CLASSIC_SVC_CONF == 1)
00907   int result = 0;
00908 
00909   FILE *fp = ACE_OS::fopen (file,
00910                             ACE_TEXT ("r"));
00911 
00912   if (fp == 0)
00913     {
00914       // Invalid svc.conf file.  We'll report it here and break out of
00915       // the method.
00916       if (ACE::debug ())
00917         ACE_DEBUG ((LM_ERROR,
00918                     ACE_TEXT ("ACE (%P|%t): %p\n"),
00919                     file));
00920 
00921       // Use stat to find out if the file exists.  I didn't use access()
00922       // because stat is better supported on most non-unix platforms.
00923       ACE_stat exists;
00924       if (ACE_OS::stat (file, &exists) == 0)
00925         // If it exists, but we couldn't open it for reading then we
00926         // must not have permission to read it.
00927         errno = EPERM;
00928       else
00929         errno = ENOENT;
00930       result = -1;
00931     }
00932   else
00933     {
00934       ACE_Svc_Conf_Param f (this, fp);
00935 
00936       // Keep track of the number of errors.
00937       result = this->process_directives_i (&f);
00938 
00939       (void) ACE_OS::fclose (fp);
00940     }
00941   return result;
00942 #else
00943   ACE_DLL dll;
00944 
00945   auto_ptr<ACE_XML_Svc_Conf>
00946     xml_svc_conf (this->get_xml_svc_conf (dll));
00947 
00948   if (xml_svc_conf.get () == 0)
00949     return -1;
00950 
00951   return xml_svc_conf->parse_file (file);
00952 #endif /* ACE_USES_CLASSIC_SVC_CONF == 1 */
00953 }
00954 
00955 int
00956 ACE_Service_Gestalt::process_directive (const ACE_TCHAR directive[])
00957 {
00958   ACE_TRACE ("ACE_Service_Gestalt::process_directive");
00959 
00960 #ifndef ACE_NLOGGING
00961   if (ACE::debug ())
00962     ACE_DEBUG ((LM_DEBUG,
00963                 ACE_TEXT ("ACE (%P|%t) SG::process_directive, repo=%@ - %s\n"),
00964                 this->repo_,
00965                 directive));
00966 #endif
00967 
00968 #if (ACE_USES_CLASSIC_SVC_CONF == 1)
00969   ACE_UNUSED_ARG (directive);
00970 
00971   ACE_Svc_Conf_Param d (this, directive);
00972 
00973   return this->process_directives_i (&d);
00974 #else
00975   ACE_DLL dll;
00976 
00977   auto_ptr<ACE_XML_Svc_Conf>
00978     xml_svc_conf (this->get_xml_svc_conf (dll));
00979 
00980   if (xml_svc_conf.get () == 0)
00981     return -1;
00982 
00983   // Temporarily (for the duration of this call) make sure that *any* static
00984   // service registrations will happen with this instance. Such registrations
00985   // are possible as a side-effect of dynamically loading a DLL, which has
00986   // other static services registered. Thus this instance will own both the
00987   // DLL and those static services, which implies that their finalization
00988   // will be performed in the correct order, i.e. prior to finalizing the DLL
00989   ACE_Service_Config_Guard guard (this);
00990 
00991   return xml_svc_conf->parse_string (directive);
00992 #endif /* ACE_USES_CLASSIC_SVC_CONF == 1 */
00993 
00994 } /* process_directive () */
00995 
00996 
00997 int
00998 ACE_Service_Gestalt::init_svc_conf_file_queue (void)
00999 {
01000   if (this->svc_conf_file_queue_ == 0)
01001     {
01002       ACE_SVC_QUEUE *tmp = 0;
01003       ACE_NEW_RETURN (tmp,
01004           ACE_SVC_QUEUE,
01005           -1);
01006       this->svc_conf_file_queue_ = tmp;
01007     }
01008 
01009 #ifndef ACE_NLOGGING
01010   if (ACE::debug ())
01011     ACE_DEBUG ((LM_DEBUG,
01012                 ACE_TEXT ("ACE (%P|%t) SG::init_svc_conf_file_queue ")
01013                 ACE_TEXT ("- this=%@, repo=%@\n"),
01014                 this, this->repo_));
01015 #endif
01016 
01017   return 0;
01018 
01019 } /* init_svc_conf_file_queue () */
01020 
01021 
01022 int
01023 ACE_Service_Gestalt::open_i (const ACE_TCHAR /*program_name*/[],
01024                              const ACE_TCHAR* /*logger_key*/,
01025                              bool ignore_static_svcs,
01026                              bool ignore_default_svc_conf_file,
01027                              bool ignore_debug_flag)
01028 {
01029   ACE_TRACE ("ACE_Service_Gestalt::open_i");
01030   int result = 0;
01031   ACE_Log_Msg *log_msg = ACE_LOG_MSG;
01032 
01033   no_static_svcs_ = ignore_static_svcs;
01034 
01035   // Record the current log setting upon entering this thread.
01036   u_long old_process_mask = log_msg->priority_mask
01037     (ACE_Log_Msg::PROCESS);
01038 
01039   u_long old_thread_mask = log_msg->priority_mask
01040     (ACE_Log_Msg::THREAD);
01041 
01042 #ifndef ACE_NLOGGING
01043   if (ACE::debug ())
01044     ACE_DEBUG ((LM_DEBUG,
01045                 ACE_TEXT ("ACE (%P|%t) SG::open_i - this=%@, ")
01046                 ACE_TEXT ("opened=%d, loadstatics=%d\n"),
01047                 this, this->is_opened_, this->no_static_svcs_));
01048 #endif
01049 
01050   // Guard against reentrant processing. For example,
01051   // if the singleton gestalt (ubergestalt) was already open,
01052   // do not open it again...
01053   if (this->is_opened_++ != 0)
01054     return 0;
01055 
01056   if (this->init_i () != 0)
01057     return -1;
01058 
01059   if (!ignore_debug_flag)
01060     {
01061       // If -d was included as a startup parameter, the user wants debug
01062       // information printed during service initialization.
01063       if (ACE::debug ())
01064         ACE_Log_Msg::enable_debug_messages ();
01065       else
01066         // The user has requested no debugging info.
01067         ACE_Log_Msg::disable_debug_messages ();
01068     }
01069 
01070   // See if we need to load the static services.
01071   if (this->no_static_svcs_ == 0
01072       && this->load_static_svcs () == -1)
01073     result = -1;
01074   else
01075     {
01076       if (this->process_commandline_directives () == -1)
01077         result = -1;
01078       else
01079         result = this->process_directives (ignore_default_svc_conf_file);
01080     }
01081 
01082 
01083   // Reset debugging back to the way it was when we came into
01084   // into <open_i>.
01085   {
01086     // Make sure to save/restore errno properly.
01087     ACE_Errno_Guard error (errno);
01088 
01089     if (!ignore_debug_flag)
01090       {
01091         log_msg->priority_mask (old_process_mask, ACE_Log_Msg::PROCESS);
01092         log_msg->priority_mask (old_thread_mask, ACE_Log_Msg::THREAD);
01093       }
01094   }
01095 
01096   return result;
01097 } /* open_i () */
01098 
01099 
01100 int
01101 ACE_Service_Gestalt::is_opened (void)
01102 {
01103   return this->is_opened_;
01104 }
01105 
01106 int
01107 ACE_Service_Gestalt::process_commandline_directives (void)
01108 {
01109   int result = 0;
01110   if (this->svc_queue_ != 0)
01111     {
01112       ACE_TString *sptr = 0;
01113       for (ACE_SVC_QUEUE_ITERATOR iter (*this->svc_queue_);
01114            iter.next (sptr) != 0;
01115            iter.advance ())
01116         {
01117           // Process just a single directive.
01118           if (this->process_directive ((sptr->fast_rep ())) != 0)
01119             {
01120               ACE_ERROR ((LM_ERROR,
01121                           ACE_TEXT ("ACE (%P|%t) %p\n"),
01122                           ACE_TEXT ("process_directive")));
01123               result = -1;
01124             }
01125         }
01126 
01127       delete this->svc_queue_;
01128       this->svc_queue_ = 0;
01129     }
01130 
01131   return result;
01132 
01133 } /* process_commandline_directives () */
01134 
01135 
01136 int
01137 ACE_Service_Gestalt::parse_args (int argc, ACE_TCHAR *argv[])
01138 {
01139   ACE_TRACE ("ACE_Service_Gestalt::parse_args");
01140   bool unused_ignore_default_svc_conf = true;
01141   return parse_args_i (argc, argv, unused_ignore_default_svc_conf);
01142 }
01143 
01144 int
01145 ACE_Service_Gestalt::parse_args_i (int argc,
01146                                    ACE_TCHAR *argv[],
01147                                    bool &ignore_default_svc_conf_file)
01148 {
01149   ACE_TRACE ("ACE_Service_Gestalt::parse_args_i");
01150   //FUZZ: disable check_for_lack_ACE_OS
01151   ACE_Get_Opt getopt (argc,
01152                       argv,
01153                       ACE_TEXT ("df:k:nyS:"),
01154                       1); // Start at argv[1].
01155   //FUZZ: enable check_for_lack_ACE_OS
01156 
01157   if (this->init_svc_conf_file_queue () == -1)
01158     return -1;
01159 
01160   //FUZZ: disable check_for_lack_ACE_OS
01161   for (int c; (argc != 0) && ((c = getopt ()) != -1); )
01162   //FUZZ: enable check_for_lack_ACE_OS
01163     switch (c)
01164       {
01165       case 'd':
01166         ACE::debug (1);
01167         break;
01168       case 'f':
01169         if (this->svc_conf_file_queue_->enqueue_tail (ACE_TString (getopt.opt_arg ())) == -1)
01170           ACE_ERROR_RETURN ((LM_ERROR,
01171                              ACE_TEXT ("%p\n"),
01172                              ACE_TEXT ("enqueue_tail")),
01173                             -1);
01174         ignore_default_svc_conf_file = true;
01175         break;
01176       case 'k':
01177         /*
01178          * @TODO: Is this always a static storage? Shouldn't we copy
01179          * & gain ownership of the value?
01180          */
01181         this->logger_key_ = getopt.opt_arg ();
01182         break;
01183       case 'n':
01184         this->no_static_svcs_ = 1;
01185         break;
01186       case 'y':
01187         this->no_static_svcs_ = 0;
01188         break;
01189       case 'S':
01190         if (this->svc_queue_ == 0)
01191           {
01192             ACE_NEW_RETURN (this->svc_queue_,
01193                             ACE_SVC_QUEUE,
01194                             -1);
01195           }
01196 
01197         if (this->svc_queue_->enqueue_tail (ACE_TString (getopt.opt_arg ())) == -1)
01198           ACE_ERROR_RETURN ((LM_ERROR,
01199                              ACE_TEXT ("%p\n"),
01200                              ACE_TEXT ("enqueue_tail")),
01201                             -1);
01202         break;
01203       default:
01204         if (ACE::debug ())
01205           ACE_DEBUG ((LM_DEBUG,
01206                       ACE_TEXT ("ACE (%P|%t) %c is not a ACE_Service_Config option\n"),
01207                       c));
01208       }
01209 
01210   return 0;
01211 } /* parse_args_i () */
01212 
01213 
01214 
01215 // Process service configuration directives from the files queued for
01216 // processing
01217 int
01218 ACE_Service_Gestalt::process_directives (bool ignore_default_svc_conf_file)
01219 {
01220   ACE_TRACE ("ACE_Service_Gestalt::process_directives");
01221 
01222   if (this->svc_conf_file_queue_ == 0
01223       || this->svc_conf_file_queue_->is_empty ())
01224     return 0;
01225 
01226   ACE_TString *sptr = 0;
01227   ACE_TString default_svc_conf (ACE_DEFAULT_SVC_CONF);
01228 
01229   // Iterate through all the svc.conf files.
01230   for (ACE_SVC_QUEUE_ITERATOR iter (*this->svc_conf_file_queue_);
01231        iter.next (sptr) != 0;
01232        iter.advance ())
01233     {
01234       if (*sptr == default_svc_conf && ignore_default_svc_conf_file)
01235         continue;
01236 
01237       int result = this->process_file (sptr->fast_rep ());
01238       if (result < 0)
01239         return result;
01240     }
01241 
01242   return 0;
01243 
01244 } /* process_directives () */
01245 
01246 // Tidy up and perform last rites on a terminating ACE_Service_Gestalt.
01247 int
01248 ACE_Service_Gestalt::close (void)
01249 {
01250   ACE_TRACE ("ACE_Service_Gestalt::close");
01251 
01252   if (!this->is_opened_ || --this->is_opened_ != 0)
01253     return 0;
01254 
01255   // Delete the list fo svc.conf files
01256   delete this->svc_conf_file_queue_;
01257   this->svc_conf_file_queue_ = 0;
01258 
01259   if (this->processed_static_svcs_ &&
01260       !this->processed_static_svcs_->is_empty())
01261     {
01262       Processed_Static_Svc **pss = 0;
01263       for (ACE_PROCESSED_STATIC_SVCS_ITERATOR iter (*this->processed_static_svcs_);
01264            iter.next (pss) != 0;
01265            iter.advance ())
01266         {
01267           delete *pss;
01268         }
01269     }
01270   delete this->processed_static_svcs_;
01271   this->processed_static_svcs_ = 0;
01272 
01273 #ifndef ACE_NLOGGING
01274   if (ACE::debug ())
01275     ACE_DEBUG ((LM_DEBUG,
01276                 ACE_TEXT ("ACE (%P|%t) SG::close - complete this=%@, repo=%@, owned=%d\n"),
01277                 this, this->repo_, this->svc_repo_is_owned_));
01278 #endif
01279 
01280   if (this->svc_repo_is_owned_)
01281     delete this->repo_;
01282 
01283   this->repo_ = 0;
01284 
01285   return 0;
01286 } /* close () */
01287 
01288 
01289 ACE_END_VERSIONED_NAMESPACE_DECL
01290 
01291 #if !defined (__ACE_INLINE__)
01292 #include "ace/Service_Gestalt.inl"
01293 #endif /* __ACE_INLINE__ */
01294 
01295 // Allocate a Service Manager.
01296 ACE_FACTORY_DEFINE (ACE, ACE_Service_Manager)

Generated on Tue Feb 2 17:18:42 2010 for ACE by  doxygen 1.4.7