]> git.saurik.com Git - wxWidgets.git/blobdiff - src/common/object.cpp
Add information about the log message generation location to wxLog.
[wxWidgets.git] / src / common / object.cpp
index e04a3e4f3d45544879d2ca51d2cefab8a4779683..622aa2f2eb3d810612e3e66d5af408909186dab3 100644 (file)
@@ -206,37 +206,45 @@ wxClassInfo *wxClassInfo::FindClass(const wxString& className)
     }
 }
 
-// This function wasn't written to be reentrant but there is a possiblity of
-// reentrance if something it does causes a shared lib to load and register
-// classes. On Solaris this happens when the wxHashTable is newed, so the first
-// part of the function has been modified to handle it, and a wxASSERT checks
-// against reentrance in the remainder of the function.
+// Reentrance can occur on some platforms (Solaris for one), as the use of hash
+// and string objects can cause other modules to load and register classes
+// before the original call returns. This is handled by keeping the hash table
+// local when it is first created and only assigning it to the global variable
+// when the function is ready to return.
+//
+// That does make the assumption that after the function has completed the
+// first time the problem will no longer happen; all the modules it depends on
+// will have been loaded. The assumption is checked using the 'entry' variable
+// as a reentrance guard, it checks that once the hash table is global it is
+// not accessed multiple times simulateously.
 
 void wxClassInfo::Register()
 {
-    if ( !sm_classTable )
-    {
-        wxHashTable *classTable = new wxHashTable(wxKEY_STRING);
-
-        // check for reentrance
-        if ( sm_classTable )
-            delete classTable;
-        else
-            sm_classTable = classTable;
-    }
-
 #if wxDEBUG_LEVEL
     // reentrance guard - see note above
     static int entry = 0;
-    wxASSERT_MSG(++entry == 1, _T("wxClassInfo::Register() reentrance"));
 #endif // wxDEBUG_LEVEL
 
+    wxHashTable *classTable;
+
+    if ( !sm_classTable )
+    {
+        // keep the hash local initially, reentrance is possible
+        classTable = new wxHashTable(wxKEY_STRING);
+    }
+    else
+    {
+        // guard againt reentrance once the global has been created
+        wxASSERT_MSG(++entry == 1, _T("wxClassInfo::Register() reentrance"));
+        classTable = sm_classTable;
+    }
+
     // Using IMPLEMENT_DYNAMIC_CLASS() macro twice (which may happen if you
     // link any object module twice mistakenly, or link twice against wx shared
     // library) will break this function because it will enter an infinite loop
     // and eventually die with "out of memory" - as this is quite hard to
     // detect if you're unaware of this, try to do some checks here.
-    wxASSERT_MSG( sm_classTable->Get(m_className) == NULL,
+    wxASSERT_MSG( classTable->Get(m_className) == NULL,
         wxString::Format
         (
             _T("Class \"%s\" already in RTTI table - have you used IMPLEMENT_DYNAMIC_CLASS() multiple times or linked some object file twice)?"),
@@ -244,10 +252,27 @@ void wxClassInfo::Register()
         )
     );
 
-    sm_classTable->Put(m_className, (wxObject *)this);
+    classTable->Put(m_className, (wxObject *)this);
+
+    // if we're using a local hash we need to try to make it global
+    if ( sm_classTable != classTable )
+    {
+        if ( !sm_classTable )
+        {
+            // make the hash global
+            sm_classTable = classTable;
+        }
+        else
+        {
+            // the gobal hash has already been created by a reentrant call,
+            // so delete the local hash and try again
+            delete classTable;
+            Register();
+        }
+    }
 
 #if wxDEBUG_LEVEL
-    --entry;
+    entry = 0;
 #endif // wxDEBUG_LEVEL
 }
 
@@ -325,8 +350,10 @@ wxClassInfo::const_iterator wxClassInfo::end_classinfo()
 // wxObjectRefData
 // ----------------------------------------------------------------------------
 
-void wxObjectRefData::DecRef()
+void wxRefCounter::DecRef()
 {
+    wxASSERT_MSG( m_count > 0, "invalid ref data count" );
+
     if ( --m_count == 0 )
         delete this;
 }
@@ -361,8 +388,6 @@ void wxObject::UnRef()
 {
     if ( m_refData )
     {
-        wxASSERT_MSG( m_refData->m_count > 0, _T("invalid ref data count") );
-
         m_refData->DecRef();
         m_refData = NULL;
     }