Restore build on FreeBSD.
[getmangos.git] / dep / ACE_wrappers / ace / Service_Repository.cpp
blob18fafe05be73e2ab9529c03f4d856ffdae2200c5
1 // $Id: Service_Repository.cpp 81388 2008-04-23 14:02:05Z johnnyw $
3 #include "ace/Service_Repository.h"
5 #if !defined (__ACE_INLINE__)
6 #include "ace/Service_Repository.inl"
7 #endif /* __ACE_INLINE__ */
9 #include "ace/Service_Types.h"
10 #include "ace/Object_Manager.h"
11 #include "ace/Log_Msg.h"
12 #include "ace/ACE.h"
13 #include "ace/OS_NS_unistd.h"
14 #include "ace/OS_NS_errno.h"
15 #include "ace/OS_NS_string.h"
17 ACE_RCSID (ace,
18 Service_Repository,
19 "$Id: Service_Repository.cpp 81388 2008-04-23 14:02:05Z johnnyw $")
21 ACE_BEGIN_VERSIONED_NAMESPACE_DECL
23 ACE_ALLOC_HOOK_DEFINE(ACE_Service_Repository)
25 // Process-wide Service Repository.
26 ACE_Service_Repository *ACE_Service_Repository::svc_rep_ = 0;
28 // Controls whether the Service_Repository is deleted when we shut
29 // down (we can only delete it safely if we created it)!
30 bool ACE_Service_Repository::delete_svc_rep_ = false;
32 void
33 ACE_Service_Repository::dump (void) const
35 #if defined (ACE_HAS_DUMP)
36 ACE_TRACE ("ACE_Service_Repository::dump");
37 #endif /* ACE_HAS_DUMP */
40 ACE_Service_Repository::ACE_Service_Repository (void)
41 : service_vector_ (0),
42 current_size_ (0),
43 total_size_ (0)
45 ACE_TRACE ("ACE_Service_Repository::ACE_Service_Repository");
48 ACE_Service_Repository *
49 ACE_Service_Repository::instance (size_t size /* = ACE_Service_Repository::DEFAULT_SIZE */)
51 ACE_TRACE ("ACE_Service_Repository::instance");
53 if (ACE_Service_Repository::svc_rep_ == 0)
55 // Perform Double-Checked Locking Optimization.
56 ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon,
57 *ACE_Static_Object_Lock::instance (), 0));
58 if (ACE_Service_Repository::svc_rep_ == 0)
60 if (ACE_Object_Manager::starting_up () ||
61 !ACE_Object_Manager::shutting_down ())
63 ACE_NEW_RETURN (ACE_Service_Repository::svc_rep_,
64 ACE_Service_Repository (size),
65 0);
66 ACE_Service_Repository::delete_svc_rep_ = true;
71 return ACE_Service_Repository::svc_rep_;
74 ACE_Service_Repository *
75 ACE_Service_Repository::instance (ACE_Service_Repository *s)
77 ACE_TRACE ("ACE_Service_Repository::instance");
78 ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon,
79 *ACE_Static_Object_Lock::instance (), 0));
81 ACE_Service_Repository *t = ACE_Service_Repository::svc_rep_;
82 // We can't safely delete it since we don't know who created it!
83 ACE_Service_Repository::delete_svc_rep_ = false;
85 ACE_Service_Repository::svc_rep_ = s;
86 return t;
89 void
90 ACE_Service_Repository::close_singleton (void)
92 ACE_TRACE ("ACE_Service_Repository::close_singleton");
94 ACE_MT (ACE_GUARD (ACE_Recursive_Thread_Mutex, ace_mon,
95 *ACE_Static_Object_Lock::instance ()));
97 if (ACE_Service_Repository::delete_svc_rep_)
99 delete ACE_Service_Repository::svc_rep_;
100 ACE_Service_Repository::svc_rep_ = 0;
101 ACE_Service_Repository::delete_svc_rep_ = false;
105 // Initialize the Repository to a clean slate.
108 ACE_Service_Repository::open (size_t size)
110 ACE_TRACE ("ACE_Service_Repository::open");
112 ACE_Service_Type **temp = 0;
114 ACE_NEW_RETURN (temp,
115 ACE_Service_Type *[size],
116 -1);
118 this->service_vector_ = const_cast<const ACE_Service_Type **> (temp);
119 this->total_size_ = size;
120 return 0;
123 ACE_Service_Repository::ACE_Service_Repository (size_t size)
124 : current_size_ (0)
126 ACE_TRACE ("ACE_Service_Repository::ACE_Service_Repository");
128 if (this->open (size) == -1)
129 ACE_ERROR ((LM_ERROR,
130 ACE_TEXT ("%p\n"),
131 ACE_TEXT ("ACE_Service_Repository")));
134 // Finalize (call <fini> and possibly delete) all the services.
137 ACE_Service_Repository::fini (void)
139 ACE_TRACE ("ACE_Service_Repository::fini");
140 ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1));
142 if (this->service_vector_ == 0)
143 return 0;
145 int retval = 0;
147 // Do not be tempted to use the prefix decrement operator. Use
148 // postfix decrement operator since the index is unsigned and may
149 // wrap around the 0
150 for (size_t i = this->current_size_; i-- != 0; )
152 // <fini> the services in reverse order.
153 ACE_Service_Type *s =
154 const_cast<ACE_Service_Type *> (this->service_vector_[i]);
156 #ifndef ACE_NLOGGING
157 if (ACE::debug ())
159 if (s != 0)
160 ACE_DEBUG ((LM_DEBUG,
161 ACE_TEXT ("ACE (%P|%t) SR::fini, repo=%@ [%d] (%d), ")
162 ACE_TEXT ("name=%s, type=%@, object=%@, active=%d\n"),
163 this,
165 this->total_size_,
166 s->name(),
167 s->type (),
168 (s->type () != 0) ? s->type ()->object () : 0,
169 s->active ()));
170 else
171 ACE_DEBUG ((LM_DEBUG,
172 ACE_TEXT ("ACE (%P|%t) SR::fini, repo=%@ [%d] (%d) -> 0\n"),
173 this,
175 this->total_size_));
177 #endif
179 // Collect any errors.
180 if (s != 0)
181 retval += s->fini ();
184 return (retval == 0) ? 0 : -1;
187 // Close down all the services.
190 ACE_Service_Repository::close (void)
192 ACE_TRACE ("ACE_Service_Repository::close");
193 ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1));
195 if (this->service_vector_ == 0)
196 return 0;
198 #ifndef ACE_NLOGGING
199 if(ACE::debug ())
200 ACE_DEBUG ((LM_DEBUG,
201 ACE_TEXT ("(%P|%t) SR::close - repo=%@, size=%d\n"),
202 this,
203 this->current_size_));
204 #endif
206 // Do not use the prefix decrement operator since the index is
207 // unsigned and may wrap around the 0.
208 for (size_t i = this->current_size_; i-- != 0; )
210 // Delete services in reverse order.
211 ACE_Service_Type *s =
212 const_cast<ACE_Service_Type *> (this->service_vector_[i]);
214 #ifndef ACE_NLOGGING
215 if(ACE::debug ())
217 if (s == 0)
218 ACE_DEBUG ((LM_DEBUG,
219 ACE_TEXT ("(%P|%t) SR::close - repo=%@ [%d] -> 0\n"),
220 this,
221 i));
222 else
223 ACE_DEBUG ((LM_DEBUG,
224 ACE_TEXT ("(%P|%t) SR::close - repo=%@ [%d], name=%s, object=%@\n"),
225 this,
227 s->name (),
228 s));
230 #endif
231 --this->current_size_;
232 delete s;
235 delete [] this->service_vector_;
236 this->service_vector_ = 0;
237 this->current_size_ = 0;
239 return 0;
242 ACE_Service_Repository::~ACE_Service_Repository (void)
244 ACE_TRACE ("ACE_Service_Repository::~ACE_Service_Repository");
245 #ifndef ACE_NLOGGING
246 if(ACE::debug ())
247 ACE_DEBUG ((LM_DEBUG, "(%P|%t) SR::<dtor>, this=%@\n", this));
248 #endif
249 this->close ();
252 // Locate an entry with <name> in the table. If <ignore_suspended> is
253 // set then only consider services marked as resumed. If the caller
254 // wants the located entry, pass back a pointer to the located entry
255 // via <srp>. If <name> is not found -1 is returned. If <name> is
256 // found, but it is suspended and the caller wants to ignore suspended
257 // services a -2 is returned. Must be called with locks held.
260 ACE_Service_Repository::find_i (const ACE_TCHAR name[],
261 size_t &slot,
262 const ACE_Service_Type **srp,
263 bool ignore_suspended) const
265 ACE_TRACE ("ACE_Service_Repository::find_i");
266 size_t i;
268 for (i = 0; i < this->current_size_; i++)
270 if (this->service_vector_[i] != 0 // skip any empty slots
271 && ACE_OS::strcmp (name,
272 this->service_vector_[i]->name ()) == 0)
273 break;
276 if (i < this->current_size_)
278 slot = i;
279 if (this->service_vector_[i]->fini_called ())
281 if (srp != 0)
282 *srp = 0;
283 return -1;
286 if (srp != 0)
287 *srp = this->service_vector_[i];
289 if (ignore_suspended
290 && this->service_vector_[i]->active () == 0)
291 return -2;
293 return 0;
296 return -1;
300 /// @brief Relocate (a static) service to another DLL.
302 /// Works by having the service type keep a reference to a specific
303 /// DLL. No locking, caller makes sure calling it is safe. You can
304 /// forcefully relocate any DLLs in the given range, not only the
305 /// static ones - but that will cause Very Bad Things (tm) to happen.
308 ACE_Service_Repository::relocate_i (size_t begin,
309 size_t end,
310 const ACE_DLL& adll)
312 ACE_SHLIB_HANDLE new_handle = adll.get_handle (0);
314 for (size_t i = begin; i < end; i++)
316 ACE_Service_Type *type =
317 const_cast<ACE_Service_Type *> (this->service_vector_[i]);
319 ACE_SHLIB_HANDLE old_handle = (type == 0) ? ACE_SHLIB_INVALID_HANDLE
320 : type->dll ().get_handle (0);
322 #ifndef ACE_NLOGGING
323 if (ACE::debug ())
325 if (type == 0)
326 ACE_DEBUG ((LM_DEBUG,
327 ACE_TEXT ("ACE (%P|%t) SR::relocate_i - repo=%@ [%d] (size=%d)")
328 ACE_TEXT (": skipping empty slot\n"),
329 this,
331 this->total_size_));
332 else
333 ACE_DEBUG ((LM_DEBUG,
334 ACE_TEXT ("ACE (%P|%t) SR::relocate_i - repo=%@ [%d] (size=%d)")
335 ACE_TEXT (": trying name=%s, handle: %d -> %d\n"),
336 this,
338 this->total_size_,
339 type->name (),
340 old_handle,
341 new_handle));
343 #endif
345 if (type != 0 // skip any gaps
346 && old_handle == ACE_SHLIB_INVALID_HANDLE
347 && new_handle != old_handle)
349 #ifndef ACE_NLOGGING
350 if (ACE::debug ())
351 ACE_DEBUG ((LM_DEBUG,
352 ACE_TEXT ("ACE (%P|%t) SR::relocate_i - repo=%@ [%d] (size=%d)")
353 ACE_TEXT (": relocating name=%s, handle: %d -> %d\n"),
354 this,
356 this->total_size_,
357 type->name (),
358 old_handle,
359 new_handle));
360 #endif
361 type->dll (adll); // ups the refcount on adll
365 return 0;
369 ACE_Service_Repository::find (const ACE_TCHAR name[],
370 const ACE_Service_Type **srp,
371 bool ignore_suspended) const
373 ACE_TRACE ("ACE_Service_Repository::find");
374 ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1));
375 size_t ignore_location = 0;
376 return this->find_i (name, ignore_location, srp, ignore_suspended);
380 // Insert the ACE_Service_Type SR into the repository. Note that
381 // services may be inserted either resumed or suspended. Using same
382 // name as in an existing service causes the delete () to be called
383 // for the old one, i.e. make sure @code sr is allocated on the heap!
385 ACE_Service_Repository::insert (const ACE_Service_Type *sr)
387 ACE_TRACE ("ACE_Service_Repository::insert");
389 size_t i = 0;
390 int return_value = -1;
391 ACE_Service_Type const *s = 0;
393 // Establish scope for locking while manipulating the service
394 // storage
396 // @TODO: Do we need a recursive mutex here?
397 ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex,
398 ace_mon,
399 this->lock_,
400 -1));
402 return_value = find_i (sr->name (), i, &s, false);
404 // Adding an entry.
405 if (s != 0)
407 this->service_vector_[i] = sr;
409 else
411 // New services are always added where current_size_ points,
412 // because if any DLL relocation needs to happen, it will be
413 // performed on services with indexes between some old
414 // current_size_ and the new current_size_ value. See
415 // ACE_Service_Type_Dynamic_Guard ctor and dtor for details.
417 if (i < this->current_size_)
418 i = this->current_size_;
420 if (i < this->total_size_)
422 this->service_vector_[i] = sr;
423 this->current_size_++;
424 return_value = 0;
426 else
428 return_value = -1; // no space left
431 // Since there may be "holes" left by removed services one
432 // could consider wrapping current_size_ modulo
433 // total_size_. This is going to impact
434 // ACE_Service_Type_Dynamic_Guard, too and is tricky. Perhaps
435 // a new directive, like "reload" would be better as it can
436 // combine the removal and insertion in an atomic step and
437 // avoid creating too many "holes".
440 #ifndef ACE_NLOGGING
441 if (ACE::debug ())
442 ACE_DEBUG ((LM_DEBUG,
443 ACE_TEXT ("ACE (%P|%t) SR::insert - repo=%@ [%d] (%d),")
444 ACE_TEXT (" name=%s (%s) (type=%@, object=%@, active=%d)\n"),
445 this,
447 this->total_size_,
448 sr->name(),
449 (return_value == 0 ? ((s==0) ? "new" : "replacing") : "failed"),
450 sr->type (),
451 (sr->type () != 0) ? sr->type ()->object () : 0,
452 sr->active ()));
453 #endif
455 // If necessary, delete but outside the lock. (s may be 0, but
456 // that's okay, too)
457 delete s;
459 if (return_value == -1)
460 ACE_OS::last_error (ENOSPC);
462 return return_value;
465 // Resume a service that was previously suspended.
467 ACE_Service_Repository::resume (const ACE_TCHAR name[],
468 const ACE_Service_Type **srp)
470 ACE_TRACE ("ACE_Service_Repository::resume");
471 ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1));
473 size_t i = 0;
474 if (-1 == this->find_i (name, i, srp, 0))
475 return -1;
477 return this->service_vector_[i]->resume ();
480 // Suspend a service so that it will not be considered active under
481 // most circumstances by other portions of the ACE_Service_Repository.
484 ACE_Service_Repository::suspend (const ACE_TCHAR name[],
485 const ACE_Service_Type **srp)
487 ACE_TRACE ("ACE_Service_Repository::suspend");
488 ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1));
489 size_t i = 0;
490 if (-1 == this->find_i (name, i, srp, 0))
491 return -1;
493 return this->service_vector_[i]->suspend ();
498 * @brief Completely remove a <name> entry from the Repository and
499 * dynamically unlink it if it was originally dynamically linked.
503 ACE_Service_Repository::remove (const ACE_TCHAR name[], ACE_Service_Type **ps)
505 ACE_TRACE ("ACE_Service_Repository::remove");
506 ACE_Service_Type *s = 0;
508 ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1));
510 // Not found!?
511 if (this->remove_i (name, &s) == -1)
512 return -1;
515 if (ps != 0)
516 *ps = s;
517 else
518 delete s;
519 return 0;
523 * @brief Completely remove a <name> entry from the Repository and
524 * dynamically unlink it if it was originally dynamically linked.
526 * Return a ptr to the entry in @code ps. There is no locking so make
527 * sure you hold the repo lock when calling.
529 * Since the order of services in the Respository matters, we can't
530 * simply overwrite the entry being deleted with the last and
531 * decrement the <current_size> by 1. A good example of why the order
532 * matters is a dynamic service, in whose DLL there is at least one
533 * static service. In order to prevent SEGV during finalization, those
534 * static services must be finalized _before_the dynamic service that
535 * owns them. Otherwice the TEXT segment, containing the code for the
536 * static service's desructor may be unloaded with the DLL.
538 * Neither can we "pack" the array because this may happen inside the
539 * scope of a Service_Dynamic_Guard, which caches an index where
540 * loading of a DLL started in order to relocate dependent services.
543 ACE_Service_Repository::remove_i (const ACE_TCHAR name[], ACE_Service_Type **ps)
545 size_t i = 0;
546 if (-1 == this->find_i (name, i, 0, false))
547 return -1; // Not found
549 // We may need the old ptr - to be delete outside the lock!
550 *ps = const_cast<ACE_Service_Type *> (this->service_vector_[i]);
552 #ifndef ACE_NLOGGING
553 if (ACE::debug ())
554 ACE_DEBUG ((LM_DEBUG,
555 ACE_TEXT ("ACE (%P|%t) SR::remove_i - repo=%@ [%d] (%d),")
556 ACE_TEXT (" name=%s (removed) (type=%@, active=%d)\n"),
557 this,
559 this->total_size_,
560 name,
561 *ps,
562 (*ps)->active ()));
563 #endif
565 this->service_vector_[i] = 0; // simply leave a gap
566 return 0;
569 ACE_ALLOC_HOOK_DEFINE(ACE_Service_Repository_Iterator)
571 void
572 ACE_Service_Repository_Iterator::dump (void) const
574 #if defined (ACE_HAS_DUMP)
575 ACE_TRACE ("ACE_Service_Repository_Iterator::dump");
576 #endif /* ACE_HAS_DUMP */
580 // Initializes the iterator and skips over any suspended entries at
581 // the beginning of the table, if necessary. Note, you must not
582 // perform destructive operations on elements during this iteration...
584 ACE_Service_Repository_Iterator::ACE_Service_Repository_Iterator
585 (ACE_Service_Repository &sr, int ignr_suspended)
586 : svc_rep_ (sr),
587 next_ (0),
588 ignore_suspended_ (ignr_suspended)
590 while (!(done() || valid()))
591 this->next_++;
594 // Obtains a pointer to the next valid service in the table. If there
595 // are no more entries, returns 0, else 1.
598 ACE_Service_Repository_Iterator::next (const ACE_Service_Type *&sr)
600 ACE_TRACE ("ACE_Service_Repository_Iterator::next");
602 if (done ())
603 return 0;
605 sr = this->svc_rep_.service_vector_[this->next_];
606 return 1;
609 // Advance the iterator by the proper amount. If we are ignoring
610 // suspended entries and the current entry is suspended, then we must
611 // skip over this entry. Otherwise, we must advance the NEXT index to
612 // reference the next valid service entry.
615 ACE_Service_Repository_Iterator::advance (void)
617 ACE_TRACE ("ACE_Service_Repository_Iterator::advance");
619 if (done()) return 0;
621 do this->next_++; while (!(done () || valid ()));
623 return !done();
626 bool
627 ACE_Service_Repository_Iterator::valid (void) const
629 ACE_TRACE ("ACE_Service_Repository_Iterator::valid");
630 if (!this->ignore_suspended_)
631 return (this->svc_rep_.service_vector_[this->next_] != 0); // skip over gaps
633 return (this->svc_rep_.service_vector_[this->next_] != 0
634 && this->svc_rep_.service_vector_[this->next_]->active ());
637 ACE_END_VERSIONED_NAMESPACE_DECL