diff options
Diffstat (limited to 'ACE')
-rw-r--r-- | ACE/ChangeLog | 69 | ||||
-rw-r--r-- | ACE/ace/DLL.cpp | 32 | ||||
-rw-r--r-- | ACE/ace/DLL.h | 5 | ||||
-rw-r--r-- | ACE/ace/DLL_Manager.cpp | 18 | ||||
-rw-r--r-- | ACE/ace/Parse_Node.cpp | 20 | ||||
-rw-r--r-- | ACE/ace/Parse_Node.h | 6 | ||||
-rw-r--r-- | ACE/ace/Service_Gestalt.cpp | 253 | ||||
-rw-r--r-- | ACE/ace/Service_Gestalt.h | 57 | ||||
-rw-r--r-- | ACE/ace/Service_Object.cpp | 25 | ||||
-rw-r--r-- | ACE/ace/Service_Object.h | 9 | ||||
-rw-r--r-- | ACE/ace/Service_Object.inl | 3 | ||||
-rw-r--r-- | ACE/ace/Service_Repository.cpp | 90 | ||||
-rw-r--r-- | ACE/ace/Service_Repository.h | 4 | ||||
-rw-r--r-- | ACE/tests/Service_Config_Test.cpp | 16 |
14 files changed, 431 insertions, 176 deletions
diff --git a/ACE/ChangeLog b/ACE/ChangeLog index fbb28011603..fb6f4e45a4b 100644 --- a/ACE/ChangeLog +++ b/ACE/ChangeLog @@ -1,3 +1,72 @@ +Tue Aug 22 21:43:34 UTC 2006 Iliyan Jeliazkov <iliyan@ociweb.com> + + This change fixes bug#2612. + + * ace/DLL.h: + * ace/DLL.cpp: + + Made assignment return 'T&' instead of 'const T&'. Adjusted code + formatting and logging messages. + + * ace/DLL_Manager.cpp: + + Fixed formatting. + + * ace/Parse_Node.h: + * ace/Parse_Node.cpp: + + Added accessor for the underlying ACE_DLL and adjusted logging. + + * ace/Service_Gestalt.h: + * ace/Service_Gestalt.cpp: + + Introduced ACE_Service_Type_DLL_Guard class. As dynamic service + objects are loaded, static service objects that come with the + same DLL code, may also be registered. The static services + however, have no information about the context in which their + registration takes place and their relation with the DLL is + lost. A situation can easily arise where the dynamic service + object is finalized and its DLL - unmapped, but some of the + DLL's static services may still be around. Their finalization + would not be possible, if the DLL counting that code is gone. + + The guard, when instantiated (on the stack) swaps out the + current Gestalt and its service repository, and replaces them + with a "sandbox" Gestalt, which has lifetime sufficient for just + the current service initialization. Note that this mechanism is + effective even in the case where a service initialization causes + re-entry into the Gestalt to load and initialize another service + as part of the initialization. + + If no action is taken (in case of an error, for instance) the + guard destructor will simply finalize all newly initialized + service(s) from the sandbox. On the other hand, if + initialization is successful the service object descriptors are + "relocated" to the original Gestalt. + + During the relocation, all static services are "fixed-up" to + hold a reference to the DLL they belong to. Effectively, a + static service, initialized via loading of a particular DLL, + becomes a dynamic service. Thus the order of service + finalization does not matter anymore because the DLL will be + help in memory until the last service object it provides is + finalized. + + * ace/Service_Object.h: + * ace/Service_Object.inl: + * ace/Service_Object.cpp: + + Added a relocate method to modify the ACE_DLL each SO has. + + * ace/Service_Repository.h: + * ace/Service_Repository.cpp: + + Befrended ACE_Service_Type_DLL_Guard. Adjusted logging. + + * tests/Service_Config_Test.cpp: + + Simplified test case. + Tue Aug 22 18:37:48 UTC 2006 Phil Mesnier <mesnier_p@ociweb.com> * bin/MakeProjectCreator/config/ipv6.mpb: diff --git a/ACE/ace/DLL.cpp b/ACE/ace/DLL.cpp index 2d034635ac2..5f1163db393 100644 --- a/ACE/ace/DLL.cpp +++ b/ACE/ace/DLL.cpp @@ -42,13 +42,14 @@ ACE_DLL::ACE_DLL (const ACE_DLL &rhs) rhs.close_handle_on_destruction_) != 0 && ACE::debug ()) ACE_ERROR ((LM_ERROR, - ACE_LIB_TEXT ("ACE_DLL::copy_ctor: error: %s\n"), - this->error ())); + ACE_LIB_TEXT ("ACE_DLL::copy_ctor: error: %s\n"), + this->error ())); + } // Assignment operator -const ACE_DLL & +ACE_DLL & ACE_DLL::operator= (const ACE_DLL &rhs) { ACE_TRACE ("ACE_DLL::operator= (const ACE_DLL &)"); @@ -66,8 +67,8 @@ ACE_DLL::operator= (const ACE_DLL &rhs) rhs.close_handle_on_destruction_) != 0 && ACE::debug ()) ACE_ERROR ((LM_ERROR, - ACE_LIB_TEXT ("ACE_DLL::operator=: error: %s\n"), - this->error ())); + ACE_LIB_TEXT ("ACE_DLL::operator=: error: %s\n"), + this->error ())); return *this; } @@ -143,14 +144,7 @@ ACE_DLL::open_i (const ACE_TCHAR *dll_filename, this->error_ = 0; if (!dll_filename) - { - if (ACE::debug ()) - ACE_ERROR ((LM_ERROR, - ACE_LIB_TEXT ("ACE_DLL::open_i: dll_name is %s\n"), - this->dll_name_ == 0 ? ACE_LIB_TEXT ("(null)") - : this->dll_name_)); return -1; - } if (this->dll_handle_) { @@ -167,9 +161,17 @@ ACE_DLL::open_i (const ACE_TCHAR *dll_filename, this->open_mode_ = open_mode; this->close_handle_on_destruction_ = close_handle_on_destruction; - this->dll_handle_ = ACE_DLL_Manager::instance()->open_dll (this->dll_name_, - this->open_mode_, - handle); + if (ACE::debug ()) + ACE_DEBUG ((LM_DEBUG, + ACE_LIB_TEXT ("ACE_DLL::open_i: dll_name is %s\n"), + this->dll_name_ == 0 + ? ACE_LIB_TEXT ("(null)") + : this->dll_name_)); + + this->dll_handle_ = + ACE_DLL_Manager::instance()->open_dll (this->dll_name_, + this->open_mode_, + handle); if (!this->dll_handle_) this->error_ = 1; diff --git a/ACE/ace/DLL.h b/ACE/ace/DLL.h index 306b77635a4..75acb451d3e 100644 --- a/ACE/ace/DLL.h +++ b/ACE/ace/DLL.h @@ -57,7 +57,7 @@ public: explicit ACE_DLL (int close_handle_on_destruction = 1); /// Allow assignment - const ACE_DLL& operator= (const ACE_DLL &rhs); + ACE_DLL& operator= (const ACE_DLL &rhs); /** @@ -168,8 +168,7 @@ private: ACE_SHLIB_HANDLE handle = 0); - //private: -public: +private: /// Open mode. int open_mode_; diff --git a/ACE/ace/DLL_Manager.cpp b/ACE/ace/DLL_Manager.cpp index b796c4b6e55..ca4e6e4a462 100644 --- a/ACE/ace/DLL_Manager.cpp +++ b/ACE/ace/DLL_Manager.cpp @@ -552,32 +552,32 @@ ACE_DLL_Manager::open_dll (const ACE_TCHAR *dll_name, ACE_DLL_Handle, 0); - dll_handle = temp_handle; + dll_handle = temp_handle; } } if (dll_handle) { - if (dll_handle->open (dll_name, open_mode, handle) != 0) - { - // Error while openind dll. Free temp handle + if (dll_handle->open (dll_name, open_mode, handle) != 0) + { + // Error while openind dll. Free temp handle if (ACE::debug ()) ACE_ERROR ((LM_ERROR, - ACE_LIB_TEXT ("ACE_DLL_Manager::open_dll: Could not ") + ACE_LIB_TEXT ("ACE (%P|%t) DLL_Manager::open_dll: Could not ") ACE_LIB_TEXT ("open dll %s.\n"), dll_name)); - delete temp_handle; + delete temp_handle; return 0; } // Add the handle to the vector only if the dll is successfully // opened. if (temp_handle != NULL) - { - this->handle_vector_[this->current_size_] = dll_handle; + { + this->handle_vector_[this->current_size_] = dll_handle; this->current_size_++; - } + } } return dll_handle; diff --git a/ACE/ace/Parse_Node.cpp b/ACE/ace/Parse_Node.cpp index c3b194499d4..eb4287a7fda 100644 --- a/ACE/ace/Parse_Node.cpp +++ b/ACE/ace/Parse_Node.cpp @@ -267,11 +267,12 @@ ACE_Dynamic_Node::apply (ACE_Service_Gestalt *config, int &yyerrno) #ifndef ACE_NLOGGING if (ACE::debug ()) ACE_DEBUG ((LM_DEBUG, - ACE_LIB_TEXT ("(%P|%t) ACE_Dynamic_Node::apply") + ACE_LIB_TEXT ("ACE (%P|%t) Dynamic_Node::apply") ACE_LIB_TEXT (" - did dynamic on %s, error = %d\n"), this->name (), yyerrno)); #endif /* ACE_NLOGGING */ + } ACE_ALLOC_HOOK_DEFINE (ACE_Dynamic_Node) @@ -374,8 +375,9 @@ ACE_Location_Node::~ACE_Location_Node (void) } const ACE_DLL & -ACE_Location_Node::dll (void) +ACE_Location_Node::dll (void) const { + ACE_TRACE ("ACE_Location_Node::dll"); return this->dll_; } @@ -405,13 +407,6 @@ ACE_Location_Node::open_dll (int & yyerrno) { ACE_TRACE ("ACE_Location_Node::open_dll"); -#ifndef ACE_NLOGGING - if (ACE::debug ()) - ACE_DEBUG ((LM_DEBUG, - ACE_LIB_TEXT ("(%P|%t) LN::open_dll - path=%s\n"), - this->pathname ())); -#endif /* ACE_NLOGGING */ - if (-1 == this->dll_.open (this->pathname ())) { ++yyerrno; @@ -775,6 +770,13 @@ ACE_Service_Type_Factory::~ACE_Service_Type_Factory (void) } +const ACE_DLL& +ACE_Service_Type_Factory::dll (void) const +{ + return this->location_->dll(); +} + + ACE_Service_Type * ACE_Service_Type_Factory::make_service_type (ACE_Service_Gestalt *cfg) const { diff --git a/ACE/ace/Parse_Node.h b/ACE/ace/Parse_Node.h index bb456240315..c58eb4a4c79 100644 --- a/ACE/ace/Parse_Node.h +++ b/ACE/ace/Parse_Node.h @@ -309,7 +309,7 @@ class ACE_Location_Node { public: ACE_Location_Node (void); - const ACE_DLL &dll (void); + const ACE_DLL& dll (void) const; const ACE_TCHAR *pathname (void) const; void pathname (const ACE_TCHAR *h); int dispose (void) const; @@ -491,7 +491,9 @@ public: ACE_Service_Type *make_service_type (ACE_Service_Gestalt *pcfg) const; - ACE_TCHAR const* name (void) const; + const ACE_TCHAR * name (void) const; + + const ACE_DLL& dll (void) const; /// Declare the dynamic allocation hooks. ACE_ALLOC_HOOK_DECLARE; diff --git a/ACE/ace/Service_Gestalt.cpp b/ACE/ace/Service_Gestalt.cpp index 2c8a83f3114..dabd419e56a 100644 --- a/ACE/ace/Service_Gestalt.cpp +++ b/ACE/ace/Service_Gestalt.cpp @@ -171,6 +171,8 @@ ACE_Service_Type_Forward_Declaration_Guard::~ACE_Service_Type_Forward_Declaratio + + // ---------------------------------------- ACE_Service_Gestalt::Processed_Static_Svc:: @@ -180,23 +182,124 @@ Processed_Static_Svc (const ACE_Static_Svc_Descriptor *assd) { ACE_NEW_NORETURN (name_, ACE_TCHAR[ACE_OS::strlen(assd->name_)+1]); ACE_OS::strcpy(name_,assd->name_); -// if (ACE::debug ()) -// ACE_DEBUG ((LM_DEBUG, -// ACE_LIB_TEXT ("ACE (%P|%t) PSS::ctor - name = %s\n"), -// name_)); } ACE_Service_Gestalt::Processed_Static_Svc:: ~Processed_Static_Svc (void) { -// if (ACE::debug ()) -// ACE_DEBUG ((LM_DEBUG, -// ACE_LIB_TEXT ("ACE (%P|%t) PSS::dtor - name = %s\n"), -// name_)); - delete [] name_; } +ACE_Service_Type_DLL_Guard::ACE_Service_Type_DLL_Guard (ACE_Service_Gestalt* gestalt) + : gestalt_ (gestalt) + , repo_ (gestalt->repo_) + , processed_static_svcs_ (gestalt->processed_static_svcs_) + { + ACE_NEW_NORETURN (this->gestalt_->repo_, + ACE_Service_Repository (128)); + + if (this->processed_static_svcs_ == 0) + ACE_NEW_NORETURN (this->processed_static_svcs_, + ACE_Service_Gestalt::ACE_PROCESSED_STATIC_SVCS); + + this->gestalt_->processed_static_svcs_ = 0; +} + + +int +ACE_Service_Type_DLL_Guard::relocate (const ACE_DLL& adll) +{ + ACE_Service_Repository* target = this->repo_; + ACE_Service_Repository* source = this->gestalt_->repo_; + + if (ACE::debug ()) + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("ACE (%P|%t) Service_Type_DLL_Guard::relocate, %d services from %@ to repo=%@\n"), + source->current_size_, + source, + target)); + + // First associate any static service types with the DLL, because if + // any of them have to destroyed (in our dtor) it needs to happen + // safely, by properly reference counting the DLL. We don't want the + // DLL to get unmapped before finalizing all its services, remember? + for (size_t i = 0; i < source->current_size_; i++) + { + if (source->service_vector_[i]->dll ().get_handle (0) == 0) + { + ACE_Service_Type* ast = + const_cast<ACE_Service_Type*> (source->service_vector_[i]); + + ast->relocate (adll); + + if (ACE::debug ()) + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("ACE (%P|%t) Service_Type_DLL_Guard::relocate, service=%s (%@) to repo=%@\n"), + ast->name (), + ast, + target)); + } + } + + // Checking for enough size in the "real" repo + if (target->total_size_ < source->current_size_ + target->current_size_) + { + errno = ENOMEM; + return -1; // Not enough memory for the new services. The + // locally loaded services will be safely destroyed + // by the dtor + } + + // The recipient's size is sufficient, so we can relocate all local + // services to their final repo. + for (size_t i = 0; i < source->current_size_; i++) + { + target->insert (source->service_vector_[i]); + source->service_vector_[i] = 0; + } + source->current_size_ = 0; + + + // Do relocate any of the "processed static" services, too. These, I + // guess are copies of non-local services, i.e. services loaded in + // the global repository, but referenced and having a different + // instance locally. + if (this->gestalt_->processed_static_svcs_ != 0 + && !this->gestalt_->processed_static_svcs_->is_empty()) + { + ACE_Service_Gestalt::Processed_Static_Svc **pss = 0; + for (ACE_Service_Gestalt::ACE_PROCESSED_STATIC_SVCS_ITERATOR + iter (*this->gestalt_->processed_static_svcs_); + iter.next (pss) != 0; + iter.advance ()) + { + ACE_Service_Gestalt::Processed_Static_Svc *tmp = 0; + ACE_NEW_RETURN (tmp, + ACE_Service_Gestalt::Processed_Static_Svc((*pss)->assd_), + -1); + this->processed_static_svcs_->insert(tmp); + + delete *pss; + *pss = 0; + } + } + + return 0; +} + +ACE_Service_Type_DLL_Guard::~ACE_Service_Type_DLL_Guard (void) +{ + ACE_Service_Repository* tmp1 (this->gestalt_->repo_); + ACE_Service_Gestalt::ACE_PROCESSED_STATIC_SVCS* tmp2 (this->gestalt_->processed_static_svcs_); + + this->gestalt_->repo_ = this->repo_; + this->gestalt_->processed_static_svcs_ = this->processed_static_svcs_; + + delete tmp1; + delete tmp2; +} + + // ---------------------------------------- ACE_Service_Gestalt::~ACE_Service_Gestalt (void) @@ -388,7 +491,14 @@ ACE_Service_Gestalt::dump (void) const -/// +/// (Statically) initialize a service object. Locates the service +/// object's registration record, identified by svc_name and +/// initializes it, using the supplied command line parameters. Own +/// repository is searched first and if the service is located it is +/// initializaed and activated. The "processed" services descriptors +/// from the global repository are looked up otherwice, and if one is +/// found it is duplicated locally. The initialization and activatin +/// then proceeds as described above. int ACE_Service_Gestalt::initialize (const ACE_TCHAR *svc_name, @@ -411,7 +521,6 @@ ACE_Service_Gestalt::initialize (const ACE_TCHAR *svc_name, const ACE_Service_Type *srp = 0; for (int i = 0; this->repo_->find (svc_name, &srp) == -1 && i < 2; i++) - // if (this->repo_->find (svc_name, &srp) == -1) { const ACE_Static_Svc_Descriptor *assd = ACE_Service_Config::global()->find_processed_static_svc(svc_name); @@ -481,12 +590,12 @@ ACE_Service_Gestalt::initialize (const ACE_Service_Type_Factory *stf, #ifndef ACE_NLOGGING if (ACE::debug ()) ACE_ERROR_RETURN ((LM_WARNING, - ACE_LIB_TEXT ("ACE (%P|%t) \'%s\' already installed.") + ACE_LIB_TEXT ("ACE (%P|%t) SG::initialze - \'%s\' already installed.") ACE_LIB_TEXT (" Must be removed before re-installing\n"), stf->name ()), 0); #endif - return 0; + return 0; } // There is an inactive service by that name, so it may have been @@ -499,35 +608,57 @@ ACE_Service_Gestalt::initialize (const ACE_Service_Type_Factory *stf, // use case must be handled here, because if the DLL_Manager was // re-entrant we would have entered an infinite recursion here. if (retv == -2 && srp->type () == 0) - ACE_ERROR_RETURN ((LM_WARNING, - ACE_LIB_TEXT ("ACE (%P|%t) \'%s\' has not been ") - ACE_LIB_TEXT ("completely defined. Recursive ") - ACE_LIB_TEXT ("initialization request while ") - ACE_LIB_TEXT ("already performing one.\n"), - stf->name ()), - -1); + { +#ifndef ACE_NLOGGING + if (ACE::debug ()) + ACE_ERROR ((LM_WARNING, + ACE_LIB_TEXT ("ACE (%P|%t) SG::initialize - \'%s\' has not been ") + ACE_LIB_TEXT ("completely defined. Recursive ") + ACE_LIB_TEXT ("initialization request while ") + ACE_LIB_TEXT ("already performing one.\n"), + stf->name ())); + return -1; +#endif + } - // Reserve a spot for the dynamic service by inserting an incomplete - // service declaration, i.e. one that can not produce a service - // object if asked. Having this incomplete declaration works - // similar to C++'s forward declaration to allow, in this case - // proper partial ordering of the loaded services in respect to - // their finalization. I.e. dependent static services must be - // registered *after* the dynamic service that loads them, so that - // their finalization is complete *before* finalizing the dynamic - // service. - ACE_Service_Type_Forward_Declaration_Guard dummy (this->repo_, - stf->name ()); + // Use a temporary repository to "capture" any static services, that + // may be loaded with (as part of) the dynamic service. The process + // works by assigning the same ACE_DLL to all captured + // services. Thus all of them must be finalized to be able to unload + // the dll from memory. Also, the order of finalization among these + // becomes irrelevant, instead of scheming to make sure the dynamic + // service is destroyed last. + ACE_Service_Type_DLL_Guard guard (this); // make_service_type() is doing the dynamic loading and also runs - // any static initializers - ACE_Auto_Ptr<ACE_Service_Type> tmp (stf->make_service_type (this)); - if (tmp.get () != 0 && - this->initialize_i (tmp.get (), parameters) == 0) + // any static initializer code from the new DLL - this is how any + // static services will get registered. + ACE_Auto_Ptr <ACE_Service_Type> tmp (stf->make_service_type (this)); + if (tmp.get () != 0 + && this->initialize_i (tmp.get (), parameters) == 0) { - // All good the ACE_Service_Type instance is now owned by the repository - // and we should make sure it is not destroyed upon exit from this method. + // Try to relocate all SO instances from the sandbox repository + const ACE_DLL& relocation_target = tmp->dll (); + + // initialize_i() inserts the ST instance in the gestalt's + // repository, so the auto_ptr can now safely give up the + // ownership (note: zeroes out the pointer it contained) (void)tmp.release (); + + if (guard.relocate (relocation_target) != 0) + { + // The ST which we dis-owned above will be correctly + // destroyed by the ~ACE_Service_Type_DLL_Guard. +#ifndef ACE_NLOGGING + if (ACE::debug ()) + ACE_ERROR ((LM_ERROR, + ACE_LIB_TEXT ("ACE (%P|%t) SG::initialize - Error") + ACE_LIB_TEXT (" relocating static services for %s: %m\n"), + stf->name ())); +#endif + return -1; + } + return 0; } @@ -535,7 +666,7 @@ ACE_Service_Gestalt::initialize (const ACE_Service_Type_Factory *stf, #ifndef ACE_NLOGGING if (ACE::debug ()) ACE_ERROR_RETURN ((LM_ERROR, - ACE_LIB_TEXT ("ACE (%P|%t) Error initializing %s: %m\n"), + ACE_LIB_TEXT ("ACE (%P|%t) SG::initialize - %s failed: %m\n"), stf->name()), -1); #endif @@ -562,21 +693,28 @@ ACE_Service_Gestalt::initialize (const ACE_Service_Type *sr, { ACE_TRACE ("ACE_Service_Gestalt::initialize"); +#ifndef ACE_NLOGGING if (ACE::debug ()) ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("ACE (%P|%t) SG::initialize - looking up dynamic ") ACE_LIB_TEXT (" service \'%s\' to initialize\n"), sr->name ())); +#endif ACE_Service_Type *srp = 0; if (this->repo_->find (sr->name (), (const ACE_Service_Type **) &srp) >= 0) - ACE_ERROR_RETURN ((LM_WARNING, - ACE_LIB_TEXT ("ACE (%P|%t) SG::initialize - \'%s\' ") - ACE_LIB_TEXT ("has already been installed. ") - ACE_LIB_TEXT ("Remove before reinstalling\n"), - sr->name ()), - 0); + { +#ifndef ACE_NLOGGING + if (ACE::debug ()) + ACE_ERROR ((LM_WARNING, + ACE_LIB_TEXT ("ACE (%P|%t) SG::initialize - \'%s\' ") + ACE_LIB_TEXT ("has already been installed. ") + ACE_LIB_TEXT ("Remove before reinstalling\n"), + sr->name ())); +#endif + return 0; + } return this->initialize_i (sr, parameters); @@ -674,18 +812,8 @@ ACE_Service_Gestalt::process_directive (const ACE_Static_Svc_Descriptor &ssd, int ACE_Service_Gestalt::process_directive_i (const ACE_Static_Svc_Descriptor &ssd, - int force_replace) + int force_replace) { -#ifndef ACE_NLOGGING - if (ACE::debug ()) - ACE_DEBUG ((LM_DEBUG, - ACE_LIB_TEXT ("ACE (%P|%t) SG::process_directive, ") - ACE_LIB_TEXT ("repo=%@, replace=%d - %s\n"), - this->repo_, - force_replace, - ssd.name_)); -#endif - if (!force_replace) { if (this->repo_->find (ssd.name_, 0, 0) >= 0) @@ -695,6 +823,16 @@ ACE_Service_Gestalt::process_directive_i (const ACE_Static_Svc_Descriptor &ssd, } } +#ifndef ACE_NLOGGING + if (ACE::debug ()) + ACE_DEBUG ((LM_DEBUG, + ACE_LIB_TEXT ("ACE (%P|%t) SG::process_directive_i, ") + ACE_LIB_TEXT ("repo=%@, replace=%d - %s\n"), + this->repo_, + force_replace, + ssd.name_)); +#endif + ACE_Service_Object_Exterminator gobbler; void *sym = (ssd.alloc_)(&gobbler); @@ -724,6 +862,8 @@ ACE_Service_Gestalt::process_directive_i (const ACE_Static_Svc_Descriptor &ssd, return this->repo_->insert (service_type); } + + #if (ACE_USES_CLASSIC_SVC_CONF == 1) int @@ -820,9 +960,6 @@ ACE_Service_Gestalt::process_file (const ACE_TCHAR file[]) // The entry will be automaticaly removed once the thread exits this block. ACE_Service_Type_Forward_Declaration_Guard recursion_guard (this->repo_, file); - /* - * @TODO: Test with ACE_USES_CLASSIC_SVC_CONF turned off! - */ #if (ACE_USES_CLASSIC_SVC_CONF == 1) int result = 0; diff --git a/ACE/ace/Service_Gestalt.h b/ACE/ace/Service_Gestalt.h index 1476020fe38..95575a4e74d 100644 --- a/ACE/ace/Service_Gestalt.h +++ b/ACE/ace/Service_Gestalt.h @@ -29,6 +29,7 @@ #include "ace/Singleton.h" #include "ace/OS_NS_signal.h" #include "ace/Synch_Traits.h" +#include "ace/DLL.h" ACE_BEGIN_VERSIONED_NAMESPACE_DECL @@ -71,8 +72,8 @@ private: /** * Not implemented to enforce no copying */ - ACE_UNIMPLEMENTED_FUNC (ACE_Service_Gestalt(const ACE_Service_Gestalt&)) - ACE_UNIMPLEMENTED_FUNC (ACE_Service_Gestalt& operator=(const ACE_Service_Gestalt&)) + ACE_Service_Gestalt(const ACE_Service_Gestalt&); + ACE_Service_Gestalt& operator=(const ACE_Service_Gestalt&); public: enum @@ -436,8 +437,60 @@ protected: /// the static_svcs_ list. ACE_PROCESSED_STATIC_SVCS* processed_static_svcs_; +private: + + friend class ACE_Service_Type_DLL_Guard; + }; /* class ACE_Service_Gestalt */ +/** + * As dynamic service objects are loaded, static service objects that + * come with the same DLL code, may also be registered. The static + * services however, have no information about the context in which + * their registration takes place and their relation with the DLL is + * lost. A situation can easily arise where the dynamic service object + * is finalized and its DLL - unmapped, but some of the DLL's static + * services may still be around. Their finalization would not be + * possible, if the DLL counting that code is gone. + * + * The guard, when instantiated (on the stack) swaps out the current + * Gestalt and its service repository, and replaces them with a + * "sandbox" Gestalt, which has lifetime sufficient for just the + * current service initialization. Note that this mechanism is + * effective even in the case where a service initialization causes + * re-entry into the Gestalt to load and initialize another service as + * part of the initialization. + * + * If no action is taken (in case of an error, for instance) the guard + * destructor will simply finalize all newly initialized service(s) + * from the sandbox. On the other hand, if initialization is + * successful the service object descriptors are "relocated" to the + * original Gestalt. **During the relocation, all static services are + * "fixed-up" to hold a reference to the DLL they belong + * to. Effectively, a static service, initialized via loading of a + * particular DLL, becomes a dynamic service. Thus the order of + * service finalization does not matter anymore because the DLL will + * be help in memory until the last service object it provides is + * finalized. + */ +class ACE_Service_Type_DLL_Guard +{ +public: + ACE_Service_Type_DLL_Guard (ACE_Service_Gestalt* gestalt); + ~ACE_Service_Type_DLL_Guard (void); + int relocate (const ACE_DLL& adll); + +protected: + // Unimplemented copy ctor and assigment to prohibit instance + // copying. + ACE_Service_Type_DLL_Guard (const ACE_Service_Type_DLL_Guard&); + ACE_Service_Type_DLL_Guard& operator= (const ACE_Service_Type_DLL_Guard&); + +private: + ACE_Service_Gestalt* gestalt_; + ACE_Service_Repository* repo_; + ACE_Service_Gestalt::ACE_PROCESSED_STATIC_SVCS* processed_static_svcs_; +}; ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/ACE/ace/Service_Object.cpp b/ACE/ace/Service_Object.cpp index 8590d63bc31..c1534dc5b7b 100644 --- a/ACE/ace/Service_Object.cpp +++ b/ACE/ace/Service_Object.cpp @@ -33,18 +33,6 @@ ACE_Service_Type::dump (void) const #endif /* ACE_HAS_DUMP */ - // Using printf, since the log facility may not have been - // initialized yet. Using a "//" prefix, in case the executable - // happens to be a code generator and the output gets embedded in - // the generated C++ code. - ACE_OS::fprintf(stderr, - "// [ST] dump, this=%p, name=%s, type=%p, so=%p, active=%d\n", - this, - this->name_, - this->type_, - (this->type_ != 0) ? this->type_->object () : 0, - this->active_); - } ACE_Service_Type::ACE_Service_Type (const ACE_TCHAR *n, @@ -91,7 +79,7 @@ ACE_Service_Type::fini (void) { this->fini_already_called_ = 1; if (this->type_ != 0) - return this->type_->fini (); + return this->type_->fini (); else return 1; // No implementation was found. // Currently only makes sense for dummy ST, used to "reserve" @@ -119,6 +107,17 @@ ACE_Service_Type::resume (void) const return this->type_->resume (); } +/// Replace with a specific dll. Will only succeed (return 0) if the +/// instance is not associated with a DLL already. Primary use of +/// this method is to associate static service object with the DLL +/// that contains their destruction/finalization code. +void +ACE_Service_Type::relocate (const ACE_DLL & adll) +{ + this->dll_ = adll; +} + + ACE_Service_Object::ACE_Service_Object (ACE_Reactor *r) : ACE_Event_Handler (r) { diff --git a/ACE/ace/Service_Object.h b/ACE/ace/Service_Object.h index 027e217bde7..20310cde6e7 100644 --- a/ACE/ace/Service_Object.h +++ b/ACE/ace/Service_Object.h @@ -128,6 +128,10 @@ public: /// Get to the DLL's implentation const ACE_DLL & dll () const; + /// Use to associate static service object with the DLL that + /// contains their destruction/finalization code. + void relocate (const ACE_DLL &); + /// Declare the dynamic allocation hooks. ACE_ALLOC_HOOK_DECLARE; @@ -139,8 +143,9 @@ private: const ACE_Service_Type_Impl *type_; /// ACE_DLL representing the shared object file (non-zero if - /// dynamically linked). - mutable ACE_DLL dll_; + /// dynamically linked or loaded as part of another dynamically + /// linked service). + ACE_DLL dll_; /// 1 if svc is currently active, otherwise 0. int active_; diff --git a/ACE/ace/Service_Object.inl b/ACE/ace/Service_Object.inl index a675d4e942b..6740630be70 100644 --- a/ACE/ace/Service_Object.inl +++ b/ACE/ace/Service_Object.inl @@ -63,7 +63,8 @@ ACE_Service_Type::fini_called (void) const return this->fini_already_called_; } -ACE_INLINE const ACE_DLL & ACE_Service_Type::dll () const +ACE_INLINE const ACE_DLL & +ACE_Service_Type::dll () const { return this->dll_; } diff --git a/ACE/ace/Service_Repository.cpp b/ACE/ace/Service_Repository.cpp index c05e08f33af..50af9d26625 100644 --- a/ACE/ace/Service_Repository.cpp +++ b/ACE/ace/Service_Repository.cpp @@ -151,28 +151,21 @@ ACE_Service_Repository::fini (void) // order. for (int i = this->current_size_ - 1; i >= 0; i--) - { - ACE_Service_Type *s = - const_cast<ACE_Service_Type *> (this->service_vector_[i]); - - if (ACE::debug ()) - { - ACE_DEBUG ((LM_DEBUG, - ACE_LIB_TEXT ("(%P|%t) SR::fini, %@ [%d] (%d): "), - this, i, this->total_size_)); - s->dump(); - } + { + ACE_Service_Type *s = + const_cast<ACE_Service_Type *> (this->service_vector_[i]); - // Collect any errors. - int ret = s->fini (); - if (ACE::debug ()) - { - ACE_DEBUG ((LM_DEBUG, - ACE_LIB_TEXT ("(%P|%t) SR::fini, returned %d\n"), - ret)); - } - retval += ret; - } + if (ACE::debug ()) + ACE_DEBUG ((LM_DEBUG, + ACE_LIB_TEXT ("ACE (%P|%t) SR::fini, repo=%@ [%d] (size %d) - ") + ACE_LIB_TEXT ("fini so=%@, name=%s, type=%@%s\n"), + this, i, this->total_size_, + s, s->name (), s->type (), ((s->active() != 0)?", active" : ""))); + + // Collect any errors. + int ret = s->fini (); + retval += ret; + } } return (retval == 0) ? 0 : -1; @@ -193,31 +186,27 @@ ACE_Service_Repository::close (void) // necessarily be maintained since the <remove> method performs // compaction. However, the common case is not to remove // services, so typically they are deleted in reverse order. + int lastindex = this->current_size_ - 1; + this->current_size_ = 0; + for (; lastindex >= 0; lastindex--) + { + ACE_Service_Type *s = const_cast<ACE_Service_Type *> + (this->service_vector_[lastindex]); - if(ACE::debug ()) - ACE_DEBUG ((LM_DEBUG, - ACE_LIB_TEXT ("(%P|%t) SR::close, this=%@, size=%d\n"), - this, - this->current_size_)); + this->service_vector_[lastindex] = 0; - for (int i = this->current_size_ - 1; i >= 0; i--) - { if(ACE::debug ()) ACE_DEBUG ((LM_DEBUG, - ACE_LIB_TEXT ("(%P|%t) SR::close, this=%@, delete so[%d]=%@ (%s)\n"), - this, - i, - this->service_vector_[i], - this->service_vector_[i]->name ())); - - ACE_Service_Type *s = const_cast<ACE_Service_Type *> (this->service_vector_[i]); - --this->current_size_; + ACE_LIB_TEXT ("ACE (%P|%t) SR::close, repo=%@ [%d] (size=%d) - ") + ACE_LIB_TEXT ("deleting so=%@, type=%@\n"), + this, lastindex, this->total_size_, + s, s->type ())); + delete s; } delete [] this->service_vector_; this->service_vector_ = 0; - this->current_size_ = 0; } return 0; @@ -226,8 +215,6 @@ ACE_Service_Repository::close (void) ACE_Service_Repository::~ACE_Service_Repository (void) { ACE_TRACE ("ACE_Service_Repository::~ACE_Service_Repository"); - if(ACE::debug ()) - ACE_DEBUG ((LM_DEBUG, "(%P|%t) SR::<dtor>, this=%@\n", this)); this->close (); } @@ -327,28 +314,21 @@ ACE_Service_Repository::insert (const ACE_Service_Type *sr) } if (ACE::debug ()) - { - ACE_DEBUG ((LM_DEBUG, - ACE_TEXT ("ACE (%P|%t) SR::insert, repo=%@ [%d] (size=%d): "), - this, - i, - this->total_size_)); - sr->dump(); - ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\n"))); - } + ACE_DEBUG ((LM_DEBUG, + ACE_LIB_TEXT ("ACE (%P|%t) SR::insert, repo=%@ [%d] ") + ACE_LIB_TEXT ("(size=%d): %s(@%@), type=%@%s\n"), + this, i, this->total_size_, + sr->name (), sr, sr->type (), ((sr->active() != 0)?", active" : ""))); } // Delete outside the lock if (s != 0) { if (ACE::debug ()) - { - ACE_DEBUG ((LM_DEBUG, - ACE_TEXT ("ACE (%P|%t) SR::insert, repo=%@ - destroying : "), - this)); - s->dump(); - ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\n"))); - } + ACE_DEBUG ((LM_DEBUG, + ACE_LIB_TEXT ("ACE (%P|%t) SR::insert, repo=%@ - ") + ACE_LIB_TEXT ("destroying : %s\n"), + this, s->name ())); delete s; } diff --git a/ACE/ace/Service_Repository.h b/ACE/ace/Service_Repository.h index bbeafbe3602..ba4016a8405 100644 --- a/ACE/ace/Service_Repository.h +++ b/ACE/ace/Service_Repository.h @@ -29,6 +29,7 @@ ACE_BEGIN_VERSIONED_NAMESPACE_DECL class ACE_Service_Type; #define ACE_Component_Repository ACE_Service_Repository + /** * @class ACE_Service_Repository * @@ -48,6 +49,7 @@ class ACE_Export ACE_Service_Repository { public: friend class ACE_Service_Repository_Iterator; + friend class ACE_Service_Type_DLL_Guard; enum { @@ -138,6 +140,7 @@ private: const ACE_Service_Type ** = 0, int ignore_suspended = 1) const; +private: /// Contains all the configured services. const ACE_Service_Type **service_vector_; @@ -147,6 +150,7 @@ private: /// Maximum number of services. size_t total_size_; +private: /// Pointer to a process-wide ACE_Service_Repository. static ACE_Service_Repository *svc_rep_; diff --git a/ACE/tests/Service_Config_Test.cpp b/ACE/tests/Service_Config_Test.cpp index dde86668b3c..c18970173be 100644 --- a/ACE/tests/Service_Config_Test.cpp +++ b/ACE/tests/Service_Config_Test.cpp @@ -206,16 +206,18 @@ testLimits (int , ACE_TCHAR *[]) // We cant simply rely on the fact that insertion fails, because it // is typical to have no easy way of getting detailed error // information from a parser. - one.process_directive (svc_desc1); - one.process_directive (svc_desc2); - - if (-1 == one.find (ACE_TEXT ("Test_Object_1_More"), 0, 0)) + int ret1 = one.process_directive (svc_desc1); + if (ret1 != 0 || + -1 == one.find (ACE_TEXT ("Test_Object_1_More"), 0, 0)) { ++error; ACE_ERROR ((LM_ERROR, ACE_TEXT("Expected to have registered the first service\n"))); } - if (-1 != one.find (ACE_TEXT ("Test_Object_2_More"), 0, 0)) + int ret2 = one.process_directive (svc_desc2); + + if (ret2 == 0 || + -1 != one.find (ACE_TEXT ("Test_Object_2_More"), 0, 0)) { ++error; ACE_ERROR ((LM_ERROR, ACE_TEXT("Being able to add more than 1 service was not expected\n"))); @@ -250,8 +252,8 @@ run_main (int argc, ACE_TCHAR *argv[]) { ACE_START_TEST (ACE_TEXT ("Service_Config_Test")); - testOrderlyInstantialtion (argc, argv); - testLoadingServiceConfFile (argc, argv); + testOrderlyInstantialtion (argc, argv); + testLoadingServiceConfFile (argc, argv); testLimits (argc, argv); ACE_END_TEST; |