your patch

John David Anglin dave@hiauly1.hia.nrc.ca
Wed Jun 13 13:30:00 GMT 2001


Here it is!  We need this to properly intialize the _STL_mutex_lock struct
used in v3 on systems which define __GTHREAD_MUTEX_INIT_FUNCTION.

Loren Riddle wrote:

> OK, I just woke up. This is odd (since I haven't been awake to think about it),
> I now understand your patch, which used dual once functions, completely.
> The point is that even if flag processing is somehow busted across
> multiprocessors, *thread_once processing is known to be OK.  That is being
> very conservative since *thread_mutex_* points are suppose to be memory
> syncronization points (i.e. if the variables were just made voilitile, it
> should work in all practical cases as well), but I have no complaint with you being
> conservative in your patch...
> 
> Great job!

The latest changes are the _M_init_flag is now volatile and the initializer
__STL_MUTEX_INITIALIZER no longer causes any warnings if the system thread
interface defines __GTHREAD_MUTEX_INIT_DEFAULT.

I have retested under i686 linux with both the __GTHREAD_MUTEX_INIT and
__GTHREAD_MUTEX_INIT_FUNCTION modes.  I have also tested the
__GTHREAD_MUTEX_INIT_FUNCTION mode under hpux 10.20.  No regressions
were observed.  I ran the STL memory leak program posted by Loren under
hpux to make certain that STL containers were functional.  The program
was linked to the appropriate libraries with and without threads.  It
runs with no errors although I am not certain about memory leaks.  In
doing the testing of the thread mode under hpux, I ran the make check
in the thread directory as doing so in the non-thread directory
doesn't use the proper includes or link with the proper library with
`-threads'.

I documented the changes to the GTHREAD interface in this patch:
< http://gcc.gnu.org/ml/gcc-patches/2001-06/msg00885.html >.  If this
patch is approved, I hope that the documentation change to gthr.h
will also be approved.  However, it is only a documentation change
and not absolutely essential for the release.

The files gthr-rtems.h and gthr-win32.h need defines for
__GTHREAD_MUTEX_INIT_DEFAULT.  I don't have the internal information
needed to do this for these thread packages.  However, defining
__GTHREAD_MUTEX_INIT_DEFAULT is not crucial to the operational
behavior of the v3 library and it only results in a warning which
can be ignored if it isn't defined.

A number of compromises had to be made in developing this patch
due to the limitations of what can be done with code in a struct
and the requirements of the gthread/pthread interface.  I think
this is the best that can be done at the present time.

OK?

Dave
-- 
J. David Anglin                                  dave.anglin@nrc.ca
National Research Council of Canada              (613) 990-0752 (FAX: 952-6605)

2001-06-13  John David Anglin  <dave@hiauly1.hia.nrc.ca>

	* src/globals.cc: Define globals _GLIBCPP_mutex_init (),
	_GLIBCPP_mutex_address_init (), _GLIBCPP_once, _GLIBCPP_mutex
	and _GLIBCPP_mutex_address.
	* include/bits/stl_threads.h (_STL_mutex_lock): Use above to provide
	once-only runtime initialization of _M_lock mutex when
	__GTHREAD_MUTEX_INIT_FUNCTION is defined.
	(__STL_MUTEX_INITIALIZER): Provide initializer for _STL_mutex_lock
	for __GTHREAD_MUTEX_INIT_FUNCTION case.

--- src/globals.cc.orig	Wed Jun  6 14:13:01 2001
+++ src/globals.cc	Mon Jun 11 16:53:03 2001
@@ -25,6 +25,8 @@
 // invalidate any other reasons why the executable file might be covered by
 // the GNU General Public License.
 
+#include "bits/c++config.h"
+#include "bits/gthr.h"
 #include <fstream>
 #include <istream>
 #include <ostream>
@@ -73,4 +74,31 @@
   fake_wfilebuf buf_wcin;
   fake_wfilebuf buf_wcerr;
 #endif
+
+// Globals for once-only runtime initialization of mutex objects.  This
+// allows static initialization of these objects on systems that need a
+// function call to initialize a mutex.  For example, see stl_threads.h.
+#if __GTHREADS
+#ifdef __GTHREAD_MUTEX_INIT
+// This path is not needed since static initialization of mutexs works
+// on this platform.
+#elif defined(__GTHREAD_MUTEX_INIT_FUNCTION)
+__gthread_once_t _GLIBCPP_once = __GTHREAD_ONCE_INIT;
+__gthread_mutex_t _GLIBCPP_mutex;
+__gthread_mutex_t *_GLIBCPP_mutex_address;
+
+// Once-only initializer function for _GLIBCPP_mutex.  
+void
+_GLIBCPP_mutex_init ()
+{
+  __GTHREAD_MUTEX_INIT_FUNCTION (&_GLIBCPP_mutex);
+}
+// Once-only initializer function for _GLIBCPP_mutex_address.  
+void
+_GLIBCPP_mutex_address_init ()
+{
+  __GTHREAD_MUTEX_INIT_FUNCTION (_GLIBCPP_mutex_address);
+}
+#endif
+#endif
 }
--- include/bits/stl_threads.h.orig	Sat Jun  9 16:17:22 2001
+++ include/bits/stl_threads.h	Tue Jun 12 15:57:11 2001
@@ -296,21 +296,62 @@
 template <int __inst>
 unsigned _STL_mutex_spin<__inst>::__last = 0;
 
+// GCC extension begin
+#if defined(__STL_GTHREADS)
+#if !defined(__GTHREAD_MUTEX_INIT) && defined(__GTHREAD_MUTEX_INIT_FUNCTION)
+extern __gthread_mutex_t _GLIBCPP_mutex;
+extern __gthread_mutex_t *_GLIBCPP_mutex_address;
+extern __gthread_once_t _GLIBCPP_once;
+extern void _GLIBCPP_mutex_init (void);
+extern void _GLIBCPP_mutex_address_init (void);
+#endif
+#endif
+// GCC extension end
+
 struct _STL_mutex_lock
 {
 // GCC extension begin
 #if defined(__STL_GTHREADS)
+  // The class must be statically initialized with __STL_MUTEX_INITIALIZER.
+#if !defined(__GTHREAD_MUTEX_INIT) && defined(__GTHREAD_MUTEX_INIT_FUNCTION)
+  volatile int _M_init_flag;
+  __gthread_once_t _M_once;
+#endif
   __gthread_mutex_t _M_lock;
-  void _M_initialize()
-  {
+  void _M_initialize() {
 #ifdef __GTHREAD_MUTEX_INIT
-  // There should be no code in this path given the usage rules above.
+    // There should be no code in this path given the usage rules above.
 #elif defined(__GTHREAD_MUTEX_INIT_FUNCTION)
-    __GTHREAD_MUTEX_INIT_FUNCTION (&_M_lock);
+    if (_M_init_flag) return;
+    if (__gthread_once (&_GLIBCPP_once, _GLIBCPP_mutex_init) != 0
+        && __gthread_active_p ())
+      abort ();
+    __gthread_mutex_lock (&_GLIBCPP_mutex);
+    if (!_M_init_flag) {
+	// Even though we have a global lock, we use __gthread_once to be
+	// absolutely certain the _M_lock mutex is only initialized once on
+	// multiprocessor systems.
+	_GLIBCPP_mutex_address = &_M_lock;
+	if (__gthread_once (&_M_once, _GLIBCPP_mutex_address_init) != 0
+	    && __gthread_active_p ())
+	  abort ();
+	_M_init_flag = 1;
+    }
+    __gthread_mutex_unlock (&_GLIBCPP_mutex);
 #endif
   }
-  void _M_acquire_lock() { __gthread_mutex_lock(&_M_lock); }
-  void _M_release_lock() { __gthread_mutex_unlock(&_M_lock); }
+  void _M_acquire_lock() {
+#if !defined(__GTHREAD_MUTEX_INIT) && defined(__GTHREAD_MUTEX_INIT_FUNCTION)
+    if (!_M_init_flag) _M_initialize();
+#endif
+    __gthread_mutex_lock(&_M_lock);
+  }
+  void _M_release_lock() {
+#if !defined(__GTHREAD_MUTEX_INIT) && defined(__GTHREAD_MUTEX_INIT_FUNCTION)
+    if (!_M_init_flag) _M_initialize();
+#endif
+    __gthread_mutex_unlock(&_M_lock);
+  }
 #else
 // GCC extension end
 #if defined(__STL_SGI_THREADS) || defined(__STL_WIN32THREADS)
@@ -415,8 +456,13 @@
 #if defined(__STL_GTHREADS)
 #ifdef __GTHREAD_MUTEX_INIT
 #define __STL_MUTEX_INITIALIZER = { __GTHREAD_MUTEX_INIT }
+#elif defined(__GTHREAD_MUTEX_INIT_FUNCTION)
+#ifdef __GTHREAD_MUTEX_INIT_DEFAULT
+#define __STL_MUTEX_INITIALIZER \
+  = { 0, __GTHREAD_ONCE_INIT, __GTHREAD_MUTEX_INIT_DEFAULT }
 #else
-#define __STL_MUTEX_INITIALIZER
+#define __STL_MUTEX_INITIALIZER = { 0, __GTHREAD_ONCE_INIT }
+#endif
 #endif
 #else
 // GCC extension end



More information about the Libstdc++ mailing list