Service_Repository.cpp

Go to the documentation of this file.
00001 // Service_Repository.cpp,v 4.56 2006/05/24 23:22:16 jeliazkov_i Exp
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            "Service_Repository.cpp,v 4.56 2006/05/24 23:22:16 jeliazkov_i Exp")
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   //  ACE_ASSERT (ACE_Service_Repository::svc_rep_ != 0);
00072   return ACE_Service_Repository::svc_rep_;
00073 }
00074 
00075 ACE_Service_Repository *
00076 ACE_Service_Repository::instance (ACE_Service_Repository *s)
00077 {
00078   ACE_TRACE ("ACE_Service_Repository::instance");
00079   ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon,
00080                             *ACE_Static_Object_Lock::instance (), 0));
00081 
00082   ACE_Service_Repository *t = ACE_Service_Repository::svc_rep_;
00083   // We can't safely delete it since we don't know who created it!
00084   ACE_Service_Repository::delete_svc_rep_ = 0;
00085 
00086   ACE_Service_Repository::svc_rep_ = s;
00087   return t;
00088 }
00089 
00090 void
00091 ACE_Service_Repository::close_singleton (void)
00092 {
00093   ACE_TRACE ("ACE_Service_Repository::close_singleton");
00094 
00095   ACE_MT (ACE_GUARD (ACE_Recursive_Thread_Mutex, ace_mon,
00096                      *ACE_Static_Object_Lock::instance ()));
00097 
00098   if (ACE_Service_Repository::delete_svc_rep_)
00099     {
00100       delete ACE_Service_Repository::svc_rep_;
00101       ACE_Service_Repository::svc_rep_ = 0;
00102       ACE_Service_Repository::delete_svc_rep_ = 0;
00103     }
00104 }
00105 
00106 // Initialize the Repository to a clean slate.
00107 
00108 int
00109 ACE_Service_Repository::open (size_t size)
00110 {
00111   ACE_TRACE ("ACE_Service_Repository::open");
00112 
00113   ACE_Service_Type **temp;
00114 
00115   ACE_NEW_RETURN (temp,
00116                   ACE_Service_Type *[size],
00117                   -1);
00118 
00119   this->service_vector_ = const_cast<const ACE_Service_Type **> (temp);
00120   this->total_size_ = size;
00121   return 0;
00122 }
00123 
00124 ACE_Service_Repository::ACE_Service_Repository (size_t size)
00125   : current_size_ (0)
00126 {
00127   ACE_TRACE ("ACE_Service_Repository::ACE_Service_Repository");
00128 
00129   if (this->open (size) == -1)
00130     ACE_ERROR ((LM_ERROR,
00131                 ACE_LIB_TEXT ("%p\n"),
00132                 ACE_LIB_TEXT ("ACE_Service_Repository")));
00133 }
00134 
00135 // Finalize (call <fini> and possibly delete) all the services.
00136 
00137 int
00138 ACE_Service_Repository::fini (void)
00139 {
00140   ACE_TRACE ("ACE_Service_Repository::fini");
00141   ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1));
00142   int retval = 0;
00143 
00144   if (this->service_vector_ != 0)
00145     {
00146       // <fini> the services in reverse order.  Note that if services
00147       // were removed from the middle of the repository the order
00148       // won't necessarily be maintained since the <remove> method
00149       // performs compaction.  However, the common case is not to
00150       // remove services, so typically they are deleted in reverse
00151       // order.
00152 
00153       for (int i = this->current_size_ - 1; i >= 0; i--)
00154   {
00155     ACE_Service_Type *s =
00156       const_cast<ACE_Service_Type *> (this->service_vector_[i]);
00157 
00158     if (ACE::debug ())
00159       {
00160         ACE_DEBUG ((LM_DEBUG,
00161         ACE_LIB_TEXT ("(%P|%t) SR::fini, %@ [%d] (%d): "),
00162         this, i, this->total_size_));
00163         s->dump();
00164       }
00165 
00166     // Collect any errors.
00167     int ret = s->fini ();
00168     if (ACE::debug ()>1)
00169       {
00170         ACE_DEBUG ((LM_DEBUG,
00171         ACE_LIB_TEXT ("(%P|%t) SR::fini, returned %d\n"),
00172         ret));
00173       }
00174     retval += ret;
00175   }
00176     }
00177 
00178   return (retval == 0) ? 0 : -1;
00179 }
00180 
00181 // Close down all the services.
00182 
00183 int
00184 ACE_Service_Repository::close (void)
00185 {
00186   ACE_TRACE ("ACE_Service_Repository::close");
00187   ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1));
00188 
00189   if (this->service_vector_ != 0)
00190     {
00191       // Delete services in reverse order.  Note that if services were
00192       // removed from the middle of the repository the order won't
00193       // necessarily be maintained since the <remove> method performs
00194       // compaction.  However, the common case is not to remove
00195       // services, so typically they are deleted in reverse order.
00196 
00197       if(ACE::debug ())
00198         ACE_DEBUG ((LM_DEBUG,
00199                     ACE_LIB_TEXT ("(%P|%t) SR::close, this=%@, size=%d\n"),
00200                     this,
00201                     this->current_size_));
00202 
00203       for (int i = this->current_size_ - 1; i >= 0; i--)
00204         {
00205           if(ACE::debug ())
00206             ACE_DEBUG ((LM_DEBUG,
00207                         ACE_LIB_TEXT ("(%P|%t) SR::close, this=%@, delete so[%d]=%@ (%s)\n"),
00208                         this,
00209                         i,
00210                         this->service_vector_[i],
00211                         this->service_vector_[i]->name ()));
00212 
00213           ACE_Service_Type *s = const_cast<ACE_Service_Type *> (this->service_vector_[i]);
00214           --this->current_size_;
00215           delete s;
00216         }
00217 
00218       delete [] this->service_vector_;
00219       this->service_vector_ = 0;
00220       this->current_size_ = 0;
00221     }
00222 
00223   return 0;
00224 }
00225 
00226 ACE_Service_Repository::~ACE_Service_Repository (void)
00227 {
00228   ACE_TRACE ("ACE_Service_Repository::~ACE_Service_Repository");
00229   if(ACE::debug ())
00230     ACE_DEBUG ((LM_DEBUG, "(%P|%t) SR::<dtor>, this=%@\n", this));
00231   this->close ();
00232 }
00233 
00234 // Locate an entry with <name> in the table.  If <ignore_suspended> is
00235 // set then only consider services marked as resumed.  If the caller
00236 // wants the located entry, pass back a pointer to the located entry
00237 // via <srp>.  If <name> is not found -1 is returned.  If <name> is
00238 // found, but it is suspended and the caller wants to ignore suspended
00239 // services a -2 is returned.  Must be called with locks held.
00240 
00241 int
00242 ACE_Service_Repository::find_i (const ACE_TCHAR name[],
00243                                 const ACE_Service_Type **srp,
00244                                 int ignore_suspended) const
00245 {
00246   ACE_TRACE ("ACE_Service_Repository::find_i");
00247   size_t i;
00248 
00249   for (i = 0; i < this->current_size_; i++)
00250     if (ACE_OS::strcmp (name,
00251                         this->service_vector_[i]->name ()) == 0)
00252       break;
00253 
00254   if (i < this->current_size_)
00255     {
00256       if (this->service_vector_[i]->fini_called ())
00257         {
00258           if (srp != 0)
00259             *srp = 0;
00260           return -1;
00261         }
00262 
00263       if (srp != 0)
00264         *srp = this->service_vector_[i];
00265       if (ignore_suspended
00266           && this->service_vector_[i]->active () == 0)
00267         return -2;
00268       return i;
00269     }
00270   else
00271     return -1;
00272 }
00273 
00274 int
00275 ACE_Service_Repository::find (const ACE_TCHAR name[],
00276                               const ACE_Service_Type **srp,
00277                               int ignore_suspended) const
00278 {
00279   ACE_TRACE ("ACE_Service_Repository::find");
00280   ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1));
00281 
00282   return this->find_i (name, srp, ignore_suspended);
00283 }
00284 
00285 
00286 // Insert the ACE_Service_Type SR into the repository.  Note that
00287 // services may be inserted either resumed or suspended. Using same name
00288 // as in an existing service causes the delete () to be called for the old one,
00289 // i.e. make sure @code sr is allocated on the heap!
00290 
00291 int
00292 ACE_Service_Repository::insert (const ACE_Service_Type *sr)
00293 {
00294   ACE_TRACE ("ACE_Service_Repository::insert");
00295 
00296   int return_value = -1;
00297   ACE_Service_Type *s = 0;
00298 
00299   {
00300     // @TODO: Do we need a recursive mutex here?
00301     ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1));
00302     size_t i;
00303 
00304     // Check to see if this is a duplicate.
00305     for (i = 0; i < this->current_size_; i++)
00306       if (ACE_OS::strcmp (sr->name (),
00307                           this->service_vector_[i]->name ()) == 0)
00308         break;
00309 
00310     // Replacing an existing entry
00311     if (i < this->current_size_)
00312       {
00313         return_value = 0;
00314         // Check for self-assignment...
00315         if (sr != this->service_vector_[i])
00316           {
00317             s = const_cast<ACE_Service_Type *> (this->service_vector_[i]);
00318             this->service_vector_[i] = sr;
00319           }
00320       }
00321     // Adding a new entry.
00322     else if (i < this->total_size_)
00323       {
00324         this->service_vector_[i] = sr;
00325         this->current_size_++;
00326         return_value = 0;
00327       }
00328 
00329     if (ACE::debug ())
00330       {
00331         ACE_DEBUG ((LM_DEBUG,
00332                     "(%P|%t) SR::insert, repo=%@ [%d] (size=%d): ",
00333                     this,
00334                     i,
00335                     this->total_size_));
00336         sr->dump();
00337       }
00338   }
00339 
00340   // Delete outside the lock
00341   if (s != 0)
00342     {
00343       if (ACE::debug () > 1)
00344         {
00345           ACE_DEBUG ((LM_DEBUG,
00346                       "(%P|%t) SR::insert, repo=%@ - destroying : ",
00347                       this));
00348           s->dump();
00349         }
00350       delete s;
00351     }
00352 
00353   if (return_value == -1)
00354     ACE_OS::last_error (ENOSPC);
00355 
00356   return return_value;
00357 }
00358 
00359 // Re-resume a service that was previously suspended.
00360 
00361 int
00362 ACE_Service_Repository::resume (const ACE_TCHAR name[],
00363                                 const ACE_Service_Type **srp)
00364 {
00365   ACE_TRACE ("ACE_Service_Repository::resume");
00366   ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1));
00367 
00368   int i = this->find_i (name, srp, 0);
00369 
00370   if (i == -1)
00371     return -1;
00372 
00373   return this->service_vector_[i]->resume ();
00374 }
00375 
00376 // Suspend a service so that it will not be considered active under
00377 // most circumstances by other portions of the ACE_Service_Repository.
00378 
00379 int
00380 ACE_Service_Repository::suspend (const ACE_TCHAR name[],
00381                                  const ACE_Service_Type **srp)
00382 {
00383   ACE_TRACE ("ACE_Service_Repository::suspend");
00384   ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1));
00385   int i = this->find_i (name, srp, 0);
00386 
00387   if (i == -1)
00388     return -1;
00389 
00390   return this->service_vector_[i]->suspend ();
00391 }
00392 
00393 
00394 /**
00395  * @brief Completely remove a <name> entry from the Repository and
00396  * dynamically unlink it if it was originally dynamically linked.
00397  *
00398  * Since the order of services in the Respository matters, we can't
00399  * simply overwrite the entry being deleted with the last and
00400  * decrement the <current_size> by 1 - we must "pack" the array.  A
00401  * good example of why the order matters is a dynamic service, in
00402  * whose DLL there is at least one static service. In order to prevent
00403  * SEGV during finalization, those static services must be finalized
00404  * _before_the dynamic service that owns them. Otherwice the TEXT
00405  * segment, containing the code for the static service's desructor may
00406  * be unloaded with the DLL.
00407  */
00408 
00409 int
00410 ACE_Service_Repository::remove (const ACE_TCHAR name[], ACE_Service_Type **ps)
00411 {
00412   ACE_TRACE ("ACE_Service_Repository::remove");
00413   ACE_Service_Type *s = 0;
00414   {
00415     ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1));
00416     int i = this->find_i (name, 0, 0);
00417 
00418     // Not found
00419     if (i == -1)
00420       return -1;
00421 
00422     // We need the old ptr to be delete outside the lock
00423     s = const_cast<ACE_Service_Type *> (this->service_vector_[i]);
00424 
00425     // Pack the array
00426     --this->current_size_;
00427     for (size_t j = i; j < this->current_size_; j++)
00428       this->service_vector_[j] = this->service_vector_[j+1];
00429   }
00430 
00431   if (ps != 0)
00432     *ps = s;
00433   else
00434     delete s;
00435   return 0;
00436 }
00437 
00438 ACE_ALLOC_HOOK_DEFINE(ACE_Service_Repository_Iterator)
00439 
00440 void
00441 ACE_Service_Repository_Iterator::dump (void) const
00442 {
00443 #if defined (ACE_HAS_DUMP)
00444   ACE_TRACE ("ACE_Service_Repository_Iterator::dump");
00445 #endif /* ACE_HAS_DUMP */
00446 }
00447 
00448 // Initializes the iterator and skips over any suspended entries at
00449 // the beginning of the table, if necessary.  Note, you must not
00450 // perform destructive operations on elements during this iteration...
00451 
00452 ACE_Service_Repository_Iterator::ACE_Service_Repository_Iterator
00453   (ACE_Service_Repository &sr, int ignr_suspended)
00454   : svc_rep_ (sr),
00455     next_ (0),
00456     ignore_suspended_ (ignr_suspended)
00457 {
00458   while (!(done() || valid()))
00459     this->next_++;
00460 }
00461 
00462 // Obtains a pointer to the next valid service in the table.  If there
00463 // are no more entries, returns 0, else 1.
00464 
00465 int
00466 ACE_Service_Repository_Iterator::next (const ACE_Service_Type *&sr)
00467 {
00468   ACE_TRACE ("ACE_Service_Repository_Iterator::next");
00469 
00470   if (done ())
00471     return 0;
00472 
00473   sr = this->svc_rep_.service_vector_[this->next_];
00474   return 1;
00475 }
00476 
00477 // Advance the iterator by the proper amount.  If we are ignoring
00478 // suspended entries and the current entry is suspended, then we must
00479 // skip over this entry.  Otherwise, we must advance the NEXT index to
00480 // reference the next valid service entry.
00481 
00482 int
00483 ACE_Service_Repository_Iterator::advance (void)
00484 {
00485   ACE_TRACE ("ACE_Service_Repository_Iterator::advance");
00486 
00487   if (done()) return 0;
00488 
00489   do this->next_++; while (!(done () || valid ()));
00490 
00491   return !done();
00492 }
00493 
00494 bool
00495 ACE_Service_Repository_Iterator::valid (void) const
00496 {
00497   ACE_TRACE ("ACE_Service_Repository_Iterator::valid");
00498   return (this->ignore_suspended_ == 0
00499           || this->svc_rep_.service_vector_[this->next_]->active ());
00500 }
00501 
00502 ACE_END_VERSIONED_NAMESPACE_DECL

Generated on Thu Nov 9 09:42:03 2006 for ACE by doxygen 1.3.6