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"
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;
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
),
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
;
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.
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
);
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);
120 // Do not be tempted to use the prefix decrement operator. Use
121 // postfix decrement operator since the index is unsigned and may
124 // debug output for empty service entries
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
]);
133 ACELIB_DEBUG ((LM_DEBUG
,
134 ACE_TEXT ("ACE (%P|%t) SR::fini, repo=%@ [%d] -> 0\n"),
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
]);
151 (s
->type ()->service_type () != ACE_Service_Type::MODULE
))
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"),
163 (s
->type () != 0) ? s
->type ()->object () : 0,
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
]);
183 (s
->type ()->service_type () == ACE_Service_Type::MODULE
))
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"),
195 (s
->type () != 0) ? s
->type ()->object () : 0,
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);
216 ACELIB_DEBUG ((LM_DEBUG
,
217 ACE_TEXT ("ACE (%P|%t) SR::close - repo=%@, size=%d\n"),
219 this->service_array_
.size()));
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
]);
234 ACELIB_DEBUG ((LM_DEBUG
,
235 ACE_TEXT ("ACE (%P|%t) SR::close - repo=%@ [%d] -> 0\n"),
239 ACELIB_DEBUG ((LM_DEBUG
,
240 ACE_TEXT ("ACE (%P|%t) SR::close - repo=%@ [%d], name=%s, object=%@\n"),
250 this->service_array_
.clear ();
255 ACE_Service_Repository::~ACE_Service_Repository ()
257 ACE_TRACE ("ACE_Service_Repository::~ACE_Service_Repository");
260 ACELIB_DEBUG ((LM_DEBUG
, "ACE (%P|%t) SR::<dtor>, this=%@\n", this));
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
[],
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)
289 if (iter
!= this->service_array_
.end ())
291 slot
= (*iter
).first
;
292 if ((*iter
).second
->fini_called ())
300 *srp
= (*iter
).second
;
303 && (*iter
).second
->active () == 0)
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
,
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);
338 ACELIB_DEBUG ((LM_DEBUG
,
339 ACE_TEXT ("ACE (%P|%t) SR::relocate_i - repo=%@ [%d]")
340 ACE_TEXT (": skipping empty slot\n"),
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"),
355 if (type
!= 0 // skip any gaps
356 && old_handle
== ACE_SHLIB_INVALID_HANDLE
357 && new_handle
!= old_handle
)
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"),
370 type
->dll (adll
); // ups the refcount on adll
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");
398 int return_value
= -1;
399 ACE_Service_Type
const *s
= 0;
401 // Establish scope for locking while manipulating the service
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);
413 this->service_array_
[i
] = sr
;
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
;
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"),
438 (return_value
== 0 ? ((s
==0) ? "new" : "replacing") : "failed"),
440 (sr
->type () != 0) ? sr
->type ()->object () : 0,
444 // If necessary, delete but outside the lock. (s may be 0, but
448 if (return_value
== -1)
449 ACE_OS::last_error (ENOSPC
);
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);
463 if (-1 == this->find_i (name
, i
, srp
, 0))
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);
478 if (-1 == this->find_i (name
, i
, srp
, 0))
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);
497 if (this->remove_i (name
, &s
) == -1)
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
)
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
]);
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"),
550 this->service_array_
[i
] = 0; // simply leave a gap
554 ACE_ALLOC_HOOK_DEFINE(ACE_Service_Repository_Iterator
)
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
)
571 ignore_suspended_ (ignored_suspended
)
573 while (!(done() || valid()))
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");
587 sr
= this->svc_rep_
.service_array_
[this->next_
];
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 ()));
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