summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoriliyan <iliyan@ae88bc3d-4319-0410-8dbf-d08b4c9d3795>2006-08-22 22:32:10 +0000
committeriliyan <iliyan@ae88bc3d-4319-0410-8dbf-d08b4c9d3795>2006-08-22 22:32:10 +0000
commita03a40385c19531d9e11b07ce578833590db11cf (patch)
tree7d83c5cc3c5f74047b9ef544baa07de6f21f1c4a
parent558caa6c9a9c3e26100e7bd9423945b4e4a9ba78 (diff)
downloadATCD-a03a40385c19531d9e11b07ce578833590db11cf.tar.gz
ChangeLogTag: Tue Aug 22 21:43:34 UTC 2006 Iliyan Jeliazkov <iliyan@ociweb.com>
-rw-r--r--ACE/ChangeLog69
-rw-r--r--ACE/ace/DLL.cpp32
-rw-r--r--ACE/ace/DLL.h5
-rw-r--r--ACE/ace/DLL_Manager.cpp18
-rw-r--r--ACE/ace/Parse_Node.cpp20
-rw-r--r--ACE/ace/Parse_Node.h6
-rw-r--r--ACE/ace/Service_Gestalt.cpp253
-rw-r--r--ACE/ace/Service_Gestalt.h57
-rw-r--r--ACE/ace/Service_Object.cpp25
-rw-r--r--ACE/ace/Service_Object.h9
-rw-r--r--ACE/ace/Service_Object.inl3
-rw-r--r--ACE/ace/Service_Repository.cpp90
-rw-r--r--ACE/ace/Service_Repository.h4
-rw-r--r--ACE/tests/Service_Config_Test.cpp16
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;