Document return values
[ACE_TAO.git] / ACE / ace / Service_Repository.cpp
blob6251fbd55f15c422032f2c4f141c767f33f2fbe2
1 #include "ace/Service_Repository.h"
3 #if !defined (__ACE_INLINE__)
4 #include "ace/Service_Repository.inl"
5 #endif /* __ACE_INLINE__ */
7 #include "ace/Service_Types.h"
8 #include "ace/Object_Manager.h"
9 #include "ace/Log_Category.h"
10 #include "ace/ACE.h"
11 #include "ace/OS_NS_unistd.h"
12 #include "ace/OS_NS_errno.h"
13 #include "ace/OS_NS_string.h"
15 ACE_BEGIN_VERSIONED_NAMESPACE_DECL
17 ACE_ALLOC_HOOK_DEFINE(ACE_Service_Repository)
19 /// Process-wide Service Repository.
20 ACE_Service_Repository *ACE_Service_Repository::svc_rep_ = 0;
22 /// Controls whether the Service_Repository is deleted when we shut
23 /// down (we can only delete it safely if we created it)!
24 bool ACE_Service_Repository::delete_svc_rep_ = false;
26 void
27 ACE_Service_Repository::dump () const
29 #if defined (ACE_HAS_DUMP)
30 ACE_TRACE ("ACE_Service_Repository::dump");
31 #endif /* ACE_HAS_DUMP */
34 ACE_Service_Repository *
35 ACE_Service_Repository::instance (size_t size)
37 ACE_TRACE ("ACE_Service_Repository::instance");
39 if (ACE_Service_Repository::svc_rep_ == 0)
41 // Perform Double-Checked Locking Optimization.
42 ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon,
43 *ACE_Static_Object_Lock::instance (), 0));
44 if (ACE_Service_Repository::svc_rep_ == 0)
46 if (ACE_Object_Manager::starting_up () ||
47 !ACE_Object_Manager::shutting_down ())
49 ACE_NEW_RETURN (ACE_Service_Repository::svc_rep_,
50 ACE_Service_Repository (size),
51 0);
52 ACE_Service_Repository::delete_svc_rep_ = true;
57 return ACE_Service_Repository::svc_rep_;
60 ACE_Service_Repository *
61 ACE_Service_Repository::instance (ACE_Service_Repository *s)
63 ACE_TRACE ("ACE_Service_Repository::instance");
64 ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon,
65 *ACE_Static_Object_Lock::instance (), 0));
67 ACE_Service_Repository *t = ACE_Service_Repository::svc_rep_;
68 // We can't safely delete it since we don't know who created it!
69 ACE_Service_Repository::delete_svc_rep_ = false;
71 ACE_Service_Repository::svc_rep_ = s;
72 return t;
75 void
76 ACE_Service_Repository::close_singleton ()
78 ACE_TRACE ("ACE_Service_Repository::close_singleton");
80 ACE_MT (ACE_GUARD (ACE_Recursive_Thread_Mutex, ace_mon,
81 *ACE_Static_Object_Lock::instance ()));
83 if (ACE_Service_Repository::delete_svc_rep_)
85 delete ACE_Service_Repository::svc_rep_;
86 ACE_Service_Repository::svc_rep_ = 0;
87 ACE_Service_Repository::delete_svc_rep_ = false;
91 /// Initialize the Repository to a clean slate.
92 int
93 ACE_Service_Repository::open (size_t size)
95 ACE_TRACE ("ACE_Service_Repository::open");
97 // Create a new array and swap it with the local array
98 array_type local_array (size);
99 this->service_array_.swap (local_array);
101 return 0;
104 ACE_Service_Repository::ACE_Service_Repository (size_t size)
105 : service_array_ (size)
107 ACE_TRACE ("ACE_Service_Repository::ACE_Service_Repository");
111 /// Finalize (call fini() and possibly delete) all the services.
114 ACE_Service_Repository::fini ()
116 ACE_TRACE ("ACE_Service_Repository::fini");
117 ACE_GUARD_RETURN (ACE_SYNCH_RECURSIVE_MUTEX, ace_mon, this->lock_, -1);
119 int retval = 0;
120 // Do not be tempted to use the prefix decrement operator. Use
121 // postfix decrement operator since the index is unsigned and may
122 // wrap around the 0
124 // debug output for empty service entries
125 #ifndef ACE_NLOGGING
126 if (ACE::debug ())
128 for (size_t i = this->service_array_.size (); i-- != 0;)
130 ACE_Service_Type *s =
131 const_cast<ACE_Service_Type *> (this->service_array_[i]);
132 if (s == 0)
133 ACELIB_DEBUG ((LM_DEBUG,
134 ACE_TEXT ("ACE (%P|%t) SR::fini, repo=%@ [%d] -> 0\n"),
135 this,
136 i));
139 #endif
141 // Remove all the Service_Object and Stream instances
143 for (size_t i = this->service_array_.size (); i-- != 0;)
145 // <fini> the services in reverse order.
146 ACE_Service_Type *s =
147 const_cast<ACE_Service_Type *> (this->service_array_[i]);
149 if (s != 0 &&
150 s->type () != 0 &&
151 (s->type ()->service_type () != ACE_Service_Type::MODULE))
153 #ifndef ACE_NLOGGING
154 if (ACE::debug ())
156 ACELIB_DEBUG ((LM_DEBUG,
157 ACE_TEXT ("ACE (%P|%t) SR::fini, repo=%@ [%d], ")
158 ACE_TEXT ("name=%s, type=%@, object=%@, active=%d\n"),
159 this,
161 s->name (),
162 s->type (),
163 (s->type () != 0) ? s->type ()->object () : 0,
164 s->active ()));
166 #endif
168 // Collect any errors.
169 retval += s->fini ();
173 // Remove all the Module instances
175 for (size_t i = this->service_array_.size (); i-- != 0;)
177 // <fini> the services in reverse order.
178 ACE_Service_Type *s =
179 const_cast<ACE_Service_Type *> (this->service_array_[i]);
181 if (s != 0 &&
182 s->type () != 0 &&
183 (s->type ()->service_type () == ACE_Service_Type::MODULE))
185 #ifndef ACE_NLOGGING
186 if (ACE::debug ())
188 ACELIB_DEBUG ((LM_DEBUG,
189 ACE_TEXT ("ACE (%P|%t) SR::fini, repo=%@ [%d], ")
190 ACE_TEXT ("name=%s, type=%@, object=%@, active=%d\n"),
191 this,
193 s->name (),
194 s->type (),
195 (s->type () != 0) ? s->type ()->object () : 0,
196 s->active ()));
198 #endif
199 // Collect any errors.
200 retval += s->fini ();
203 return (retval == 0) ? 0 : -1;
207 /// Close down all the services.
209 ACE_Service_Repository::close ()
211 ACE_TRACE ("ACE_Service_Repository::close");
212 ACE_GUARD_RETURN (ACE_SYNCH_RECURSIVE_MUTEX, ace_mon, this->lock_, -1);
214 #ifndef ACE_NLOGGING
215 if(ACE::debug ())
216 ACELIB_DEBUG ((LM_DEBUG,
217 ACE_TEXT ("ACE (%P|%t) SR::close - repo=%@, size=%d\n"),
218 this,
219 this->service_array_.size()));
220 #endif
222 // Do not use the prefix decrement operator since the index is
223 // unsigned and may wrap around the 0.
224 for (size_t i = this->service_array_.size(); i-- != 0; )
226 // Delete services in reverse order.
227 ACE_Service_Type *s =
228 const_cast<ACE_Service_Type *> (this->service_array_[i]);
230 #ifndef ACE_NLOGGING
231 if(ACE::debug ())
233 if (s == 0)
234 ACELIB_DEBUG ((LM_DEBUG,
235 ACE_TEXT ("ACE (%P|%t) SR::close - repo=%@ [%d] -> 0\n"),
236 this,
237 i));
238 else
239 ACELIB_DEBUG ((LM_DEBUG,
240 ACE_TEXT ("ACE (%P|%t) SR::close - repo=%@ [%d], name=%s, object=%@\n"),
241 this,
243 s->name (),
244 s));
246 #endif
247 delete s;
250 this->service_array_.clear ();
252 return 0;
255 ACE_Service_Repository::~ACE_Service_Repository ()
257 ACE_TRACE ("ACE_Service_Repository::~ACE_Service_Repository");
258 #ifndef ACE_NLOGGING
259 if(ACE::debug ())
260 ACELIB_DEBUG ((LM_DEBUG, "ACE (%P|%t) SR::<dtor>, this=%@\n", this));
261 #endif
262 this->close ();
265 /// Locate an entry with @a name in the table. If @a ignore_suspended is
266 /// set then only consider services marked as resumed. If the caller
267 /// wants the located entry, pass back a pointer to the located entry
268 /// via @a srp. If @a name is not found -1 is returned. If @a name is
269 /// found, but it is suspended and the caller wants to ignore suspended
270 /// services a -2 is returned. Must be called with locks held.
272 ACE_Service_Repository::find_i (const ACE_TCHAR name[],
273 size_t &slot,
274 const ACE_Service_Type **srp,
275 bool ignore_suspended) const
277 ACE_TRACE ("ACE_Service_Repository::find_i");
278 array_type::const_iterator iter;
280 for (iter = this->service_array_.begin(); iter != this->service_array_.end(); ++iter)
282 if ((*iter).second != 0 // skip any empty slots
283 && ACE_OS::strcmp (name, (*iter).second->name ()) == 0)
285 break;
289 if (iter != this->service_array_.end ())
291 slot = (*iter).first;
292 if ((*iter).second->fini_called ())
294 if (srp != 0)
295 *srp = 0;
296 return -1;
299 if (srp != 0)
300 *srp = (*iter).second;
302 if (ignore_suspended
303 && (*iter).second->active () == 0)
304 return -2;
306 return 0;
309 return -1;
313 /// @brief Relocate (a static) service to another DLL.
315 /// Works by having the service type keep a reference to a specific
316 /// DLL. No locking, caller makes sure calling it is safe. You can
317 /// forcefully relocate any DLLs in the given range, not only the
318 /// static ones - but that will cause Very Bad Things (tm) to happen.
320 ACE_Service_Repository::relocate_i (size_t begin,
321 size_t end,
322 const ACE_DLL& adll)
324 ACE_SHLIB_HANDLE new_handle = adll.get_handle (0);
326 for (size_t i = begin; i < end; i++)
328 ACE_Service_Type *type =
329 const_cast<ACE_Service_Type *> (this->service_array_[i]);
331 ACE_SHLIB_HANDLE old_handle = (type == 0) ? ACE_SHLIB_INVALID_HANDLE
332 : type->dll ().get_handle (0);
334 #ifndef ACE_NLOGGING
335 if (ACE::debug ())
337 if (type == 0)
338 ACELIB_DEBUG ((LM_DEBUG,
339 ACE_TEXT ("ACE (%P|%t) SR::relocate_i - repo=%@ [%d]")
340 ACE_TEXT (": skipping empty slot\n"),
341 this,
342 i));
343 else
344 ACELIB_DEBUG ((LM_DEBUG,
345 ACE_TEXT ("ACE (%P|%t) SR::relocate_i - repo=%@ [%d]")
346 ACE_TEXT (": trying name=%s, handle: %d -> %d\n"),
347 this,
349 type->name (),
350 old_handle,
351 new_handle));
353 #endif
355 if (type != 0 // skip any gaps
356 && old_handle == ACE_SHLIB_INVALID_HANDLE
357 && new_handle != old_handle)
359 #ifndef ACE_NLOGGING
360 if (ACE::debug ())
361 ACELIB_DEBUG ((LM_DEBUG,
362 ACE_TEXT ("ACE (%P|%t) SR::relocate_i - repo=%@ [%d]")
363 ACE_TEXT (": relocating name=%s, handle: %d -> %d\n"),
364 this,
366 type->name (),
367 old_handle,
368 new_handle));
369 #endif
370 type->dll (adll); // ups the refcount on adll
374 return 0;
378 ACE_Service_Repository::find (const ACE_TCHAR name[],
379 const ACE_Service_Type **srp,
380 bool ignore_suspended) const
382 ACE_TRACE ("ACE_Service_Repository::find");
383 ACE_GUARD_RETURN (ACE_SYNCH_RECURSIVE_MUTEX, ace_mon, this->lock_, -1);
384 size_t ignore_location = 0;
385 return this->find_i (name, ignore_location, srp, ignore_suspended);
388 /// Insert the ACE_Service_Type SR into the repository. Note that
389 /// services may be inserted either resumed or suspended. Using same
390 /// name as in an existing service causes the delete () to be called
391 /// for the old one, i.e. make sure @code sr is allocated on the heap!
393 ACE_Service_Repository::insert (const ACE_Service_Type *sr)
395 ACE_TRACE ("ACE_Service_Repository::insert");
397 size_t i = 0;
398 int return_value = -1;
399 ACE_Service_Type const *s = 0;
401 // Establish scope for locking while manipulating the service
402 // storage
404 // @TODO: Do we need a recursive mutex here?
405 ACE_GUARD_RETURN (ACE_SYNCH_RECURSIVE_MUTEX,
406 ace_mon, this->lock_, -1);
408 return_value = find_i (sr->name (), i, &s, false);
410 // Adding an entry.
411 if (s != 0)
413 this->service_array_[i] = sr;
415 else
417 // New services are always added where current_size_ points,
418 // because if any DLL relocation needs to happen, it will be
419 // performed on services with indexes between some old
420 // current_size_ and the new current_size_ value. See
421 // ACE_Service_Type_Dynamic_Guard ctor and dtor for details.
423 if (i < this->service_array_.size ())
424 i = this->service_array_.size ();
426 this->service_array_[i] = sr;
427 return_value = 0;
430 #ifndef ACE_NLOGGING
431 if (ACE::debug ())
432 ACELIB_DEBUG ((LM_DEBUG,
433 ACE_TEXT ("ACE (%P|%t) SR::insert - repo=%@ [%d],")
434 ACE_TEXT (" name=%s (%C) (type=%@, object=%@, active=%d)\n"),
435 this,
437 sr->name(),
438 (return_value == 0 ? ((s==0) ? "new" : "replacing") : "failed"),
439 sr->type (),
440 (sr->type () != 0) ? sr->type ()->object () : 0,
441 sr->active ()));
442 #endif
444 // If necessary, delete but outside the lock. (s may be 0, but
445 // that's okay, too)
446 delete s;
448 if (return_value == -1)
449 ACE_OS::last_error (ENOSPC);
451 return return_value;
454 /// Resume a service that was previously suspended.
456 ACE_Service_Repository::resume (const ACE_TCHAR name[],
457 const ACE_Service_Type **srp)
459 ACE_TRACE ("ACE_Service_Repository::resume");
460 ACE_GUARD_RETURN (ACE_SYNCH_RECURSIVE_MUTEX, ace_mon, this->lock_, -1);
462 size_t i = 0;
463 if (-1 == this->find_i (name, i, srp, 0))
464 return -1;
466 return this->service_array_[i]->resume ();
469 /// Suspend a service so that it will not be considered active under
470 /// most circumstances by other portions of the ACE_Service_Repository.
472 ACE_Service_Repository::suspend (const ACE_TCHAR name[],
473 const ACE_Service_Type **srp)
475 ACE_TRACE ("ACE_Service_Repository::suspend");
476 ACE_GUARD_RETURN (ACE_SYNCH_RECURSIVE_MUTEX, ace_mon, this->lock_, -1);
477 size_t i = 0;
478 if (-1 == this->find_i (name, i, srp, 0))
479 return -1;
481 return this->service_array_[i]->suspend ();
485 * @brief Completely remove a @a name entry from the Repository and
486 * dynamically unlink it if it was originally dynamically linked.
489 ACE_Service_Repository::remove (const ACE_TCHAR name[], ACE_Service_Type **ps)
491 ACE_TRACE ("ACE_Service_Repository::remove");
492 ACE_Service_Type *s = 0;
494 ACE_GUARD_RETURN (ACE_SYNCH_RECURSIVE_MUTEX, ace_mon, this->lock_, -1);
496 // Not found!?
497 if (this->remove_i (name, &s) == -1)
498 return -1;
501 if (ps != 0)
502 *ps = s;
503 else
504 delete s;
505 return 0;
509 * @brief Completely remove a @a name entry from the Repository and
510 * dynamically unlink it if it was originally dynamically linked.
512 * Return a ptr to the entry in @code ps. There is no locking so make
513 * sure you hold the repo lock when calling.
515 * Since the order of services in the Respository matters, we can't
516 * simply overwrite the entry being deleted with the last and
517 * decrement the @c current_size by 1. A good example of why the order
518 * matters is a dynamic service, in whose DLL there is at least one
519 * static service. In order to prevent SEGV during finalization, those
520 * static services must be finalized _before_the dynamic service that
521 * owns them. Otherwice the TEXT segment, containing the code for the
522 * static service's desructor may be unloaded with the DLL.
524 * Neither can we "pack" the array because this may happen inside the
525 * scope of a Service_Dynamic_Guard, which caches an index where
526 * loading of a DLL started in order to relocate dependent services.
529 ACE_Service_Repository::remove_i (const ACE_TCHAR name[], ACE_Service_Type **ps)
531 size_t i = 0;
532 if (-1 == this->find_i (name, i, 0, false))
533 return -1; // Not found
535 // We may need the old ptr - to be delete outside the lock!
536 *ps = const_cast<ACE_Service_Type *> (this->service_array_[i]);
538 #ifndef ACE_NLOGGING
539 if (ACE::debug ())
540 ACELIB_DEBUG ((LM_DEBUG,
541 ACE_TEXT ("ACE (%P|%t) SR::remove_i - repo=%@ [%d],")
542 ACE_TEXT (" name=%s (removed) (type=%@, active=%d)\n"),
543 this,
545 name,
546 *ps,
547 (*ps)->active ()));
548 #endif
550 this->service_array_[i] = 0; // simply leave a gap
551 return 0;
554 ACE_ALLOC_HOOK_DEFINE(ACE_Service_Repository_Iterator)
556 void
557 ACE_Service_Repository_Iterator::dump () const
559 #if defined (ACE_HAS_DUMP)
560 ACE_TRACE ("ACE_Service_Repository_Iterator::dump");
561 #endif /* ACE_HAS_DUMP */
564 /// Initializes the iterator and skips over any suspended entries at
565 /// the beginning of the table, if necessary. Note, you must not
566 /// perform destructive operations on elements during this iteration...
567 ACE_Service_Repository_Iterator::ACE_Service_Repository_Iterator
568 (ACE_Service_Repository &sr, bool ignored_suspended)
569 : svc_rep_ (sr),
570 next_ (0),
571 ignore_suspended_ (ignored_suspended)
573 while (!(done() || valid()))
574 this->next_++;
577 /// Obtains a pointer to the next valid service in the table. If there
578 /// are no more entries, returns 0, else 1.
580 ACE_Service_Repository_Iterator::next (const ACE_Service_Type *&sr)
582 ACE_TRACE ("ACE_Service_Repository_Iterator::next");
584 if (done ())
585 return 0;
587 sr = this->svc_rep_.service_array_[this->next_];
588 return 1;
591 /// Advance the iterator by the proper amount. If we are ignoring
592 /// suspended entries and the current entry is suspended, then we must
593 /// skip over this entry. Otherwise, we must advance the NEXT index to
594 /// reference the next valid service entry.
596 ACE_Service_Repository_Iterator::advance ()
598 ACE_TRACE ("ACE_Service_Repository_Iterator::advance");
600 if (done()) return 0;
602 do this->next_++; while (!(done () || valid ()));
604 return !done();
607 bool
608 ACE_Service_Repository_Iterator::valid () const
610 ACE_TRACE ("ACE_Service_Repository_Iterator::valid");
611 if (!this->ignore_suspended_)
612 return (this->svc_rep_.service_array_[this->next_] != 0); // skip over gaps
614 return (this->svc_rep_.service_array_[this->next_] != 0
615 && this->svc_rep_.service_array_[this->next_]->active ());
618 ACE_END_VERSIONED_NAMESPACE_DECL