]> git.saurik.com Git - wxWidgets.git/commitdiff
Fix bug with unloading wxPluginLibrary objects in "wrong" order.
authorVadim Zeitlin <vadim@wxwidgets.org>
Sat, 26 May 2012 12:29:54 +0000 (12:29 +0000)
committerVadim Zeitlin <vadim@wxwidgets.org>
Sat, 26 May 2012 12:29:54 +0000 (12:29 +0000)
wxPluginLibrary objects had to be unloaded in exactly the reverse order to
which they were loaded in. This was not documented and was a serious
limitation for any realistic use of plugins anyhow, so fix it and allow
unloading them in any order now.

Instead of keeping a pointer to the last wxClassInfo not created by this
plugin, now keep a pointer to the first wxClassInfo that was created by it.
This makes the code slightly more complex but this pointer, unlike the old
one, remains valid even if another plugin was unloaded.

Closes #14261.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@71571 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

docs/changes.txt
include/wx/dynload.h
src/common/dynload.cpp

index 28bbac5ac63e716abdba830109003a35d8b2918d..e917d2384b2d6f6d059a77a3d247091e6d98303a 100644 (file)
@@ -522,6 +522,7 @@ All:
 - Implement wxThread::SetConcurrency() for POSIX systems (Igor Korot).
 - Fix deadlock due to too many events in Unix console apps (Lukasz Michalski).
 - Added wxDir::GetNameWithSep().
+- Allow unloading wxPluginLibrary objects in any order (manyleaves).
 
 All (GUI):
 
index 3c5644d652d77ff93237df03d32ae367720d8ae7..bb2997bb4f7fcc3d657527f2acc5070863a28e4b 100644 (file)
@@ -82,8 +82,11 @@ public:
 
 private:
 
-    const wxClassInfo    *m_before; // sm_first before loading this lib
-    const wxClassInfo    *m_after;  // ..and after.
+    // These pointers may be NULL but if they are not, then m_ourLast follows
+    // m_ourFirst in the linked list, i.e. can be found by calling GetNext() a
+    // sufficient number of times.
+    const wxClassInfo    *m_ourFirst; // first class info in this plugin
+    const wxClassInfo    *m_ourLast;  // ..and the last one
 
     size_t          m_linkcount;    // Ref count of library link calls
     size_t          m_objcount;     // ..and (pluggable) object instantiations.
index a76a1907334f1b9e80f6586ee1d6932271deea68..e9febf28cbca14e7a89032c3873a330088977f86 100644 (file)
@@ -76,9 +76,32 @@ wxPluginLibrary::wxPluginLibrary(const wxString &libname, int flags)
         : m_linkcount(1)
         , m_objcount(0)
 {
-    m_before = wxClassInfo::GetFirst();
+    const wxClassInfo* const oldFirst = wxClassInfo::GetFirst();
     Load( libname, flags );
-    m_after = wxClassInfo::GetFirst();
+
+    // It is simple to know what is the last object we registered, it's just
+    // the new head of the wxClassInfo list:
+    m_ourLast = wxClassInfo::GetFirst();
+
+    // But to find the first wxClassInfo created by this library we need to
+    // iterate until we get to the previous head as we don't have the links in
+    // the backwards direction:
+    if ( m_ourLast != oldFirst )
+    {
+        for ( const wxClassInfo* info = m_ourLast; ; info = info->GetNext() )
+        {
+            if ( info->GetNext() == oldFirst )
+            {
+                m_ourFirst = info;
+                break;
+            }
+        }
+    }
+    else // We didn't register any classes at all.
+    {
+        m_ourFirst =
+        m_ourLast = NULL;
+    }
 
     if( m_handle != 0 )
     {
@@ -130,7 +153,10 @@ bool wxPluginLibrary::UnrefLib()
 
 void wxPluginLibrary::UpdateClasses()
 {
-    for (const wxClassInfo *info = m_after; info != m_before; info = info->GetNext())
+    if ( !m_ourFirst )
+        return;
+
+    for ( const wxClassInfo *info = m_ourFirst; ; info = info->GetNext() )
     {
         if( info->GetClassName() )
         {
@@ -138,6 +164,9 @@ void wxPluginLibrary::UpdateClasses()
             // we can quickly find the entry they correspond to.
             (*ms_classes)[info->GetClassName()] = this;
         }
+
+        if ( info == m_ourLast )
+            break;
     }
 }
 
@@ -147,9 +176,15 @@ void wxPluginLibrary::RestoreClasses()
     if (!ms_classes)
         return;
 
-    for(const wxClassInfo *info = m_after; info != m_before; info = info->GetNext())
+    if ( !m_ourFirst )
+        return;
+
+    for ( const wxClassInfo *info = m_ourFirst; ; info = info->GetNext() )
     {
         ms_classes->erase(ms_classes->find(info->GetClassName()));
+
+        if ( info == m_ourLast )
+            break;
     }
 }
 
@@ -166,16 +201,22 @@ void wxPluginLibrary::RegisterModules()
     wxASSERT_MSG( m_linkcount == 1,
                   wxT("RegisterModules should only be called for the first load") );
 
-    for ( const wxClassInfo *info = m_after; info != m_before; info = info->GetNext())
+    if ( m_ourFirst )
     {
-        if( info->IsKindOf(CLASSINFO(wxModule)) )
+        for ( const wxClassInfo *info = m_ourFirst; ; info = info->GetNext() )
         {
-            wxModule *m = wxDynamicCast(info->CreateObject(), wxModule);
+            if( info->IsKindOf(CLASSINFO(wxModule)) )
+            {
+                wxModule *m = wxDynamicCast(info->CreateObject(), wxModule);
 
-            wxASSERT_MSG( m, wxT("wxDynamicCast of wxModule failed") );
+                wxASSERT_MSG( m, wxT("wxDynamicCast of wxModule failed") );
+
+                m_wxmodules.push_back(m);
+                wxModule::RegisterModule(m);
+            }
 
-            m_wxmodules.push_back(m);
-            wxModule::RegisterModule(m);
+            if ( info == m_ourLast )
+                break;
         }
     }