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"
13 #include "ace/OS_NS_unistd.h"
14 #include "ace/OS_NS_errno.h"
15 #include "ace/OS_NS_string.h"
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;
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),
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
),
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
;
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
],
118 this->service_vector_
= const_cast<const ACE_Service_Type
**> (temp
);
119 this->total_size_
= size
;
123 ACE_Service_Repository::ACE_Service_Repository (size_t size
)
126 ACE_TRACE ("ACE_Service_Repository::ACE_Service_Repository");
128 if (this->open (size
) == -1)
129 ACE_ERROR ((LM_ERROR
,
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)
147 // Do not be tempted to use the prefix decrement operator. Use
148 // postfix decrement operator since the index is unsigned and may
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
]);
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"),
168 (s
->type () != 0) ? s
->type ()->object () : 0,
171 ACE_DEBUG ((LM_DEBUG
,
172 ACE_TEXT ("ACE (%P|%t) SR::fini, repo=%@ [%d] (%d) -> 0\n"),
179 // Collect any errors.
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)
200 ACE_DEBUG ((LM_DEBUG
,
201 ACE_TEXT ("(%P|%t) SR::close - repo=%@, size=%d\n"),
203 this->current_size_
));
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
]);
218 ACE_DEBUG ((LM_DEBUG
,
219 ACE_TEXT ("(%P|%t) SR::close - repo=%@ [%d] -> 0\n"),
223 ACE_DEBUG ((LM_DEBUG
,
224 ACE_TEXT ("(%P|%t) SR::close - repo=%@ [%d], name=%s, object=%@\n"),
231 --this->current_size_
;
235 delete [] this->service_vector_
;
236 this->service_vector_
= 0;
237 this->current_size_
= 0;
242 ACE_Service_Repository::~ACE_Service_Repository (void)
244 ACE_TRACE ("ACE_Service_Repository::~ACE_Service_Repository");
247 ACE_DEBUG ((LM_DEBUG
, "(%P|%t) SR::<dtor>, this=%@\n", this));
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
[],
262 const ACE_Service_Type
**srp
,
263 bool ignore_suspended
) const
265 ACE_TRACE ("ACE_Service_Repository::find_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)
276 if (i
< this->current_size_
)
279 if (this->service_vector_
[i
]->fini_called ())
287 *srp
= this->service_vector_
[i
];
290 && this->service_vector_
[i
]->active () == 0)
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
,
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);
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"),
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"),
345 if (type
!= 0 // skip any gaps
346 && old_handle
== ACE_SHLIB_INVALID_HANDLE
347 && new_handle
!= old_handle
)
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"),
361 type
->dll (adll
); // ups the refcount on adll
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");
390 int return_value
= -1;
391 ACE_Service_Type
const *s
= 0;
393 // Establish scope for locking while manipulating the service
396 // @TODO: Do we need a recursive mutex here?
397 ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex
,
402 return_value
= find_i (sr
->name (), i
, &s
, false);
407 this->service_vector_
[i
] = sr
;
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_
++;
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".
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"),
449 (return_value
== 0 ? ((s
==0) ? "new" : "replacing") : "failed"),
451 (sr
->type () != 0) ? sr
->type ()->object () : 0,
455 // If necessary, delete but outside the lock. (s may be 0, but
459 if (return_value
== -1)
460 ACE_OS::last_error (ENOSPC
);
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));
474 if (-1 == this->find_i (name
, i
, srp
, 0))
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));
490 if (-1 == this->find_i (name
, i
, srp
, 0))
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));
511 if (this->remove_i (name
, &s
) == -1)
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
)
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
]);
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"),
565 this->service_vector_
[i
] = 0; // simply leave a gap
569 ACE_ALLOC_HOOK_DEFINE(ACE_Service_Repository_Iterator
)
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
)
588 ignore_suspended_ (ignr_suspended
)
590 while (!(done() || valid()))
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");
605 sr
= this->svc_rep_
.service_vector_
[this->next_
];
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 ()));
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