Service_Gestalt.cpp

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

Generated on Sun Jan 27 12:05:37 2008 for ACE by doxygen 1.3.6