Service_Repository.cpp

Go to the documentation of this file.
00001 // $Id: Service_Repository.cpp 81388 2008-04-23 14:02:05Z 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 81388 2008-04-23 14:02:05Z 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 bool ACE_Service_Repository::delete_svc_rep_ = false;
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_ = true;
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_ = false;
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_ = false;
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 = 0;
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 
00142   if (this->service_vector_ == 0)
00143     return 0;
00144 
00145   int retval = 0;
00146 
00147   // Do not be tempted to use the prefix decrement operator.  Use
00148   // postfix decrement operator since the index is unsigned and may
00149   // wrap around the 0
00150   for (size_t i = this->current_size_; i-- != 0; )
00151     {
00152       // <fini> the services in reverse order.
00153       ACE_Service_Type *s =
00154         const_cast<ACE_Service_Type *> (this->service_vector_[i]);
00155 
00156 #ifndef ACE_NLOGGING
00157       if (ACE::debug ())
00158         {
00159           if (s != 0)
00160             ACE_DEBUG ((LM_DEBUG,
00161                         ACE_TEXT ("ACE (%P|%t) SR::fini, repo=%@ [%d] (%d), ")
00162                         ACE_TEXT ("name=%s, type=%@, object=%@, active=%d\n"),
00163                         this,
00164                         i,
00165                         this->total_size_,
00166                         s->name(),
00167                         s->type (),
00168                         (s->type () != 0) ? s->type ()->object () : 0,
00169                         s->active ()));
00170           else
00171             ACE_DEBUG ((LM_DEBUG,
00172                         ACE_TEXT ("ACE (%P|%t) SR::fini, repo=%@ [%d] (%d) -> 0\n"),
00173                         this,
00174                         i,
00175                         this->total_size_));
00176         }
00177 #endif
00178 
00179       // Collect any errors.
00180       if (s != 0)
00181         retval += s->fini ();
00182     }
00183 
00184   return (retval == 0) ? 0 : -1;
00185 }
00186 
00187 // Close down all the services.
00188 
00189 int
00190 ACE_Service_Repository::close (void)
00191 {
00192   ACE_TRACE ("ACE_Service_Repository::close");
00193   ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1));
00194 
00195   if (this->service_vector_ == 0)
00196     return 0;
00197 
00198 #ifndef ACE_NLOGGING
00199   if(ACE::debug ())
00200     ACE_DEBUG ((LM_DEBUG,
00201                 ACE_TEXT ("(%P|%t) SR::close - repo=%@, size=%d\n"),
00202                 this,
00203                 this->current_size_));
00204 #endif
00205 
00206   // Do not use the prefix decrement operator since the index is
00207   // unsigned and may wrap around the 0.
00208   for (size_t i = this->current_size_; i-- != 0; )
00209     {
00210       // Delete services in reverse order.
00211       ACE_Service_Type *s =
00212         const_cast<ACE_Service_Type *> (this->service_vector_[i]);
00213 
00214 #ifndef ACE_NLOGGING
00215       if(ACE::debug ())
00216         {
00217           if (s == 0)
00218             ACE_DEBUG ((LM_DEBUG,
00219                         ACE_TEXT ("(%P|%t) SR::close - repo=%@ [%d] -> 0\n"),
00220                         this,
00221                         i));
00222           else
00223             ACE_DEBUG ((LM_DEBUG,
00224                         ACE_TEXT ("(%P|%t) SR::close - repo=%@ [%d], name=%s, object=%@\n"),
00225                         this,
00226                         i,
00227                         s->name (),
00228                         s));
00229         }
00230 #endif
00231       --this->current_size_;
00232       delete s;
00233     }
00234 
00235   delete [] this->service_vector_;
00236   this->service_vector_ = 0;
00237   this->current_size_ = 0;
00238 
00239   return 0;
00240 }
00241 
00242 ACE_Service_Repository::~ACE_Service_Repository (void)
00243 {
00244   ACE_TRACE ("ACE_Service_Repository::~ACE_Service_Repository");
00245 #ifndef ACE_NLOGGING
00246   if(ACE::debug ())
00247     ACE_DEBUG ((LM_DEBUG, "(%P|%t) SR::<dtor>, this=%@\n", this));
00248 #endif
00249   this->close ();
00250 }
00251 
00252 // Locate an entry with <name> in the table.  If <ignore_suspended> is
00253 // set then only consider services marked as resumed.  If the caller
00254 // wants the located entry, pass back a pointer to the located entry
00255 // via <srp>.  If <name> is not found -1 is returned.  If <name> is
00256 // found, but it is suspended and the caller wants to ignore suspended
00257 // services a -2 is returned.  Must be called with locks held.
00258 
00259 int
00260 ACE_Service_Repository::find_i (const ACE_TCHAR name[],
00261                                 size_t &slot,
00262                                 const ACE_Service_Type **srp,
00263                                 bool ignore_suspended) const
00264 {
00265   ACE_TRACE ("ACE_Service_Repository::find_i");
00266   size_t i;
00267 
00268   for (i = 0; i < this->current_size_; i++)
00269     {
00270       if (this->service_vector_[i] != 0 // skip any empty slots
00271           && ACE_OS::strcmp (name,
00272                              this->service_vector_[i]->name ()) == 0)
00273         break;
00274     }
00275 
00276   if (i < this->current_size_)
00277     {
00278       slot = i;
00279       if (this->service_vector_[i]->fini_called ())
00280         {
00281           if (srp != 0)
00282             *srp = 0;
00283           return -1;
00284         }
00285 
00286       if (srp != 0)
00287         *srp = this->service_vector_[i];
00288 
00289       if (ignore_suspended
00290           && this->service_vector_[i]->active () == 0)
00291         return -2;
00292 
00293       return 0;
00294     }
00295 
00296   return -1;
00297 }
00298 
00299 
00300 /// @brief Relocate (a static) service to another DLL.
00301 ///
00302 /// Works by having the service type keep a reference to a specific
00303 /// DLL. No locking, caller makes sure calling it is safe. You can
00304 /// forcefully relocate any DLLs in the given range, not only the
00305 /// static ones - but that will cause Very Bad Things (tm) to happen.
00306 
00307 int
00308 ACE_Service_Repository::relocate_i (size_t begin,
00309                                     size_t end,
00310                                     const ACE_DLL& adll)
00311 {
00312   ACE_SHLIB_HANDLE new_handle = adll.get_handle (0);
00313 
00314   for (size_t i = begin; i < end; i++)
00315     {
00316       ACE_Service_Type *type =
00317         const_cast<ACE_Service_Type *> (this->service_vector_[i]);
00318 
00319       ACE_SHLIB_HANDLE old_handle = (type == 0) ? ACE_SHLIB_INVALID_HANDLE
00320                                                 : type->dll ().get_handle (0);
00321 
00322 #ifndef ACE_NLOGGING
00323       if (ACE::debug ())
00324         {
00325           if (type == 0)
00326             ACE_DEBUG ((LM_DEBUG,
00327                         ACE_TEXT ("ACE (%P|%t) SR::relocate_i - repo=%@ [%d] (size=%d)")
00328                         ACE_TEXT (": skipping empty slot\n"),
00329                         this,
00330                         i,
00331                         this->total_size_));
00332           else
00333             ACE_DEBUG ((LM_DEBUG,
00334                         ACE_TEXT ("ACE (%P|%t) SR::relocate_i - repo=%@ [%d] (size=%d)")
00335                         ACE_TEXT (": trying name=%s, handle: %d -> %d\n"),
00336                         this,
00337                         i,
00338                         this->total_size_,
00339                         type->name (),
00340                         old_handle,
00341                         new_handle));
00342         }
00343 #endif
00344 
00345       if (type != 0  // skip any gaps
00346           && old_handle == ACE_SHLIB_INVALID_HANDLE
00347           && new_handle != old_handle)
00348         {
00349 #ifndef ACE_NLOGGING
00350           if (ACE::debug ())
00351             ACE_DEBUG ((LM_DEBUG,
00352                         ACE_TEXT ("ACE (%P|%t) SR::relocate_i - repo=%@ [%d] (size=%d)")
00353                         ACE_TEXT (": relocating name=%s, handle: %d -> %d\n"),
00354                         this,
00355                         i,
00356                         this->total_size_,
00357                         type->name (),
00358                         old_handle,
00359                         new_handle));
00360 #endif
00361           type->dll (adll); // ups the refcount on adll
00362         }
00363     }
00364 
00365   return 0;
00366 }
00367 
00368 int
00369 ACE_Service_Repository::find (const ACE_TCHAR name[],
00370                               const ACE_Service_Type **srp,
00371                               bool ignore_suspended) const
00372 {
00373   ACE_TRACE ("ACE_Service_Repository::find");
00374   ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1));
00375   size_t ignore_location = 0;
00376   return this->find_i (name, ignore_location, srp, ignore_suspended);
00377 }
00378 
00379 
00380 // Insert the ACE_Service_Type SR into the repository.  Note that
00381 // services may be inserted either resumed or suspended. Using same
00382 // name as in an existing service causes the delete () to be called
00383 // for the old one, i.e. make sure @code sr is allocated on the heap!
00384 int
00385 ACE_Service_Repository::insert (const ACE_Service_Type *sr)
00386 {
00387   ACE_TRACE ("ACE_Service_Repository::insert");
00388 
00389   size_t i = 0;
00390   int return_value = -1;
00391   ACE_Service_Type const *s = 0;
00392 
00393   // Establish scope for locking while manipulating the service
00394   // storage
00395   {
00396     // @TODO: Do we need a recursive mutex here?
00397     ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex,
00398                               ace_mon,
00399                               this->lock_,
00400                               -1));
00401 
00402     return_value = find_i (sr->name (), i, &s, false);
00403 
00404     // Adding an entry.
00405     if (s != 0)
00406       {
00407         this->service_vector_[i] = sr;
00408       }
00409     else
00410       {
00411         // New services are always added where current_size_ points,
00412         // because if any DLL relocation needs to happen, it will be
00413         // performed on services with indexes between some old
00414         // current_size_ and the new current_size_ value.  See
00415         // ACE_Service_Type_Dynamic_Guard ctor and dtor for details.
00416 
00417         if (i < this->current_size_)
00418           i = this->current_size_;
00419 
00420         if (i < this->total_size_)
00421           {
00422             this->service_vector_[i] = sr;
00423             this->current_size_++;
00424             return_value = 0;
00425           }
00426         else
00427           {
00428             return_value = -1; // no space left
00429           }
00430 
00431         // Since there may be "holes" left by removed services one
00432         // could consider wrapping current_size_ modulo
00433         // total_size_. This is going to impact
00434         // ACE_Service_Type_Dynamic_Guard, too and is tricky. Perhaps
00435         // a new directive, like "reload" would be better as it can
00436         // combine the removal and insertion in an atomic step and
00437         // avoid creating too many "holes".
00438       }
00439   }
00440 #ifndef ACE_NLOGGING
00441   if (ACE::debug ())
00442     ACE_DEBUG ((LM_DEBUG,
00443                 ACE_TEXT ("ACE (%P|%t) SR::insert - repo=%@ [%d] (%d),")
00444                 ACE_TEXT (" name=%s (%s) (type=%@, object=%@, active=%d)\n"),
00445                 this,
00446                 i,
00447                 this->total_size_,
00448                 sr->name(),
00449                 (return_value == 0 ? ((s==0) ? "new" : "replacing") : "failed"),
00450                 sr->type (),
00451                 (sr->type () != 0) ? sr->type ()->object () : 0,
00452                 sr->active ()));
00453 #endif
00454 
00455   // If necessary, delete but outside the lock. (s may be 0, but
00456   // that's okay, too)
00457   delete s;
00458 
00459   if (return_value == -1)
00460     ACE_OS::last_error (ENOSPC);
00461 
00462   return return_value;
00463 }
00464 
00465 // Resume a service that was previously suspended.
00466 int
00467 ACE_Service_Repository::resume (const ACE_TCHAR name[],
00468                                 const ACE_Service_Type **srp)
00469 {
00470   ACE_TRACE ("ACE_Service_Repository::resume");
00471   ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1));
00472 
00473   size_t i = 0;
00474   if (-1 == this->find_i (name, i, srp, 0))
00475     return -1;
00476 
00477   return this->service_vector_[i]->resume ();
00478 }
00479 
00480 // Suspend a service so that it will not be considered active under
00481 // most circumstances by other portions of the ACE_Service_Repository.
00482 
00483 int
00484 ACE_Service_Repository::suspend (const ACE_TCHAR name[],
00485                                  const ACE_Service_Type **srp)
00486 {
00487   ACE_TRACE ("ACE_Service_Repository::suspend");
00488   ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1));
00489   size_t i = 0;
00490   if (-1 == this->find_i (name, i, srp, 0))
00491     return -1;
00492 
00493   return this->service_vector_[i]->suspend ();
00494 }
00495 
00496 
00497 /**
00498  * @brief Completely remove a <name> entry from the Repository and
00499  * dynamically unlink it if it was originally dynamically linked.
00500  */
00501 
00502 int
00503 ACE_Service_Repository::remove (const ACE_TCHAR name[], ACE_Service_Type **ps)
00504 {
00505   ACE_TRACE ("ACE_Service_Repository::remove");
00506   ACE_Service_Type *s = 0;
00507   {
00508     ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1));
00509 
00510     // Not found!?
00511     if (this->remove_i (name, &s) == -1)
00512       return -1;
00513   }
00514 
00515   if (ps != 0)
00516     *ps = s;
00517   else
00518     delete s;
00519   return 0;
00520 }
00521 
00522 /**
00523  * @brief Completely remove a <name> entry from the Repository and
00524  * dynamically unlink it if it was originally dynamically linked.
00525  *
00526  * Return a ptr to the entry in @code ps. There is no locking so make
00527  * sure you hold the repo lock when calling.
00528  *
00529  * Since the order of services in the Respository matters, we can't
00530  * simply overwrite the entry being deleted with the last and
00531  * decrement the <current_size> by 1.  A good example of why the order
00532  * matters is a dynamic service, in whose DLL there is at least one
00533  * static service. In order to prevent SEGV during finalization, those
00534  * static services must be finalized _before_the dynamic service that
00535  * owns them. Otherwice the TEXT segment, containing the code for the
00536  * static service's desructor may be unloaded with the DLL.
00537  *
00538  * Neither can we "pack" the array because this may happen inside the
00539  * scope of a Service_Dynamic_Guard, which caches an index where
00540  * loading of a DLL started in order to relocate dependent services.
00541  */
00542 int
00543 ACE_Service_Repository::remove_i (const ACE_TCHAR name[], ACE_Service_Type **ps)
00544 {
00545   size_t i = 0;
00546   if (-1 == this->find_i (name, i, 0, false))
00547     return -1;    // Not found
00548 
00549   // We may need the old ptr - to be delete outside the lock!
00550   *ps = const_cast<ACE_Service_Type *> (this->service_vector_[i]);
00551 
00552 #ifndef ACE_NLOGGING
00553   if (ACE::debug ())
00554     ACE_DEBUG ((LM_DEBUG,
00555                 ACE_TEXT ("ACE (%P|%t) SR::remove_i - repo=%@ [%d] (%d),")
00556                 ACE_TEXT (" name=%s (removed) (type=%@, active=%d)\n"),
00557                 this,
00558                 i,
00559                 this->total_size_,
00560                 name,
00561                 *ps,
00562                 (*ps)->active ()));
00563 #endif
00564 
00565   this->service_vector_[i] = 0; // simply leave a gap
00566   return 0;
00567 }
00568 
00569 ACE_ALLOC_HOOK_DEFINE(ACE_Service_Repository_Iterator)
00570 
00571 void
00572 ACE_Service_Repository_Iterator::dump (void) const
00573 {
00574 #if defined (ACE_HAS_DUMP)
00575   ACE_TRACE ("ACE_Service_Repository_Iterator::dump");
00576 #endif /* ACE_HAS_DUMP */
00577 }
00578 
00579 
00580 // Initializes the iterator and skips over any suspended entries at
00581 // the beginning of the table, if necessary.  Note, you must not
00582 // perform destructive operations on elements during this iteration...
00583 
00584 ACE_Service_Repository_Iterator::ACE_Service_Repository_Iterator
00585   (ACE_Service_Repository &sr, int ignr_suspended)
00586   : svc_rep_ (sr),
00587     next_ (0),
00588     ignore_suspended_ (ignr_suspended)
00589 {
00590   while (!(done() || valid()))
00591     this->next_++;
00592 }
00593 
00594 // Obtains a pointer to the next valid service in the table.  If there
00595 // are no more entries, returns 0, else 1.
00596 
00597 int
00598 ACE_Service_Repository_Iterator::next (const ACE_Service_Type *&sr)
00599 {
00600   ACE_TRACE ("ACE_Service_Repository_Iterator::next");
00601 
00602   if (done ())
00603     return 0;
00604 
00605   sr = this->svc_rep_.service_vector_[this->next_];
00606   return 1;
00607 }
00608 
00609 // Advance the iterator by the proper amount.  If we are ignoring
00610 // suspended entries and the current entry is suspended, then we must
00611 // skip over this entry.  Otherwise, we must advance the NEXT index to
00612 // reference the next valid service entry.
00613 
00614 int
00615 ACE_Service_Repository_Iterator::advance (void)
00616 {
00617   ACE_TRACE ("ACE_Service_Repository_Iterator::advance");
00618 
00619   if (done()) return 0;
00620 
00621   do this->next_++; while (!(done () || valid ()));
00622 
00623   return !done();
00624 }
00625 
00626 bool
00627 ACE_Service_Repository_Iterator::valid (void) const
00628 {
00629   ACE_TRACE ("ACE_Service_Repository_Iterator::valid");
00630   if (!this->ignore_suspended_)
00631     return (this->svc_rep_.service_vector_[this->next_] != 0); // skip over gaps
00632 
00633   return (this->svc_rep_.service_vector_[this->next_] != 0
00634           && this->svc_rep_.service_vector_[this->next_]->active ());
00635 }
00636 
00637 ACE_END_VERSIONED_NAMESPACE_DECL

Generated on Tue Feb 2 17:18:42 2010 for ACE by  doxygen 1.4.7