Merge pull request #2309 from mitza-oci/warnings
[ACE_TAO.git] / ACE / ace / Service_Gestalt.cpp
blob049c997fc2e49c34affdd8c4416e1b63831ec9e7
1 #include "ace/Svc_Conf.h"
2 #include "ace/Get_Opt.h"
3 #include "ace/ARGV.h"
4 #include "ace/Malloc.h"
5 #include "ace/Service_Manager.h"
6 #include "ace/Service_Types.h"
7 #include "ace/Containers.h"
8 #include "ace/Reactor.h"
9 #include "ace/Thread_Manager.h"
10 #include "ace/DLL.h"
11 #include "ace/XML_Svc_Conf.h"
12 #include "ace/SString.h"
14 #ifndef ACE_LACKS_UNIX_SIGNALS
15 # include "ace/Signal.h"
16 #endif /* !ACE_LACKS_UNIX_SIGNALS */
18 #include "ace/OS_NS_stdio.h"
19 #include "ace/OS_NS_string.h"
20 #include "ace/OS_NS_time.h"
21 #include "ace/OS_NS_unistd.h"
22 #include "ace/OS_NS_sys_stat.h"
23 #include "ace/TSS_T.h"
24 #include "ace/Service_Gestalt.h"
25 #include "ace/Svc_Conf_Param.h"
26 #include <memory>
28 ACE_BEGIN_VERSIONED_NAMESPACE_DECL
30 ACE_Service_Type_Dynamic_Guard::ACE_Service_Type_Dynamic_Guard
31 (ACE_Service_Repository &r, const ACE_TCHAR *name)
32 : repo_ (r)
33 // Relocation starts where the next service will be inserted (if any)
34 , repo_begin_ (r.current_size ())
35 , name_ (name)
36 # if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0)
37 // On this thread (for the duration of the initialize() method),
38 // we're about to do two things that require locking: (1) fiddle
39 // with the repository and (2) load a DLL and hence lock the
40 // DLL_Manager.
42 // Now if we don't lock the repo here, it is possible that two
43 // threads may deadlock on initialization because they can acquire
44 // locks (1) and (2) in different order, for instance:
46 // T1: loads a DLL (2) and registers a service (1);
48 // T2: may be relocating a service (1), which could lead to a
49 // (re)opening or uping the ref count on a DLL (2);
51 // To prevent this, we lock the repo here, using the repo_monitor_
52 // member guard.
53 , repo_monitor_ (r.lock_)
54 #endif
56 if (ACE::debug ())
57 ACELIB_DEBUG ((LM_DEBUG,
58 ACE_TEXT ("ACE (%P|%t) STDG::<ctor>, repo=%@")
59 ACE_TEXT(", name=%s - beginning at [%d]\n"),
60 &this->repo_,
61 this->name_,
62 this->repo_begin_));
64 ACE_ASSERT (this->name_ != 0); // No name?
68 /// Destructor
69 ACE_Service_Type_Dynamic_Guard::~ACE_Service_Type_Dynamic_Guard ()
71 const ACE_Service_Type *tmp = 0;
73 // Lookup without ignoring suspended services. Making sure
74 // not to ignore any inactive services, since those may be forward
75 // declarations
76 size_t slot = 0;
77 int const ret = this->repo_.find_i (this->name_, slot, &tmp, false);
79 // We inserted it (as inactive), so we expect to find it, right?
80 if ((ret < 0 && ret != -2) || tmp == 0)
82 if (ACE::debug ())
83 ACELIB_ERROR ((LM_WARNING,
84 ACE_TEXT ("ACE (%P|%t) STDG::<dtor> - Failed (%d) to find %s -> %@\n"),
85 ret, this->name_, tmp));
86 return;
89 if (tmp->type () != 0)
91 // Something has registered a proper (non-forward-decl) service with
92 // the same name as our dummy.
94 if (ACE::debug ())
95 ACELIB_DEBUG ((LM_DEBUG,
96 ACE_TEXT ("ACE (%P|%t) STDG::<dtor>, repo=%@ [%d], ")
97 ACE_TEXT ("name=%s - updating dependents [%d - %d)\n"),
98 &this->repo_,
99 slot,
100 this->name_,
101 this->repo_begin_,
102 this->repo_.current_size ()));
104 // Relocate any services inserted since we were created.
105 // Any (static, i.e. DLL = 0) services registered in
106 // the context of this guard aren't really static because
107 // their code belongs in the DLL's code segment
108 this->repo_.relocate_i (this->repo_begin_, this->repo_.current_size (), tmp->dll());
110 if (ACE::debug ())
111 ACELIB_DEBUG ((LM_DEBUG,
112 ACE_TEXT ("ACE (%P|%t) STDG::<dtor>, repo=%@ [%d], ")
113 ACE_TEXT ("name=%s - loaded (type=%@, impl=%@, object=%@, active=%d)\n"),
114 &this->repo_,
115 slot,
116 this->name_,
117 tmp,
118 tmp->type (),
119 tmp->type ()->object (),
120 tmp->active ()));
125 // ----------------------------------------
127 ACE_Service_Gestalt::Processed_Static_Svc::
128 Processed_Static_Svc (const ACE_Static_Svc_Descriptor *assd)
129 :name_(0),
130 assd_(assd)
132 #if defined (ACE_HAS_ALLOC_HOOKS)
133 ACE_ALLOCATOR_NORETURN (name_, static_cast<ACE_TCHAR*>(ACE_Allocator::instance()->malloc (sizeof(ACE_TCHAR) * (ACE_OS::strlen(assd->name_)+1))));
134 #else
135 ACE_NEW_NORETURN (name_, ACE_TCHAR[ACE_OS::strlen(assd->name_)+1]);
136 #endif /* ACE_HAS_ALLOC_HOOKS */
137 ACE_OS::strcpy(name_,assd->name_);
140 ACE_Service_Gestalt::Processed_Static_Svc::~Processed_Static_Svc ()
142 #if defined (ACE_HAS_ALLOC_HOOKS)
143 ACE_Allocator::instance()->free(name_);
144 #else
145 delete [] name_;
146 #endif /* ACE_HAS_ALLOC_HOOKS */
149 ACE_ALLOC_HOOK_DEFINE(ACE_Service_Gestalt::Processed_Static_Svc)
151 void
152 ACE_Service_Gestalt::intrusive_add_ref (ACE_Service_Gestalt* g)
154 if (g != 0)
156 ++g->refcnt_;
157 ACE_ASSERT (g->refcnt_ > 0);
161 void
162 ACE_Service_Gestalt::intrusive_remove_ref (ACE_Service_Gestalt* g)
164 if (g != 0)
166 long tmp = --g->refcnt_;
167 if (tmp <= 0) delete g;
168 ACE_ASSERT (tmp >= 0);
173 ACE_Service_Gestalt::~ACE_Service_Gestalt ()
175 if (this->svc_repo_is_owned_)
176 delete this->repo_;
178 this->repo_ =0;
180 delete this->static_svcs_;
181 this->static_svcs_ = 0;
183 // Delete the dynamically allocated static_svcs instance.
184 #ifndef ACE_NLOGGING
185 if (ACE::debug ())
186 ACELIB_DEBUG ((LM_DEBUG,
187 ACE_TEXT ("ACE (%P|%t) SG::~SG - this=%@, pss = %@\n"),
188 this, this->processed_static_svcs_));
189 #endif
191 if (this->processed_static_svcs_ &&
192 !this->processed_static_svcs_->is_empty())
194 Processed_Static_Svc **pss = 0;
195 for (ACE_PROCESSED_STATIC_SVCS_ITERATOR iter (*this->processed_static_svcs_);
196 iter.next (pss) != 0;
197 iter.advance ())
199 delete *pss;
203 delete this->processed_static_svcs_;
204 this->processed_static_svcs_ = 0;
206 delete this->svc_conf_file_queue_;
207 this->svc_conf_file_queue_ = 0;
209 delete this->svc_queue_;
210 this->svc_queue_ = 0;
213 ACE_Service_Gestalt::ACE_Service_Gestalt (size_t size,
214 bool svc_repo_is_owned,
215 bool no_static_svcs)
216 : svc_repo_is_owned_ (svc_repo_is_owned)
217 , svc_repo_size_ (size)
218 , is_opened_ (0)
219 , logger_key_ (ACE_DEFAULT_LOGGER_KEY)
220 , no_static_svcs_ (no_static_svcs)
221 , svc_queue_ (0)
222 , svc_conf_file_queue_ (0)
223 , repo_ (0)
224 , static_svcs_ (0)
225 , processed_static_svcs_ (0)
226 , refcnt_ (0)
228 (void)this->init_i ();
230 #ifndef ACE_NLOGGING
231 if (ACE::debug ())
232 ACELIB_DEBUG ((LM_DEBUG,
233 ACE_TEXT ("ACE (%P|%t) SG::ctor - this = %@, pss = %@\n"),
234 this, this->processed_static_svcs_));
235 #endif
238 /// Performs the common initialization tasks for a new or previously
239 /// closed instance. Must not be virtual, as it is also called from
240 /// the constructor.
242 ACE_Service_Gestalt::init_i ()
244 // Only initialize the repo_ if (a) we are being constructed, or;
245 // (b) we're being open()-ed, perhaps after previously having been
246 // close()-ed. In both cases: repo_ == 0 and we need a repository.
247 if (this->repo_ == 0)
249 if (this->svc_repo_is_owned_)
251 ACE_NEW_RETURN (this->repo_,
252 ACE_Service_Repository (this->svc_repo_size_),
253 -1);
255 else
257 this->repo_ =
258 ACE_Service_Repository::instance (this->svc_repo_size_);
262 if (init_svc_conf_file_queue () == -1)
263 return -1;
265 return 0;
269 /// Add the default statically-linked services to the Service
270 /// Repository.
272 ACE_Service_Gestalt::load_static_svcs ()
274 ACE_TRACE ("ACE_Service_Gestalt::load_static_svcs");
276 if (this->static_svcs_ == 0)
277 return 0; // Nothing to do
279 ACE_Static_Svc_Descriptor **ssdp = 0;
280 for (ACE_STATIC_SVCS_ITERATOR iter (*this->static_svcs_);
281 iter.next (ssdp) != 0;
282 iter.advance ())
284 ACE_Static_Svc_Descriptor *ssd = *ssdp;
286 if (this->process_directive (*ssd, 1) == -1)
287 return -1;
289 return 0;
290 } /* load_static_svcs () */
293 /// Find a static service descriptor by name
295 ACE_Service_Gestalt::find_static_svc_descriptor (const ACE_TCHAR* name,
296 ACE_Static_Svc_Descriptor **ssd) const
298 ACE_TRACE ("ACE_Service_Gestalt::find_static_svc_descriptor");
300 if (this->static_svcs_ == 0)
301 return -1;
303 ACE_Static_Svc_Descriptor **ssdp = 0;
304 for (ACE_STATIC_SVCS_ITERATOR iter ( *this->static_svcs_);
305 iter.next (ssdp) != 0;
306 iter.advance ())
308 if (ACE_OS::strcmp ((*ssdp)->name_, name) == 0)
310 if (ssd != 0)
311 *ssd = *ssdp;
313 return 0;
317 return -1;
320 /// @brief
321 const ACE_Static_Svc_Descriptor*
322 ACE_Service_Gestalt::find_processed_static_svc (const ACE_TCHAR* name)
324 if (this->processed_static_svcs_ == 0 || name == 0)
325 return 0;
327 Processed_Static_Svc **pss = 0;
328 for (ACE_PROCESSED_STATIC_SVCS_ITERATOR iter (*this->processed_static_svcs_);
329 iter.next (pss) != 0;
330 iter.advance ())
332 if (ACE_OS::strcmp ((*pss)->name_, name) == 0)
333 return (*pss)->assd_;
335 return 0;
339 /// @brief Captures a list of the direcives processed (explicitely) for this
340 /// Gestalt so that services can be replicated in other repositories
341 /// upon their first initialization.
343 /// This is part of the mechanism ensuring distinct local instances
344 /// for static service objects, loaded in another repository.
345 void
346 ACE_Service_Gestalt::add_processed_static_svc
347 (const ACE_Static_Svc_Descriptor *assd)
349 /// When process_directive(Static_Svc_Descriptor&) is called, it
350 /// associates a service object with the Gestalt and makes the
351 /// resource (a Service Object) local to the repository. This is but
352 /// the first step in using such SO. The next is the
353 /// "initialization" step. It is typically done through a "static"
354 /// service configuration directive.
356 /// In contrast a "dynamic" directive, when processed through the
357 /// overloaded process_directives(string) both creates the SO
358 /// locally and initializes it, where the statics directive must
359 /// first locate the SO and then calls the init() method. This means
360 /// that durig the "static" initialization there's no specific
361 /// information about the hosting repository and the gestalt must
362 /// employ some lookup strategy to find it elsewhere.
364 if (this->processed_static_svcs_ == 0)
365 ACE_NEW (this->processed_static_svcs_,
366 ACE_PROCESSED_STATIC_SVCS);
368 Processed_Static_Svc **pss = 0;
369 for (ACE_PROCESSED_STATIC_SVCS_ITERATOR iter (*this->processed_static_svcs_);
370 iter.next (pss) != 0;
371 iter.advance ())
373 if (ACE_OS::strcmp ((*pss)->name_, assd->name_) == 0)
375 (*pss)->assd_ = assd;
376 return;
379 Processed_Static_Svc *tmp = 0;
380 ACE_NEW (tmp,Processed_Static_Svc(assd));
381 this->processed_static_svcs_->insert(tmp);
383 if (ACE::debug ())
384 ACELIB_DEBUG ((LM_DEBUG,
385 ACE_TEXT ("ACE (%P|%t) SG::add_processed_static_svc, ")
386 ACE_TEXT ("repo=%@ - %s\n"),
387 this->repo_,
388 assd->name_));
392 /// Queues a static service object descriptor which, during open()
393 /// will be given to process_directive() to create the Service
394 /// Object. Normally, only called from static initializers, prior to
395 /// calling open() but loading a service from a DLL can cause it too.
398 ACE_Service_Gestalt::insert (ACE_Static_Svc_Descriptor *stsd)
400 if (this->static_svcs_ == 0)
401 ACE_NEW_RETURN (this->static_svcs_,
402 ACE_STATIC_SVCS,
403 -1);
405 return this->static_svcs_->insert (stsd);
409 ACE_ALLOC_HOOK_DEFINE (ACE_Service_Gestalt)
412 void
413 ACE_Service_Gestalt::dump () const
415 #if defined (ACE_HAS_DUMP)
416 ACE_TRACE ("ACE_Service_Gestalt::dump");
417 #endif /* ACE_HAS_DUMP */
421 ACE_Service_Gestalt::initialize (const ACE_TCHAR *svc_name,
422 const ACE_TCHAR *parameters)
424 ACE_TRACE ("ACE_Service_Gestalt_Base::initialize (repo)");
425 ACE_ARGV args (parameters);
427 #ifndef ACE_NLOGGING
428 if (ACE::debug ())
430 ACELIB_DEBUG ((LM_DEBUG,
431 ACE_TEXT ("ACE (%P|%t) SG::initialize - () repo=%@, ")
432 ACE_TEXT ("looking up static ")
433 ACE_TEXT ("service \'%s\' to initialize\n"),
434 this->repo_,
435 svc_name));
437 #endif
439 const ACE_Service_Type *srp = 0;
440 for (int i = 0; this->find (svc_name, &srp) == -1 && i < 2; i++)
441 // if (this->repo_->find (svc_name, &srp) == -1)
443 const ACE_Static_Svc_Descriptor *assd =
444 ACE_Service_Config::global()->find_processed_static_svc(svc_name);
445 if (assd != 0)
447 this->process_directive_i(*assd, 0);
449 else
451 ACELIB_ERROR_RETURN ((LM_ERROR,
452 ACE_TEXT ("ACE (%P|%t) ERROR: SG::initialize - service \'%s\'")
453 ACE_TEXT (" was not located.\n"),
454 svc_name),
455 -1);
458 if (srp == 0)
459 ACELIB_ERROR_RETURN ((LM_ERROR,
460 ACE_TEXT ("ACE (%P|%t) ERROR: SG::initialize - service \'%s\'")
461 ACE_TEXT (" was not located.\n"),
462 svc_name),
463 -1);
465 /// If initialization fails ...
466 if (srp->type ()->init (args.argc (),
467 args.argv ()) == -1)
469 // ... report and remove this entry.
470 ACELIB_ERROR ((LM_ERROR,
471 ACE_TEXT ("ACE (%P|%t) ERROR: SG::initialize - static init of \'%s\'")
472 ACE_TEXT (" failed (%p)\n"),
473 svc_name, ACE_TEXT ("error")));
474 this->repo_->remove (svc_name);
475 return -1;
478 // If everything is ok, activate it
479 const_cast<ACE_Service_Type *>(srp)->active (1);
480 return 0;
484 #if (ACE_USES_CLASSIC_SVC_CONF == 1)
486 ACE_Service_Gestalt::initialize (const ACE_Service_Type_Factory *stf,
487 const ACE_TCHAR *parameters)
489 ACE_TRACE ("ACE_Service_Gestalt::initialize");
491 #ifndef ACE_NLOGGING
492 if (ACE::debug ())
493 ACELIB_DEBUG ((LM_DEBUG,
494 ACE_TEXT ("ACE (%P|%t) SG::initialize - repo=%@, name=%s")
495 ACE_TEXT (" - looking up in the repo\n"),
496 this->repo_,
497 stf->name ()));
498 #endif
500 ACE_Service_Type *srp = 0;
501 int const retv = this->repo_->find (stf->name (),
502 (const ACE_Service_Type **) &srp);
504 // If there is an active service already, remove it first
505 // before it can be re-installed.
506 if (retv >= 0)
508 #ifndef ACE_NLOGGING
509 if (ACE::debug ())
510 ACELIB_DEBUG ((LM_WARNING,
511 ACE_TEXT ("ACE (%P|%t) SG::initialize - repo=%@,")
512 ACE_TEXT (" name=%s - removing a pre-existing namesake.\n"),
513 this->repo_,
514 stf->name ()));
515 #endif
516 this->repo_->remove (stf->name ());
519 // If there is an inactive service by that name it may have been
520 // either inactivated, or just a forward declaration for a service,
521 // that is in the process of being initialized. If it is the latter,
522 // then we have detected an attempt to initialize the same dynamic
523 // service while still processing previous attempt. This can lock up
524 // the process, because the ACE_DLL_Manager::open () is not
525 // re-entrant - it uses a Singleton lock to serialize concurent
526 // invocations. This use case must be handled here, because if the
527 // DLL_Manager was re-entrant we would have entered an infinite
528 // recursion here.
529 if (retv == -2 && srp->type () == 0)
530 ACELIB_ERROR_RETURN ((LM_WARNING,
531 ACE_TEXT ("ACE (%P|%t) SG::initialize - repo=%@,")
532 ACE_TEXT (" name=%s - forward-declared; ")
533 ACE_TEXT (" recursive initialization requests are")
534 ACE_TEXT (" ignored.\n"),
535 this->repo_,
536 stf->name ()),
537 -1);
539 // Reserve a spot for the dynamic service by inserting an incomplete
540 // service declaration, i.e. one that can not produce a service
541 // object if asked (a forward declaration). This declaration
542 // ensures maintaining the proper partial ordering of the services
543 // with respect to their finalization. For example, dependent static
544 // services must be registered *after* the dynamic service that
545 // loads them, so that their finalization is complete *before*
546 // finalizing the dynamic service.
547 ACE_Service_Type_Dynamic_Guard dummy (*this->repo_,
548 stf->name ());
550 // make_service_type() is doing the dynamic loading and also runs
551 // any static initializers
552 std::unique_ptr<ACE_Service_Type> tmp (stf->make_service_type (this));
554 if (tmp.get () != 0 &&
555 this->initialize_i (tmp.get (), parameters) == 0)
557 // All good. Tthe ACE_Service_Type instance is now owned by the
558 // repository and we should make sure it is not destroyed upon
559 // exit from this method.
560 tmp.release ();
561 return 0;
564 return -1;
566 #endif /* (ACE_USES_CLASSIC_SVC_CONF == 1) */
569 /// Dynamically link the shared object file and retrieve a pointer to
570 /// the designated shared object in this file.
571 /// @note This is obsolete (and error-prone) in the presense of dynamic
572 /// services with their own static services. This method will allow those
573 /// static services to register *before* the dynamic service that owns them.
574 /// Upon finalization of the static services the process may crash, because
575 /// the dynamic service's DLL may have been already released, together with
576 /// the memory in which the static services reside.
577 /// It may not crash, for instance, when the first static service to register
578 /// is the same as the dynamic service being loaded. You should be so lucky! ..
580 ACE_Service_Gestalt::initialize (const ACE_Service_Type *sr,
581 const ACE_TCHAR *parameters)
583 ACE_TRACE ("ACE_Service_Gestalt::initialize");
585 if (ACE::debug ())
586 ACELIB_DEBUG ((LM_DEBUG,
587 ACE_TEXT ("ACE (%P|%t) SG::initialize - repo=%@, name=%s")
588 ACE_TEXT (" - looking up in the repo\n"),
589 this->repo_,
590 sr->name ()));
592 ACE_Service_Type *srp = 0;
593 if (this->repo_->find (sr->name (),
594 (const ACE_Service_Type **) &srp) >= 0)
596 #ifndef ACE_NLOGGING
597 ACELIB_DEBUG ((LM_WARNING,
598 ACE_TEXT ("ACE (%P|%t) SG::initialize - repo=%@, name=%s")
599 ACE_TEXT (" - removing a pre-existing namesake.\n"),
600 this->repo_,
601 sr->name ()));
602 #endif
603 this->repo_->remove (sr->name ());
606 return this->initialize_i (sr, parameters);
609 /// Dynamically link the shared object file and retrieve a pointer to
610 /// the designated shared object in this file.
612 ACE_Service_Gestalt::initialize_i (const ACE_Service_Type *sr,
613 const ACE_TCHAR *parameters)
615 ACE_TRACE ("ACE_Service_Gestalt::initialize_i");
616 ACE_ARGV args (parameters);
617 if (sr->type ()->init (args.argc (),
618 args.argv ()) == -1)
620 // We just get ps to avoid having remove() delete it.
621 ACE_Service_Type *ps = 0;
622 this->repo_->remove (sr->name (), &ps);
624 #ifndef ACE_NLOGGING
625 // Not using LM_ERROR here to avoid confusing the test harness
626 if (ACE::debug ())
627 ACELIB_ERROR_RETURN ((LM_WARNING,
628 ACE_TEXT ("ACE (%P|%t) SG::initialize_i -")
629 ACE_TEXT (" repo=%@, name=%s - remove failed: %m\n"),
630 this->repo_,
631 sr->name ()),
632 -1);
633 #endif
634 return -1;
637 if (this->repo_->insert (sr) == -1)
639 #ifndef ACE_NLOGGING
640 // Not using LM_ERROR here to avoid confusing the test harness
641 if (ACE::debug ())
642 ACELIB_ERROR_RETURN ((LM_WARNING,
643 ACE_TEXT ("ACE (%P|%t) SG::initialize_i -")
644 ACE_TEXT (" repo=%@, name=%s - insert failed: %m\n"),
645 this->repo_,
646 sr->name ()),
647 -1);
648 #endif
649 return -1;
652 return 0;
655 // Totally remove <svc_name> from the daemon by removing it from the
656 // ACE_Reactor, and unlinking it if necessary.
659 ACE_Service_Gestalt::remove (const ACE_TCHAR svc_name[])
661 ACE_TRACE ("ACE_Service_Gestalt::remove");
662 if (this->repo_ == 0)
663 return -1;
665 return this->repo_->remove (svc_name);
668 /// Suspend @a svc_name. Note that this will not unlink the service
669 /// from the daemon if it was dynamically linked, it will mark it as
670 /// being suspended in the Service Repository and call the <suspend>
671 /// member function on the appropriate <ACE_Service_Object>. A service
672 /// can be resumed later on by calling the <resume> method...
674 ACE_Service_Gestalt::suspend (const ACE_TCHAR svc_name[])
676 ACE_TRACE ("ACE_Service_Gestalt::suspend");
677 if (this->repo_ == 0)
678 return -1;
680 return this->repo_->suspend (svc_name);
683 // Resume a SVC_NAME that was previously suspended or has not yet
684 // been resumed (e.g., a static service).
687 ACE_Service_Gestalt::resume (const ACE_TCHAR svc_name[])
689 ACE_TRACE ("ACE_Service_Gestalt::resume");
690 if (this->repo_ == 0)
691 return -1;
693 return this->repo_->resume (svc_name);
698 ACE_Service_Gestalt::process_directive (const ACE_Static_Svc_Descriptor &ssd,
699 bool force_replace)
701 int const result = process_directive_i (ssd, force_replace);
702 if (result == 0)
704 this->add_processed_static_svc(&ssd);
706 return result;
710 ACE_Service_Gestalt::process_directive_i (const ACE_Static_Svc_Descriptor &ssd,
711 bool force_replace)
713 if (this->repo_ == 0)
714 return -1;
716 if (!force_replace)
718 if (this->repo_->find (ssd.name_, 0, 0) >= 0)
720 // The service is already there, just return
721 return 0;
726 ACE_Service_Object_Exterminator gobbler;
727 void *sym = (ssd.alloc_)(&gobbler);
729 ACE_Service_Type_Impl *stp =
730 ACE_Service_Config::create_service_type_impl (ssd.name_,
731 ssd.type_,
732 sym,
733 ssd.flags_,
734 gobbler);
735 if (stp == 0)
736 return 0;
738 ACE_Service_Type *service_type = 0;
740 // This is just a temporary to force the compiler to use the right
741 // constructor in ACE_Service_Type. Note that, in cases where we are
742 // called from a static initializer which is part of a DLL, there is
743 // not enough information about the actuall DLL in this context.
744 ACE_DLL tmp_dll;
746 ACE_NEW_RETURN (service_type,
747 ACE_Service_Type (ssd.name_,
748 stp,
749 tmp_dll,
750 ssd.active_),
751 -1);
753 #ifndef ACE_NLOGGING
754 if (ACE::debug ())
755 ACELIB_DEBUG ((LM_DEBUG,
756 ACE_TEXT ("ACE (%P|%t) SG::process_directive_i, ")
757 ACE_TEXT ("repo=%@ - %s, dll=%s, force=%d\n"),
758 this->repo_,
759 ssd.name_,
760 (tmp_dll.dll_name_ == 0) ? ACE_TEXT ("<null>") : tmp_dll.dll_name_,
761 force_replace));
762 #endif
764 return this->repo_->insert (service_type);
767 #if (ACE_USES_CLASSIC_SVC_CONF == 1)
770 ACE_Service_Gestalt::process_directives_i (ACE_Svc_Conf_Param *param)
772 #ifndef ACE_NLOGGING
773 if (ACE::debug ())
774 ACELIB_DEBUG ((LM_DEBUG,
775 ACE_TEXT ("ACE (%P|%t) SG::process_directives_i, ")
776 ACE_TEXT ("repo=%@ - %s\n"),
777 this->repo_,
778 (param->type == ACE_Svc_Conf_Param::SVC_CONF_FILE)
779 ? ACE_TEXT ("<from file>")
780 : param->source.directive));
781 #endif
783 // Were we called in the context of the current instance?
784 ACE_ASSERT (this == param->config);
786 // Temporarily (for the duration of this call) make sure that *any*
787 // static service registrations will happen with this instance. Such
788 // registrations are possible as a side-effect of dynamically
789 // loading a DLL, which has other static services registered. Thus
790 // this instance will own both the DLL and those static services,
791 // which implies that their finalization will be performed in the
792 // correct order, i.e. prior to finalizing the DLL
793 ACE_Service_Config_Guard guard (this);
795 ::ace_yyparse (param);
797 // This is a hack, better errors should be provided...
798 if (param->yyerrno > 0)
800 // Always set the last error if ace_yyparse() fails.
801 // Other code may use errno to determine the type
802 // of problem that occurred from processing directives.
803 ACE_OS::last_error (EINVAL);
804 return param->yyerrno;
806 else
807 return 0;
810 #else
812 ACE_XML_Svc_Conf *
813 ACE_Service_Gestalt::get_xml_svc_conf (ACE_DLL &xmldll)
815 if (xmldll.open (ACE_TEXT ("ACEXML_XML_Svc_Conf_Parser")) == -1)
816 ACELIB_ERROR_RETURN ((LM_ERROR,
817 ACE_TEXT ("ACE (%P|%t) Failure to open ACEXML_XML_Svc_Conf_Parser: %p\n"),
818 ACE_TEXT("ACE_Service_Config::get_xml_svc_conf")),
821 void * foo = xmldll.symbol (ACE_TEXT ("_ACEXML_create_XML_Svc_Conf_Object"));
822 intptr_t const temp_p = reinterpret_cast<intptr_t> (foo);
824 ACE_XML_Svc_Conf::Factory factory = reinterpret_cast<ACE_XML_Svc_Conf::Factory> (temp_p);
826 if (factory == 0)
827 ACELIB_ERROR_RETURN ((LM_ERROR,
828 ACE_TEXT ("ACE (%P|%t) Unable to resolve factory: %p\n"),
829 xmldll.error ()),
832 return factory ();
834 #endif /* ACE_USES_CLASSIC_SVC_CONF == 1 */
837 ACE_Service_Gestalt::process_file (const ACE_TCHAR file[])
839 ACE_TRACE ("ACE_Service_Gestalt::process_file");
841 // To avoid recursive processing of the same file and the same repository
842 // we maintain an implicit stack of dummy "services" named after the file
843 // being processed. Anytime we have to open a new file, we then can check
844 // to see if it is not already being processed by searching for a dummy
845 // service with a matching name.
846 if (this->repo_->find (file, 0, 0) >=0)
848 ACELIB_DEBUG ((LM_WARNING,
849 ACE_TEXT ("ACE (%P|%t) Configuration file %s is currently")
850 ACE_TEXT (" being processed. Ignoring recursive process_file().\n"),
851 file));
852 return 0;
855 // Register a dummy service as a forward decl, using the file name as name.
856 // The entry will be automaticaly removed once the thread exits this block.
857 ACE_Service_Type_Dynamic_Guard recursion_guard (*this->repo_,
858 file);
861 * @TODO: Test with ACE_USES_CLASSIC_SVC_CONF turned off!
863 #if (ACE_USES_CLASSIC_SVC_CONF == 1)
864 int result = 0;
866 FILE *fp = ACE_OS::fopen (file,
867 ACE_TEXT ("r"));
869 if (fp == 0)
871 // Invalid svc.conf file. We'll report it here and break out of
872 // the method.
873 if (ACE::debug ())
874 ACELIB_DEBUG ((LM_ERROR,
875 ACE_TEXT ("ACE (%P|%t): %p\n"),
876 file));
878 // Use stat to find out if the file exists. I didn't use access()
879 // because stat is better supported on most non-unix platforms.
880 ACE_stat exists;
881 if (ACE_OS::stat (file, &exists) == 0)
882 // If it exists, but we couldn't open it for reading then we
883 // must not have permission to read it.
884 errno = EPERM;
885 else
886 errno = ENOENT;
887 result = -1;
889 else
891 ACE_Svc_Conf_Param f (this, fp);
893 // Keep track of the number of errors.
894 result = this->process_directives_i (&f);
896 (void) ACE_OS::fclose (fp);
898 return result;
899 #else
900 ACE_DLL dll;
902 std::unique_ptr<ACE_XML_Svc_Conf> xml_svc_conf (this->get_xml_svc_conf (dll));
904 if (xml_svc_conf.get () == 0)
905 return -1;
907 return xml_svc_conf->parse_file (file);
908 #endif /* ACE_USES_CLASSIC_SVC_CONF == 1 */
912 ACE_Service_Gestalt::process_directive (const ACE_TCHAR directive[])
914 ACE_TRACE ("ACE_Service_Gestalt::process_directive");
916 #ifndef ACE_NLOGGING
917 if (ACE::debug ())
918 ACELIB_DEBUG ((LM_DEBUG,
919 ACE_TEXT ("ACE (%P|%t) SG::process_directive, repo=%@ - %s\n"),
920 this->repo_,
921 directive));
922 #endif
924 #if (ACE_USES_CLASSIC_SVC_CONF == 1)
925 ACE_UNUSED_ARG (directive);
927 ACE_Svc_Conf_Param d (this, directive);
929 return this->process_directives_i (&d);
930 #else
931 ACE_DLL dll;
933 std::unique_ptr<ACE_XML_Svc_Conf> xml_svc_conf (this->get_xml_svc_conf (dll));
935 if (xml_svc_conf.get () == 0)
936 return -1;
938 // Temporarily (for the duration of this call) make sure that *any* static
939 // service registrations will happen with this instance. Such registrations
940 // are possible as a side-effect of dynamically loading a DLL, which has
941 // other static services registered. Thus this instance will own both the
942 // DLL and those static services, which implies that their finalization
943 // will be performed in the correct order, i.e. prior to finalizing the DLL
944 ACE_Service_Config_Guard guard (this);
946 return xml_svc_conf->parse_string (directive);
947 #endif /* ACE_USES_CLASSIC_SVC_CONF == 1 */
949 } /* process_directive () */
953 ACE_Service_Gestalt::init_svc_conf_file_queue ()
955 if (this->svc_conf_file_queue_ == 0)
957 ACE_SVC_QUEUE *tmp = 0;
958 ACE_NEW_RETURN (tmp,
959 ACE_SVC_QUEUE,
960 -1);
961 this->svc_conf_file_queue_ = tmp;
964 #ifndef ACE_NLOGGING
965 if (ACE::debug ())
966 ACELIB_DEBUG ((LM_DEBUG,
967 ACE_TEXT ("ACE (%P|%t) SG::init_svc_conf_file_queue ")
968 ACE_TEXT ("- this=%@, repo=%@\n"),
969 this, this->repo_));
970 #endif
972 return 0;
973 } /* init_svc_conf_file_queue () */
977 ACE_Service_Gestalt::open_i (const ACE_TCHAR program_name[],
978 const ACE_TCHAR* logger_key,
979 bool ignore_static_svcs,
980 bool ignore_default_svc_conf_file,
981 bool ignore_debug_flag)
983 ACE_TRACE ("ACE_Service_Gestalt::open_i");
984 int result = 0;
985 ACE_Log_Msg *log_msg = ACE_LOG_MSG;
987 this->no_static_svcs_ = ignore_static_svcs;
989 // Record the current log setting upon entering this thread.
990 u_long old_process_mask = log_msg->priority_mask
991 (ACE_Log_Msg::PROCESS);
993 u_long old_thread_mask = log_msg->priority_mask
994 (ACE_Log_Msg::THREAD);
996 #ifndef ACE_NLOGGING
997 if (ACE::debug ())
998 ACELIB_DEBUG ((LM_DEBUG,
999 ACE_TEXT ("ACE (%P|%t) SG::open_i - this=%@, ")
1000 ACE_TEXT ("opened=%d, loadstatics=%d\n"),
1001 this, this->is_opened_, this->no_static_svcs_));
1002 #endif
1004 // Guard against reentrant processing. For example,
1005 // if the singleton gestalt (ubergestalt) was already open,
1006 // do not open it again...
1007 if (this->is_opened_++ != 0)
1008 return 0;
1010 if (this->init_i () != 0)
1011 return -1;
1013 u_long flags = log_msg->flags ();
1015 // Only use STDERR if the caller hasn't already set the flags.
1016 if (flags == 0)
1017 flags = (u_long) ACE_Log_Msg::STDERR;
1019 const ACE_TCHAR *key = logger_key;
1021 if (key == 0 || ACE_OS::strcmp (key, ACE_DEFAULT_LOGGER_KEY) == 0)
1023 // Only use the static <logger_key_> if the caller doesn't
1024 // override it in the parameter list or if the key supplied is
1025 // equal to the default static logger key.
1026 key = this->logger_key_;
1028 else
1030 ACE_SET_BITS (flags, ACE_Log_Msg::LOGGER);
1033 if (log_msg->open (program_name,
1034 flags,
1035 key) == -1)
1036 return -1;
1038 if (!ignore_debug_flag)
1040 // If -d was included as a startup parameter, the user wants debug
1041 // information printed during service initialization.
1042 if (ACE::debug ())
1043 ACE_Log_Msg::enable_debug_messages ();
1044 else
1045 // The user has requested no debugging info.
1046 ACE_Log_Msg::disable_debug_messages ();
1049 if (!ignore_default_svc_conf_file)
1051 bool add_default = true;
1052 bool has_files = this->svc_conf_file_queue_ &&
1053 !this->svc_conf_file_queue_->is_empty ();
1054 bool has_cmdline = this->svc_queue_ && !this->svc_queue_->is_empty ();
1055 if (has_files || has_cmdline)
1057 // check if default file is already listed
1058 ACE_TString *sptr = 0;
1059 ACE_TString default_svc_conf (ACE_DEFAULT_SVC_CONF);
1061 for (ACE_SVC_QUEUE_ITERATOR iter (*this->svc_conf_file_queue_);
1062 iter.next (sptr) != 0 && add_default;
1063 iter.advance ())
1065 add_default = (*sptr != default_svc_conf);
1068 if (add_default)
1070 FILE *fp = ACE_OS::fopen (ACE_DEFAULT_SVC_CONF, ACE_TEXT ("r"));
1071 if (fp != 0)
1072 ACE_OS::fclose(fp);
1073 else
1074 add_default = false;
1078 // Load the default "svc.conf" entry. here if there weren't
1079 // overriding -f arguments in <parse_args>.
1080 if (add_default && svc_conf_file_queue_->enqueue_head
1081 (ACE_TString (ACE_DEFAULT_SVC_CONF)) == -1)
1083 errno = ENOENT;
1084 ACELIB_ERROR_RETURN ((LM_ERROR,
1085 ACE_TEXT ("%p\n"),
1086 ACE_TEXT ("enqueuing ")
1087 ACE_DEFAULT_SVC_CONF
1088 ACE_TEXT(" file")),
1089 -1);
1093 // See if we need to load the static services.
1094 if (this->no_static_svcs_ == 0
1095 && this->load_static_svcs () == -1)
1096 result = -1;
1097 else
1099 result = this->process_directives ();
1100 if (result != -1)
1102 int temp = this->process_commandline_directives ();
1103 if (temp == -1)
1104 result = -1;
1105 else result += temp;
1109 // Reset debugging back to the way it was when we came into
1110 // into <open_i>.
1112 // Make sure to save/restore errno properly.
1113 ACE_Errno_Guard error (errno);
1115 if (!ignore_debug_flag)
1117 log_msg->priority_mask (old_process_mask, ACE_Log_Msg::PROCESS);
1118 log_msg->priority_mask (old_thread_mask, ACE_Log_Msg::THREAD);
1122 return result;
1123 } /* open_i () */
1127 ACE_Service_Gestalt::is_opened ()
1129 return this->is_opened_;
1133 ACE_Service_Gestalt::process_commandline_directives ()
1135 int result = 0;
1136 if (this->svc_queue_ != 0)
1138 ACE_TString *sptr = 0;
1139 for (ACE_SVC_QUEUE_ITERATOR iter (*this->svc_queue_);
1140 iter.next (sptr) != 0;
1141 iter.advance ())
1143 // Process just a single directive.
1144 if (this->process_directive ((sptr->fast_rep ())) != 0)
1146 ACELIB_ERROR ((LM_ERROR,
1147 ACE_TEXT ("ACE (%P|%t) %p\n"),
1148 ACE_TEXT ("process_directive")));
1149 result = -1;
1153 delete this->svc_queue_;
1154 this->svc_queue_ = 0;
1157 return result;
1158 } /* process_commandline_directives () */
1162 ACE_Service_Gestalt::parse_args (int argc, ACE_TCHAR *argv[])
1164 ACE_TRACE ("ACE_Service_Gestalt::parse_args");
1165 bool unused_ignore_default_svc_conf = true;
1166 return parse_args_i (argc, argv, unused_ignore_default_svc_conf);
1170 ACE_Service_Gestalt::parse_args_i (int argc,
1171 ACE_TCHAR *argv[],
1172 bool &ignore_default_svc_conf_file)
1174 ACE_TRACE ("ACE_Service_Gestalt::parse_args_i");
1175 ACE_Get_Opt get_opt (argc,
1176 argv,
1177 ACE_TEXT ("df:k:nyS:"),
1178 1); // Start at argv[1].
1180 if (this->init_svc_conf_file_queue () == -1)
1181 return -1;
1183 for (int c; (argc != 0) && ((c = get_opt ()) != -1); )
1184 switch (c)
1186 case 'd':
1187 ACE::debug (1);
1188 break;
1189 case 'f':
1190 if (this->svc_conf_file_queue_->enqueue_tail (ACE_TString (get_opt.opt_arg ())) == -1)
1191 ACELIB_ERROR_RETURN ((LM_ERROR,
1192 ACE_TEXT ("%p\n"),
1193 ACE_TEXT ("enqueue_tail")),
1194 -1);
1195 ignore_default_svc_conf_file = true;
1196 break;
1197 case 'k':
1199 * @TODO: Is this always a static storage? Shouldn't we copy
1200 * & gain ownership of the value?
1202 this->logger_key_ = get_opt.opt_arg ();
1203 break;
1204 case 'n':
1205 this->no_static_svcs_ = 1;
1206 break;
1207 case 'y':
1208 this->no_static_svcs_ = 0;
1209 break;
1210 case 'S':
1211 if (this->svc_queue_ == 0)
1213 ACE_NEW_RETURN (this->svc_queue_,
1214 ACE_SVC_QUEUE,
1215 -1);
1218 if (this->svc_queue_->enqueue_tail (ACE_TString (get_opt.opt_arg ())) == -1)
1219 ACELIB_ERROR_RETURN ((LM_ERROR,
1220 ACE_TEXT ("%p\n"),
1221 ACE_TEXT ("enqueue_tail")),
1222 -1);
1223 break;
1224 default:
1225 if (ACE::debug ())
1226 ACELIB_DEBUG ((LM_DEBUG,
1227 ACE_TEXT ("ACE (%P|%t) %c is not a ACE_Service_Config option\n"),
1228 c));
1231 return 0;
1232 } /* parse_args_i () */
1235 // Process service configuration directives from the files queued for
1236 // processing
1238 ACE_Service_Gestalt::process_directives (bool )
1240 ACE_TRACE ("ACE_Service_Gestalt::process_directives");
1241 if (this->svc_conf_file_queue_ == 0
1242 || this->svc_conf_file_queue_->is_empty ())
1244 return 0;
1247 ACE_TString *sptr = 0;
1248 int failed = 0;
1250 // Iterate through all the svc.conf files.
1251 for (ACE_SVC_QUEUE_ITERATOR iter (*this->svc_conf_file_queue_);
1252 iter.next (sptr) != 0;
1253 iter.advance ())
1255 int result = this->process_file (sptr->fast_rep ());
1256 if (result < 0)
1257 return result;
1258 failed += result;
1261 return failed;
1262 } /* process_directives () */
1264 // Tidy up and perform last rites on a terminating ACE_Service_Gestalt.
1266 ACE_Service_Gestalt::close ()
1268 ACE_TRACE ("ACE_Service_Gestalt::close");
1270 if (!this->is_opened_ || --this->is_opened_ != 0)
1271 return 0;
1273 // Delete the list fo svc.conf files
1274 delete this->svc_conf_file_queue_;
1275 this->svc_conf_file_queue_ = 0;
1277 if (this->processed_static_svcs_ &&
1278 !this->processed_static_svcs_->is_empty())
1280 Processed_Static_Svc **pss = 0;
1281 for (ACE_PROCESSED_STATIC_SVCS_ITERATOR iter (*this->processed_static_svcs_);
1282 iter.next (pss) != 0;
1283 iter.advance ())
1285 delete *pss;
1288 delete this->processed_static_svcs_;
1289 this->processed_static_svcs_ = 0;
1291 #ifndef ACE_NLOGGING
1292 if (ACE::debug ())
1293 ACELIB_DEBUG ((LM_DEBUG,
1294 ACE_TEXT ("ACE (%P|%t) SG::close - complete this=%@, repo=%@, owned=%d\n"),
1295 this, this->repo_, this->svc_repo_is_owned_));
1296 #endif
1298 if (this->svc_repo_is_owned_)
1299 delete this->repo_;
1301 this->repo_ = 0;
1303 return 0;
1304 } /* close () */
1307 ACE_END_VERSIONED_NAMESPACE_DECL
1309 #if !defined (__ACE_INLINE__)
1310 #include "ace/Service_Gestalt.inl"
1311 #endif /* __ACE_INLINE__ */
1313 // Allocate a Service Manager.
1314 ACE_FACTORY_DEFINE (ACE, ACE_Service_Manager)