Service_Repository.cpp

Go to the documentation of this file.
00001 // $Id: Service_Repository.cpp 79134 2007-07-31 18:23:50Z johnnyw $
00002 
00003 #include "ace/Service_Repository.h"
00004 
00005 #if !defined (__ACE_INLINE__)
00006 #include "ace/Service_Repository.inl"
00007 #endif /* __ACE_INLINE__ */
00008 
00009 #include "ace/Service_Types.h"
00010 #include "ace/Object_Manager.h"
00011 #include "ace/Log_Msg.h"
00012 #include "ace/ACE.h"
00013 #include "ace/OS_NS_unistd.h"
00014 #include "ace/OS_NS_errno.h"
00015 #include "ace/OS_NS_string.h"
00016 
00017 ACE_RCSID (ace,
00018            Service_Repository,
00019            "$Id: Service_Repository.cpp 79134 2007-07-31 18:23:50Z johnnyw $")
00020 
00021   ACE_BEGIN_VERSIONED_NAMESPACE_DECL
00022 
00023 ACE_ALLOC_HOOK_DEFINE(ACE_Service_Repository)
00024 
00025 // Process-wide Service Repository.
00026 ACE_Service_Repository *ACE_Service_Repository::svc_rep_ = 0;
00027 
00028 // Controls whether the Service_Repository is deleted when we shut
00029 // down (we can only delete it safely if we created it)!
00030 int ACE_Service_Repository::delete_svc_rep_ = 0;
00031 
00032 void
00033 ACE_Service_Repository::dump (void) const
00034 {
00035 #if defined (ACE_HAS_DUMP)
00036   ACE_TRACE ("ACE_Service_Repository::dump");
00037 #endif /* ACE_HAS_DUMP */
00038 }
00039 
00040 ACE_Service_Repository::ACE_Service_Repository (void)
00041   : service_vector_ (0),
00042     current_size_ (0),
00043     total_size_ (0)
00044 {
00045   ACE_TRACE ("ACE_Service_Repository::ACE_Service_Repository");
00046 }
00047 
00048 ACE_Service_Repository *
00049 ACE_Service_Repository::instance (size_t size /* = ACE_Service_Repository::DEFAULT_SIZE */)
00050 {
00051   ACE_TRACE ("ACE_Service_Repository::instance");
00052 
00053   if (ACE_Service_Repository::svc_rep_ == 0)
00054     {
00055       // Perform Double-Checked Locking Optimization.
00056       ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon,
00057                                 *ACE_Static_Object_Lock::instance (), 0));
00058       if (ACE_Service_Repository::svc_rep_ == 0)
00059         {
00060           if (ACE_Object_Manager::starting_up () ||
00061               !ACE_Object_Manager::shutting_down ())
00062             {
00063               ACE_NEW_RETURN (ACE_Service_Repository::svc_rep_,
00064                               ACE_Service_Repository (size),
00065                               0);
00066               ACE_Service_Repository::delete_svc_rep_ = 1;
00067             }
00068         }
00069     }
00070 
00071   return ACE_Service_Repository::svc_rep_;
00072 }
00073 
00074 ACE_Service_Repository *
00075 ACE_Service_Repository::instance (ACE_Service_Repository *s)
00076 {
00077   ACE_TRACE ("ACE_Service_Repository::instance");
00078   ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon,
00079                             *ACE_Static_Object_Lock::instance (), 0));
00080 
00081   ACE_Service_Repository *t = ACE_Service_Repository::svc_rep_;
00082   // We can't safely delete it since we don't know who created it!
00083   ACE_Service_Repository::delete_svc_rep_ = 0;
00084 
00085   ACE_Service_Repository::svc_rep_ = s;
00086   return t;
00087 }
00088 
00089 void
00090 ACE_Service_Repository::close_singleton (void)
00091 {
00092   ACE_TRACE ("ACE_Service_Repository::close_singleton");
00093 
00094   ACE_MT (ACE_GUARD (ACE_Recursive_Thread_Mutex, ace_mon,
00095                      *ACE_Static_Object_Lock::instance ()));
00096 
00097   if (ACE_Service_Repository::delete_svc_rep_)
00098     {
00099       delete ACE_Service_Repository::svc_rep_;
00100       ACE_Service_Repository::svc_rep_ = 0;
00101       ACE_Service_Repository::delete_svc_rep_ = 0;
00102     }
00103 }
00104 
00105 // Initialize the Repository to a clean slate.
00106 
00107 int
00108 ACE_Service_Repository::open (size_t size)
00109 {
00110   ACE_TRACE ("ACE_Service_Repository::open");
00111 
00112   ACE_Service_Type **temp;
00113 
00114   ACE_NEW_RETURN (temp,
00115                   ACE_Service_Type *[size],
00116                   -1);
00117 
00118   this->service_vector_ = const_cast<const ACE_Service_Type **> (temp);
00119   this->total_size_ = size;
00120   return 0;
00121 }
00122 
00123 ACE_Service_Repository::ACE_Service_Repository (size_t size)
00124   : current_size_ (0)
00125 {
00126   ACE_TRACE ("ACE_Service_Repository::ACE_Service_Repository");
00127 
00128   if (this->open (size) == -1)
00129     ACE_ERROR ((LM_ERROR,
00130                 ACE_TEXT ("%p\n"),
00131                 ACE_TEXT ("ACE_Service_Repository")));
00132 }
00133 
00134 // Finalize (call <fini> and possibly delete) all the services.
00135 
00136 int
00137 ACE_Service_Repository::fini (void)
00138 {
00139   ACE_TRACE ("ACE_Service_Repository::fini");
00140   ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1));
00141   int retval = 0;
00142 
00143   if (this->service_vector_ != 0)
00144     {
00145       // <fini> the services in reverse order.  Note that if services
00146       // were removed from the middle of the repository the order
00147       // won't necessarily be maintained since the <remove> method
00148       // performs compaction.  However, the common case is not to
00149       // remove services, so typically they are deleted in reverse
00150       // order.
00151 
00152       // Do not be tempted to use the prefix decrement operator.  We
00153       // need to use the postfix decrement operator in this case since
00154       // the index is unsigned.
00155       for (size_t i = this->current_size_; i-- != 0; )
00156         {
00157           ACE_Service_Type *s =
00158             const_cast<ACE_Service_Type *> (this->service_vector_[i]);
00159 
00160 #ifndef ACE_NLOGGING
00161           if (ACE::debug ())
00162               ACE_DEBUG ((LM_DEBUG,
00163                           ACE_TEXT ("ACE (%P|%t) SR::fini, repo=%@ [%d] (%d), ")
00164                           ACE_TEXT ("name=%s, type=%@, impl=%@, object=%@, active=%d\n"),
00165                           this, i, this->total_size_, s->name(), s->type (),
00166                           (s->type () != 0) ? s->type ()->object () : 0,
00167                           s->active ()));
00168 #endif
00169 
00170           // Collect any errors.
00171           int ret = s->fini ();
00172           retval += ret;
00173         }
00174     }
00175 
00176   return (retval == 0) ? 0 : -1;
00177 }
00178 
00179 // Close down all the services.
00180 
00181 int
00182 ACE_Service_Repository::close (void)
00183 {
00184   ACE_TRACE ("ACE_Service_Repository::close");
00185   ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1));
00186 
00187   if (this->service_vector_ != 0)
00188     {
00189       // Delete services in reverse order.  Note that if services were
00190       // removed from the middle of the repository the order won't
00191       // necessarily be maintained since the <remove> method performs
00192       // compaction.  However, the common case is not to remove
00193       // services, so typically they are deleted in reverse order.
00194 
00195 #ifndef ACE_NLOGGING
00196       if(ACE::debug ())
00197         ACE_DEBUG ((LM_DEBUG,
00198                     ACE_TEXT ("(%P|%t) SR::close, this=%@, size=%d\n"),
00199                     this,
00200                     this->current_size_));
00201 #endif
00202 
00203       // Do not be tempted to use the prefix decrement operator.  We
00204       // need to use the postfix decrement operator in this case since
00205       // the index is unsigned.
00206       for (size_t i = this->current_size_; i-- != 0; )
00207         {
00208 
00209 #ifndef ACE_NLOGGING
00210           if(ACE::debug ())
00211             ACE_DEBUG ((LM_DEBUG,
00212                         ACE_TEXT ("(%P|%t) SR::close, this=%@, delete so[%d]=%@ (%s)\n"),
00213                         this, i,
00214                         this->service_vector_[i],
00215                         this->service_vector_[i]->name ()));
00216 #endif
00217 
00218           ACE_Service_Type *s = const_cast<ACE_Service_Type *> (this->service_vector_[i]);
00219           --this->current_size_;
00220           delete s;
00221         }
00222 
00223       delete [] this->service_vector_;
00224       this->service_vector_ = 0;
00225       this->current_size_ = 0;
00226     }
00227 
00228   return 0;
00229 }
00230 
00231 ACE_Service_Repository::~ACE_Service_Repository (void)
00232 {
00233   ACE_TRACE ("ACE_Service_Repository::~ACE_Service_Repository");
00234 #ifndef ACE_NLOGGING
00235   if(ACE::debug ())
00236     ACE_DEBUG ((LM_DEBUG, "(%P|%t) SR::<dtor>, this=%@\n", this));
00237 #endif
00238   this->close ();
00239 }
00240 
00241 // Locate an entry with <name> in the table.  If <ignore_suspended> is
00242 // set then only consider services marked as resumed.  If the caller
00243 // wants the located entry, pass back a pointer to the located entry
00244 // via <srp>.  If <name> is not found -1 is returned.  If <name> is
00245 // found, but it is suspended and the caller wants to ignore suspended
00246 // services a -2 is returned.  Must be called with locks held.
00247 
00248 int
00249 ACE_Service_Repository::find_i (const ACE_TCHAR name[],
00250                                 size_t &slot,
00251                                 const ACE_Service_Type **srp,
00252                                 bool ignore_suspended) const
00253 {
00254   ACE_TRACE ("ACE_Service_Repository::find_i");
00255   size_t i;
00256 
00257   for (i = 0; i < this->current_size_; i++)
00258     if (ACE_OS::strcmp (name,
00259                         this->service_vector_[i]->name ()) == 0)
00260       break;
00261 
00262   if (i < this->current_size_)
00263     {
00264       slot = i;
00265       if (this->service_vector_[i]->fini_called ())
00266         {
00267           if (srp != 0)
00268             *srp = 0;
00269           return -1;
00270         }
00271 
00272       if (srp != 0)
00273         *srp = this->service_vector_[i];
00274       if (ignore_suspended
00275           && this->service_vector_[i]->active () == 0)
00276         return -2;
00277       return 0;
00278     }
00279   else
00280     return -1;
00281 }
00282 
00283 
00284 /// @brief Relocate (a static) service to another DLL.
00285 ///
00286 /// Works by having the service type keep a reference to a specific
00287 /// DLL. No locking, caller makes sure calling it is safe. You can
00288 /// forcefully relocate any DLLs in the given range, not only the
00289 /// static ones - but that will cause Very Bad Things (tm) to happen.
00290 
00291 int
00292 ACE_Service_Repository::relocate_i (size_t begin,
00293                                     size_t end,
00294                                     const ACE_DLL& adll,
00295                                     bool static_only)
00296 {
00297   ACE_SHLIB_HANDLE new_handle = adll.get_handle (0);
00298 
00299   for (size_t i = begin; i < end; i++)
00300     {
00301       ACE_Service_Type *type =
00302         const_cast<ACE_Service_Type *> (this->service_vector_[i]);
00303 
00304       ACE_SHLIB_HANDLE old_handle =  type->dll ().get_handle (0);
00305       if (static_only && old_handle != ACE_SHLIB_INVALID_HANDLE)
00306         continue;
00307 
00308 #ifndef ACE_NLOGGING
00309     if (ACE::debug ())
00310         ACE_DEBUG ((LM_DEBUG,
00311                     ACE_TEXT ("ACE (%P|%t) SR::relocate, repo=%@ [%d] (size=%d): name=%s - DLL from=%d to=%d\n"),
00312                     this, i, this->total_size_, type->name (),
00313                     old_handle,
00314                     new_handle));
00315 #else
00316   ACE_UNUSED_ARG (new_handle);
00317 #endif
00318       type->dll (adll);
00319     }
00320 
00321   return 0;
00322 }
00323 
00324 int
00325 ACE_Service_Repository::find (const ACE_TCHAR name[],
00326                               const ACE_Service_Type **srp,
00327                               bool ignore_suspended) const
00328 {
00329   ACE_TRACE ("ACE_Service_Repository::find");
00330   ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1));
00331   size_t ignore_location = 0;
00332   return this->find_i (name, ignore_location, srp, ignore_suspended);
00333 }
00334 
00335 
00336 // Insert the ACE_Service_Type SR into the repository.  Note that
00337 // services may be inserted either resumed or suspended. Using same name
00338 // as in an existing service causes the delete () to be called for the old one,
00339 // i.e. make sure @code sr is allocated on the heap!
00340 
00341 int
00342 ACE_Service_Repository::insert (const ACE_Service_Type *sr)
00343 {
00344   ACE_TRACE ("ACE_Service_Repository::insert");
00345 
00346   int return_value = -1;
00347   ACE_Service_Type *s = 0;
00348   size_t i = 0;
00349 
00350   {
00351     // @TODO: Do we need a recursive mutex here?
00352     ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1));
00353 
00354     // Check to see if this is a duplicate.
00355     for (i = 0; i < this->current_size_; i++)
00356       if (ACE_OS::strcmp (sr->name (),
00357                           this->service_vector_[i]->name ()) == 0)
00358         break;
00359 
00360     // Replacing an existing entry
00361     if (i < this->current_size_)
00362       {
00363         return_value = 0;
00364         // Check for self-assignment...
00365         if (sr != this->service_vector_[i])
00366           {
00367             s = const_cast<ACE_Service_Type *> (this->service_vector_[i]);
00368             this->service_vector_[i] = sr;
00369           }
00370       }
00371     // Adding a new entry.
00372     else if (i < this->total_size_)
00373       {
00374         this->service_vector_[i] = sr;
00375         this->current_size_++;
00376         return_value = 0;
00377       }
00378 
00379 #ifndef ACE_NLOGGING
00380     if (ACE::debug ())
00381       ACE_DEBUG ((LM_DEBUG,
00382                   ACE_TEXT ("ACE (%P|%t) SR::insert")
00383                   ACE_TEXT (" - repo=%@ [%d] (%d), name=%s")
00384                   ACE_TEXT (", type=%@, object=%@, active=%d\n"),
00385                   this, i, this->total_size_, sr->name(), sr->type (),
00386                   (sr->type () != 0) ? sr->type ()->object () : 0,
00387                   sr->active ()));
00388 #endif
00389   }
00390 
00391   // Delete outside the lock
00392   if (s != 0)
00393     {
00394 #ifndef ACE_NLOGGING
00395       if (ACE::debug ())
00396         ACE_DEBUG ((LM_DEBUG,
00397                     ACE_TEXT ("ACE (%P|%t) SR::insert")
00398                     ACE_TEXT (" - destroying (replacing), repo=%@ [%d] (%d), name=%s")
00399                     ACE_TEXT (", type=%@, object=%@, active=%d\n"),
00400                     this, i, this->total_size_, s->name(), s->type (),
00401                     (s->type () != 0) ? s->type ()->object () : 0,
00402                     s->active ()));
00403 #endif
00404       delete s;
00405     }
00406 
00407   if (return_value == -1)
00408     ACE_OS::last_error (ENOSPC);
00409 
00410   return return_value;
00411 }
00412 
00413 // Re-resume a service that was previously suspended.
00414 
00415 int
00416 ACE_Service_Repository::resume (const ACE_TCHAR name[],
00417                                 const ACE_Service_Type **srp)
00418 {
00419   ACE_TRACE ("ACE_Service_Repository::resume");
00420   ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1));
00421 
00422   size_t i = 0;
00423   if (-1 == this->find_i (name, i, srp, 0))
00424     return -1;
00425 
00426   return this->service_vector_[i]->resume ();
00427 }
00428 
00429 // Suspend a service so that it will not be considered active under
00430 // most circumstances by other portions of the ACE_Service_Repository.
00431 
00432 int
00433 ACE_Service_Repository::suspend (const ACE_TCHAR name[],
00434                                  const ACE_Service_Type **srp)
00435 {
00436   ACE_TRACE ("ACE_Service_Repository::suspend");
00437   ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1));
00438   size_t i = 0;
00439   if (-1 == this->find_i (name, i, srp, 0))
00440     return -1;
00441 
00442   return this->service_vector_[i]->suspend ();
00443 }
00444 
00445 
00446 /**
00447  * @brief Completely remove a <name> entry from the Repository and
00448  * dynamically unlink it if it was originally dynamically linked.
00449  */
00450 
00451 int
00452 ACE_Service_Repository::remove (const ACE_TCHAR name[], ACE_Service_Type **ps)
00453 {
00454   ACE_TRACE ("ACE_Service_Repository::remove");
00455   ACE_Service_Type *s = 0;
00456   {
00457     ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1));
00458 
00459     // Not found!?
00460     if (this->remove_i (name, &s) == -1)
00461       return -1;
00462   }
00463 
00464   if (ps != 0)
00465     *ps = s;
00466   else
00467     delete s;
00468   return 0;
00469 }
00470 
00471 /**
00472  * @brief Completely remove a <name> entry from the Repository and
00473  * dynamically unlink it if it was originally dynamically linked.
00474  *
00475  * Return a ptr to the entry in @code ps. There is no locking so make
00476  * sure you hold the repo lock when calling.
00477  *
00478  * Since the order of services in the Respository matters, we can't
00479  * simply overwrite the entry being deleted with the last and
00480  * decrement the <current_size> by 1 - we must "pack" the array.  A
00481  * good example of why the order matters is a dynamic service, in
00482  * whose DLL there is at least one static service. In order to prevent
00483  * SEGV during finalization, those static services must be finalized
00484  * _before_the dynamic service that owns them. Otherwice the TEXT
00485  * segment, containing the code for the static service's desructor may
00486  * be unloaded with the DLL.
00487  *
00488  * @note: (IJ) The above is not entirely true, since the introduction
00489  * of the ACE_Service_Dynamic_Guard, which fixes-up any stray static
00490  * services to hold a reference to the DLL. This allows out-of order
00491  * removals and perhaps allows to skip packing the repo. I left it in
00492  * because a packed repo is a lot easier to debug.
00493  */
00494 int
00495 ACE_Service_Repository::remove_i (const ACE_TCHAR name[], ACE_Service_Type **ps)
00496 {
00497   size_t i = 0;
00498   if (-1 == this->find_i (name, i, 0, false))
00499     return -1;    // Not found
00500 
00501   // We may need the old ptr - to be delete outside the lock!
00502   *ps = const_cast<ACE_Service_Type *> (this->service_vector_[i]);
00503 
00504   // Pack the array
00505   --this->current_size_;
00506   for (size_t j = i; j < this->current_size_; j++)
00507     this->service_vector_[j] = this->service_vector_[j+1];
00508 
00509   return 0;
00510 }
00511 
00512 ACE_ALLOC_HOOK_DEFINE(ACE_Service_Repository_Iterator)
00513 
00514 void
00515 ACE_Service_Repository_Iterator::dump (void) const
00516 {
00517 #if defined (ACE_HAS_DUMP)
00518   ACE_TRACE ("ACE_Service_Repository_Iterator::dump");
00519 #endif /* ACE_HAS_DUMP */
00520 }
00521 
00522 
00523 // Initializes the iterator and skips over any suspended entries at
00524 // the beginning of the table, if necessary.  Note, you must not
00525 // perform destructive operations on elements during this iteration...
00526 
00527 ACE_Service_Repository_Iterator::ACE_Service_Repository_Iterator
00528   (ACE_Service_Repository &sr, int ignr_suspended)
00529   : svc_rep_ (sr),
00530     next_ (0),
00531     ignore_suspended_ (ignr_suspended)
00532 {
00533   while (!(done() || valid()))
00534     this->next_++;
00535 }
00536 
00537 // Obtains a pointer to the next valid service in the table.  If there
00538 // are no more entries, returns 0, else 1.
00539 
00540 int
00541 ACE_Service_Repository_Iterator::next (const ACE_Service_Type *&sr)
00542 {
00543   ACE_TRACE ("ACE_Service_Repository_Iterator::next");
00544 
00545   if (done ())
00546     return 0;
00547 
00548   sr = this->svc_rep_.service_vector_[this->next_];
00549   return 1;
00550 }
00551 
00552 // Advance the iterator by the proper amount.  If we are ignoring
00553 // suspended entries and the current entry is suspended, then we must
00554 // skip over this entry.  Otherwise, we must advance the NEXT index to
00555 // reference the next valid service entry.
00556 
00557 int
00558 ACE_Service_Repository_Iterator::advance (void)
00559 {
00560   ACE_TRACE ("ACE_Service_Repository_Iterator::advance");
00561 
00562   if (done()) return 0;
00563 
00564   do this->next_++; while (!(done () || valid ()));
00565 
00566   return !done();
00567 }
00568 
00569 bool
00570 ACE_Service_Repository_Iterator::valid (void) const
00571 {
00572   ACE_TRACE ("ACE_Service_Repository_Iterator::valid");
00573   return (this->ignore_suspended_ == 0
00574           || this->svc_rep_.service_vector_[this->next_]->active ());
00575 }
00576 
00577 ACE_END_VERSIONED_NAMESPACE_DECL

Generated on Sun Jan 27 12:05:37 2008 for ACE by doxygen 1.3.6