summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog84
-rw-r--r--ChangeLog.pre-2-084
-rw-r--r--ChangeLog.pre-2-1084
-rw-r--r--ChangeLog.pre-2-1284
-rw-r--r--ChangeLog.pre-2-284
-rw-r--r--ChangeLog.pre-2-484
-rw-r--r--ChangeLog.pre-2-684
-rw-r--r--ChangeLog.pre-2-884
-rw-r--r--Makefile.am5
-rw-r--r--acconfig.h2
-rw-r--r--configure.in206
-rw-r--r--garray.c19
-rw-r--r--gbacktrace.c5
-rw-r--r--gcache.c11
-rw-r--r--gcompletion.c4
-rw-r--r--gdataset.c76
-rw-r--r--gdate.c24
-rw-r--r--gerror.c5
-rw-r--r--ghash.c13
-rw-r--r--ghook.c5
-rw-r--r--giochannel.c4
-rw-r--r--giounix.c4
-rw-r--r--glib-config.in15
-rw-r--r--glib.h134
-rw-r--r--glib/Makefile.am5
-rw-r--r--glib/garray.c19
-rw-r--r--glib/gbacktrace.c5
-rw-r--r--glib/gcache.c11
-rw-r--r--glib/gcompletion.c4
-rw-r--r--glib/gdataset.c76
-rw-r--r--glib/gdate.c24
-rw-r--r--glib/gerror.c5
-rw-r--r--glib/ghash.c13
-rw-r--r--glib/ghook.c5
-rw-r--r--glib/giochannel.c4
-rw-r--r--glib/giounix.c4
-rw-r--r--glib/glib.h134
-rw-r--r--glib/glist.c44
-rw-r--r--glib/gmain.c158
-rw-r--r--glib/gmem.c89
-rw-r--r--glib/gmessages.c115
-rw-r--r--glib/gnode.c36
-rw-r--r--glib/gprimes.c5
-rw-r--r--glib/grel.c5
-rw-r--r--glib/gscanner.c5
-rw-r--r--glib/gslist.c37
-rw-r--r--glib/gstrfuncs.c26
-rw-r--r--glib/gstring.c11
-rw-r--r--glib/gtimer.c4
-rw-r--r--glib/gtree.c18
-rw-r--r--glib/gutils.c34
-rw-r--r--glist.c44
-rw-r--r--gmain.c158
-rw-r--r--gmem.c89
-rw-r--r--gmessages.c115
-rw-r--r--gmodule/ChangeLog5
-rw-r--r--gmodule/gmodule-dl.c5
-rw-r--r--gmodule/gmodule-dld.c5
-rw-r--r--gmodule/gmodule-win32.c5
-rw-r--r--gmodule/gmodule.c68
-rw-r--r--gmutex.c176
-rw-r--r--gnode.c36
-rw-r--r--gprimes.c5
-rw-r--r--grel.c5
-rw-r--r--gscanner.c5
-rw-r--r--gslist.c37
-rw-r--r--gstrfuncs.c26
-rw-r--r--gstring.c11
-rw-r--r--gthread/.cvsignore8
-rw-r--r--gthread/Makefile.am21
-rw-r--r--gthread/gthread-none.c28
-rw-r--r--gthread/gthread-nspr.c218
-rw-r--r--gthread/gthread-posix.c176
-rw-r--r--gthread/gthread-solaris.c177
-rw-r--r--gthread/gthread.c101
-rw-r--r--gthread/testgthread.c200
-rw-r--r--gtimer.c4
-rw-r--r--gtree.c18
-rw-r--r--gutils.c34
79 files changed, 3635 insertions, 245 deletions
diff --git a/ChangeLog b/ChangeLog
index 7d1d0758f..dc3ecadc7 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,87 @@
+1998-12-11 Sebastian Wilhelmi <wilhelmi@ira.uka.de>
+
+ * gthread/gthread-nspr.c, configure.in: Added new default thread
+ implementation on top of the mozilla nspr library.
+
+ * gmem.c, gmessaged.c, gthread/gthread.c, gthread/gthread-*.c:
+ Changed GStaticMutex and GStaticPrivate in gmem.c and gmessages.c
+ into GMutex and GPrivate resp. to make error reporting and use of
+ gmem possible in most (not all, though) gthread functions. Also
+ initialized the modules via new init functions.
+
+ * configure.in: Fixed syntax bug in definition of type
+ GStaticMutex.
+
+ * gthread/testgthread.c: Updated to work with nspr, but see note
+ there for remaining problems.
+
+1998-12-10 Sebastian Wilhelmi <wilhelmi@ira.uka.de>
+
+ * gmutex.c, glib.h: Now abort, if a mutex/cond/private is
+ allocated before the thread system is set up.
+
+ * gthread/gthread.c (g_thread_init): Removed g_thread_try_init(),
+ as it is not necessary. Changed the error message. Corrected logic
+ for g_thread_use_default_impl.
+
+ * gmutex.c (g_mutex_init): Keep the thread private data array
+ after calling g_thread_init().
+
+1998-12-09 Sebastian Wilhelmi <wilhelmi@ira.uka.de>
+
+ * gthread/testgthread.c (new_thread): Now also working for posix
+ threads; (wait_thread): Now a better implementation, that does not
+ use 100% CPU.
+
+ * Made the thread related code follow GNU coding standard.
+
+ * Made a comment (HOLDS:) above each function, that expects the
+ given locks to be held.
+
+ * Changed try_lock to trylock throughout.
+
+ * glib.c: Eventually removed the #if 0'ed code for old GStaticMutex.
+
+ * glib.c: Corrected g_trylock macro for G_DEBUG_LOCKS.
+
+ * gmain.c (g_main_poll_add_unlocked): first take a new poll record
+ form the poll_free_list.
+
+ * gmem.c, gstrfuncs.c, gutils.c: Made it MT safe.
+
+ * gthraed/*.c: Added copyright headers.
+
+ * gthread/gthread-solaris.c: do not use g_log for errors, as g_log
+ uses these module and endless recursions might happen, just use a
+ plain fprintf(stderr,...).
+
+ * gthread/gthread.c (g_thread_try_init): Call g_mutex_init().
+
+ * gthread/testgthread.c: updated test program.
+
+Tue Dec 8 18:49:56 1998 Owen Taylor <otaylor@redhat.com>
+
+ * Start at adding thread-safety. (mostly work
+ of Sebastian Wilhelmi <wilhelmi@ira.uka.de>)
+
+ - configure.in now looks for a system thread implementation.
+ Currently support is included for POSIX threads
+ and Solaris threads. The default support is built
+ into a separate library -lgthread.
+
+ - The thread implementation can be modified by passing
+ a vector of functions g_thread_init().
+
+ - The default or supplied functions are used to
+ implement a small set of thread functions for
+ mutexes, condition variables, and thread-private
+ data.
+
+ - GLib now uses these functions to provide thread
+ safety. (In the sense that all global static
+ data is locked... individual structures must still
+ be locked by the caller.)
+
Sat Dec 12 19:08:59 1998 Tim Janik <timj@gtk.org>
* configure.in: always define G_HAVE_INLINE if __cplusplus is
diff --git a/ChangeLog.pre-2-0 b/ChangeLog.pre-2-0
index 7d1d0758f..dc3ecadc7 100644
--- a/ChangeLog.pre-2-0
+++ b/ChangeLog.pre-2-0
@@ -1,3 +1,87 @@
+1998-12-11 Sebastian Wilhelmi <wilhelmi@ira.uka.de>
+
+ * gthread/gthread-nspr.c, configure.in: Added new default thread
+ implementation on top of the mozilla nspr library.
+
+ * gmem.c, gmessaged.c, gthread/gthread.c, gthread/gthread-*.c:
+ Changed GStaticMutex and GStaticPrivate in gmem.c and gmessages.c
+ into GMutex and GPrivate resp. to make error reporting and use of
+ gmem possible in most (not all, though) gthread functions. Also
+ initialized the modules via new init functions.
+
+ * configure.in: Fixed syntax bug in definition of type
+ GStaticMutex.
+
+ * gthread/testgthread.c: Updated to work with nspr, but see note
+ there for remaining problems.
+
+1998-12-10 Sebastian Wilhelmi <wilhelmi@ira.uka.de>
+
+ * gmutex.c, glib.h: Now abort, if a mutex/cond/private is
+ allocated before the thread system is set up.
+
+ * gthread/gthread.c (g_thread_init): Removed g_thread_try_init(),
+ as it is not necessary. Changed the error message. Corrected logic
+ for g_thread_use_default_impl.
+
+ * gmutex.c (g_mutex_init): Keep the thread private data array
+ after calling g_thread_init().
+
+1998-12-09 Sebastian Wilhelmi <wilhelmi@ira.uka.de>
+
+ * gthread/testgthread.c (new_thread): Now also working for posix
+ threads; (wait_thread): Now a better implementation, that does not
+ use 100% CPU.
+
+ * Made the thread related code follow GNU coding standard.
+
+ * Made a comment (HOLDS:) above each function, that expects the
+ given locks to be held.
+
+ * Changed try_lock to trylock throughout.
+
+ * glib.c: Eventually removed the #if 0'ed code for old GStaticMutex.
+
+ * glib.c: Corrected g_trylock macro for G_DEBUG_LOCKS.
+
+ * gmain.c (g_main_poll_add_unlocked): first take a new poll record
+ form the poll_free_list.
+
+ * gmem.c, gstrfuncs.c, gutils.c: Made it MT safe.
+
+ * gthraed/*.c: Added copyright headers.
+
+ * gthread/gthread-solaris.c: do not use g_log for errors, as g_log
+ uses these module and endless recursions might happen, just use a
+ plain fprintf(stderr,...).
+
+ * gthread/gthread.c (g_thread_try_init): Call g_mutex_init().
+
+ * gthread/testgthread.c: updated test program.
+
+Tue Dec 8 18:49:56 1998 Owen Taylor <otaylor@redhat.com>
+
+ * Start at adding thread-safety. (mostly work
+ of Sebastian Wilhelmi <wilhelmi@ira.uka.de>)
+
+ - configure.in now looks for a system thread implementation.
+ Currently support is included for POSIX threads
+ and Solaris threads. The default support is built
+ into a separate library -lgthread.
+
+ - The thread implementation can be modified by passing
+ a vector of functions g_thread_init().
+
+ - The default or supplied functions are used to
+ implement a small set of thread functions for
+ mutexes, condition variables, and thread-private
+ data.
+
+ - GLib now uses these functions to provide thread
+ safety. (In the sense that all global static
+ data is locked... individual structures must still
+ be locked by the caller.)
+
Sat Dec 12 19:08:59 1998 Tim Janik <timj@gtk.org>
* configure.in: always define G_HAVE_INLINE if __cplusplus is
diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10
index 7d1d0758f..dc3ecadc7 100644
--- a/ChangeLog.pre-2-10
+++ b/ChangeLog.pre-2-10
@@ -1,3 +1,87 @@
+1998-12-11 Sebastian Wilhelmi <wilhelmi@ira.uka.de>
+
+ * gthread/gthread-nspr.c, configure.in: Added new default thread
+ implementation on top of the mozilla nspr library.
+
+ * gmem.c, gmessaged.c, gthread/gthread.c, gthread/gthread-*.c:
+ Changed GStaticMutex and GStaticPrivate in gmem.c and gmessages.c
+ into GMutex and GPrivate resp. to make error reporting and use of
+ gmem possible in most (not all, though) gthread functions. Also
+ initialized the modules via new init functions.
+
+ * configure.in: Fixed syntax bug in definition of type
+ GStaticMutex.
+
+ * gthread/testgthread.c: Updated to work with nspr, but see note
+ there for remaining problems.
+
+1998-12-10 Sebastian Wilhelmi <wilhelmi@ira.uka.de>
+
+ * gmutex.c, glib.h: Now abort, if a mutex/cond/private is
+ allocated before the thread system is set up.
+
+ * gthread/gthread.c (g_thread_init): Removed g_thread_try_init(),
+ as it is not necessary. Changed the error message. Corrected logic
+ for g_thread_use_default_impl.
+
+ * gmutex.c (g_mutex_init): Keep the thread private data array
+ after calling g_thread_init().
+
+1998-12-09 Sebastian Wilhelmi <wilhelmi@ira.uka.de>
+
+ * gthread/testgthread.c (new_thread): Now also working for posix
+ threads; (wait_thread): Now a better implementation, that does not
+ use 100% CPU.
+
+ * Made the thread related code follow GNU coding standard.
+
+ * Made a comment (HOLDS:) above each function, that expects the
+ given locks to be held.
+
+ * Changed try_lock to trylock throughout.
+
+ * glib.c: Eventually removed the #if 0'ed code for old GStaticMutex.
+
+ * glib.c: Corrected g_trylock macro for G_DEBUG_LOCKS.
+
+ * gmain.c (g_main_poll_add_unlocked): first take a new poll record
+ form the poll_free_list.
+
+ * gmem.c, gstrfuncs.c, gutils.c: Made it MT safe.
+
+ * gthraed/*.c: Added copyright headers.
+
+ * gthread/gthread-solaris.c: do not use g_log for errors, as g_log
+ uses these module and endless recursions might happen, just use a
+ plain fprintf(stderr,...).
+
+ * gthread/gthread.c (g_thread_try_init): Call g_mutex_init().
+
+ * gthread/testgthread.c: updated test program.
+
+Tue Dec 8 18:49:56 1998 Owen Taylor <otaylor@redhat.com>
+
+ * Start at adding thread-safety. (mostly work
+ of Sebastian Wilhelmi <wilhelmi@ira.uka.de>)
+
+ - configure.in now looks for a system thread implementation.
+ Currently support is included for POSIX threads
+ and Solaris threads. The default support is built
+ into a separate library -lgthread.
+
+ - The thread implementation can be modified by passing
+ a vector of functions g_thread_init().
+
+ - The default or supplied functions are used to
+ implement a small set of thread functions for
+ mutexes, condition variables, and thread-private
+ data.
+
+ - GLib now uses these functions to provide thread
+ safety. (In the sense that all global static
+ data is locked... individual structures must still
+ be locked by the caller.)
+
Sat Dec 12 19:08:59 1998 Tim Janik <timj@gtk.org>
* configure.in: always define G_HAVE_INLINE if __cplusplus is
diff --git a/ChangeLog.pre-2-12 b/ChangeLog.pre-2-12
index 7d1d0758f..dc3ecadc7 100644
--- a/ChangeLog.pre-2-12
+++ b/ChangeLog.pre-2-12
@@ -1,3 +1,87 @@
+1998-12-11 Sebastian Wilhelmi <wilhelmi@ira.uka.de>
+
+ * gthread/gthread-nspr.c, configure.in: Added new default thread
+ implementation on top of the mozilla nspr library.
+
+ * gmem.c, gmessaged.c, gthread/gthread.c, gthread/gthread-*.c:
+ Changed GStaticMutex and GStaticPrivate in gmem.c and gmessages.c
+ into GMutex and GPrivate resp. to make error reporting and use of
+ gmem possible in most (not all, though) gthread functions. Also
+ initialized the modules via new init functions.
+
+ * configure.in: Fixed syntax bug in definition of type
+ GStaticMutex.
+
+ * gthread/testgthread.c: Updated to work with nspr, but see note
+ there for remaining problems.
+
+1998-12-10 Sebastian Wilhelmi <wilhelmi@ira.uka.de>
+
+ * gmutex.c, glib.h: Now abort, if a mutex/cond/private is
+ allocated before the thread system is set up.
+
+ * gthread/gthread.c (g_thread_init): Removed g_thread_try_init(),
+ as it is not necessary. Changed the error message. Corrected logic
+ for g_thread_use_default_impl.
+
+ * gmutex.c (g_mutex_init): Keep the thread private data array
+ after calling g_thread_init().
+
+1998-12-09 Sebastian Wilhelmi <wilhelmi@ira.uka.de>
+
+ * gthread/testgthread.c (new_thread): Now also working for posix
+ threads; (wait_thread): Now a better implementation, that does not
+ use 100% CPU.
+
+ * Made the thread related code follow GNU coding standard.
+
+ * Made a comment (HOLDS:) above each function, that expects the
+ given locks to be held.
+
+ * Changed try_lock to trylock throughout.
+
+ * glib.c: Eventually removed the #if 0'ed code for old GStaticMutex.
+
+ * glib.c: Corrected g_trylock macro for G_DEBUG_LOCKS.
+
+ * gmain.c (g_main_poll_add_unlocked): first take a new poll record
+ form the poll_free_list.
+
+ * gmem.c, gstrfuncs.c, gutils.c: Made it MT safe.
+
+ * gthraed/*.c: Added copyright headers.
+
+ * gthread/gthread-solaris.c: do not use g_log for errors, as g_log
+ uses these module and endless recursions might happen, just use a
+ plain fprintf(stderr,...).
+
+ * gthread/gthread.c (g_thread_try_init): Call g_mutex_init().
+
+ * gthread/testgthread.c: updated test program.
+
+Tue Dec 8 18:49:56 1998 Owen Taylor <otaylor@redhat.com>
+
+ * Start at adding thread-safety. (mostly work
+ of Sebastian Wilhelmi <wilhelmi@ira.uka.de>)
+
+ - configure.in now looks for a system thread implementation.
+ Currently support is included for POSIX threads
+ and Solaris threads. The default support is built
+ into a separate library -lgthread.
+
+ - The thread implementation can be modified by passing
+ a vector of functions g_thread_init().
+
+ - The default or supplied functions are used to
+ implement a small set of thread functions for
+ mutexes, condition variables, and thread-private
+ data.
+
+ - GLib now uses these functions to provide thread
+ safety. (In the sense that all global static
+ data is locked... individual structures must still
+ be locked by the caller.)
+
Sat Dec 12 19:08:59 1998 Tim Janik <timj@gtk.org>
* configure.in: always define G_HAVE_INLINE if __cplusplus is
diff --git a/ChangeLog.pre-2-2 b/ChangeLog.pre-2-2
index 7d1d0758f..dc3ecadc7 100644
--- a/ChangeLog.pre-2-2
+++ b/ChangeLog.pre-2-2
@@ -1,3 +1,87 @@
+1998-12-11 Sebastian Wilhelmi <wilhelmi@ira.uka.de>
+
+ * gthread/gthread-nspr.c, configure.in: Added new default thread
+ implementation on top of the mozilla nspr library.
+
+ * gmem.c, gmessaged.c, gthread/gthread.c, gthread/gthread-*.c:
+ Changed GStaticMutex and GStaticPrivate in gmem.c and gmessages.c
+ into GMutex and GPrivate resp. to make error reporting and use of
+ gmem possible in most (not all, though) gthread functions. Also
+ initialized the modules via new init functions.
+
+ * configure.in: Fixed syntax bug in definition of type
+ GStaticMutex.
+
+ * gthread/testgthread.c: Updated to work with nspr, but see note
+ there for remaining problems.
+
+1998-12-10 Sebastian Wilhelmi <wilhelmi@ira.uka.de>
+
+ * gmutex.c, glib.h: Now abort, if a mutex/cond/private is
+ allocated before the thread system is set up.
+
+ * gthread/gthread.c (g_thread_init): Removed g_thread_try_init(),
+ as it is not necessary. Changed the error message. Corrected logic
+ for g_thread_use_default_impl.
+
+ * gmutex.c (g_mutex_init): Keep the thread private data array
+ after calling g_thread_init().
+
+1998-12-09 Sebastian Wilhelmi <wilhelmi@ira.uka.de>
+
+ * gthread/testgthread.c (new_thread): Now also working for posix
+ threads; (wait_thread): Now a better implementation, that does not
+ use 100% CPU.
+
+ * Made the thread related code follow GNU coding standard.
+
+ * Made a comment (HOLDS:) above each function, that expects the
+ given locks to be held.
+
+ * Changed try_lock to trylock throughout.
+
+ * glib.c: Eventually removed the #if 0'ed code for old GStaticMutex.
+
+ * glib.c: Corrected g_trylock macro for G_DEBUG_LOCKS.
+
+ * gmain.c (g_main_poll_add_unlocked): first take a new poll record
+ form the poll_free_list.
+
+ * gmem.c, gstrfuncs.c, gutils.c: Made it MT safe.
+
+ * gthraed/*.c: Added copyright headers.
+
+ * gthread/gthread-solaris.c: do not use g_log for errors, as g_log
+ uses these module and endless recursions might happen, just use a
+ plain fprintf(stderr,...).
+
+ * gthread/gthread.c (g_thread_try_init): Call g_mutex_init().
+
+ * gthread/testgthread.c: updated test program.
+
+Tue Dec 8 18:49:56 1998 Owen Taylor <otaylor@redhat.com>
+
+ * Start at adding thread-safety. (mostly work
+ of Sebastian Wilhelmi <wilhelmi@ira.uka.de>)
+
+ - configure.in now looks for a system thread implementation.
+ Currently support is included for POSIX threads
+ and Solaris threads. The default support is built
+ into a separate library -lgthread.
+
+ - The thread implementation can be modified by passing
+ a vector of functions g_thread_init().
+
+ - The default or supplied functions are used to
+ implement a small set of thread functions for
+ mutexes, condition variables, and thread-private
+ data.
+
+ - GLib now uses these functions to provide thread
+ safety. (In the sense that all global static
+ data is locked... individual structures must still
+ be locked by the caller.)
+
Sat Dec 12 19:08:59 1998 Tim Janik <timj@gtk.org>
* configure.in: always define G_HAVE_INLINE if __cplusplus is
diff --git a/ChangeLog.pre-2-4 b/ChangeLog.pre-2-4
index 7d1d0758f..dc3ecadc7 100644
--- a/ChangeLog.pre-2-4
+++ b/ChangeLog.pre-2-4
@@ -1,3 +1,87 @@
+1998-12-11 Sebastian Wilhelmi <wilhelmi@ira.uka.de>
+
+ * gthread/gthread-nspr.c, configure.in: Added new default thread
+ implementation on top of the mozilla nspr library.
+
+ * gmem.c, gmessaged.c, gthread/gthread.c, gthread/gthread-*.c:
+ Changed GStaticMutex and GStaticPrivate in gmem.c and gmessages.c
+ into GMutex and GPrivate resp. to make error reporting and use of
+ gmem possible in most (not all, though) gthread functions. Also
+ initialized the modules via new init functions.
+
+ * configure.in: Fixed syntax bug in definition of type
+ GStaticMutex.
+
+ * gthread/testgthread.c: Updated to work with nspr, but see note
+ there for remaining problems.
+
+1998-12-10 Sebastian Wilhelmi <wilhelmi@ira.uka.de>
+
+ * gmutex.c, glib.h: Now abort, if a mutex/cond/private is
+ allocated before the thread system is set up.
+
+ * gthread/gthread.c (g_thread_init): Removed g_thread_try_init(),
+ as it is not necessary. Changed the error message. Corrected logic
+ for g_thread_use_default_impl.
+
+ * gmutex.c (g_mutex_init): Keep the thread private data array
+ after calling g_thread_init().
+
+1998-12-09 Sebastian Wilhelmi <wilhelmi@ira.uka.de>
+
+ * gthread/testgthread.c (new_thread): Now also working for posix
+ threads; (wait_thread): Now a better implementation, that does not
+ use 100% CPU.
+
+ * Made the thread related code follow GNU coding standard.
+
+ * Made a comment (HOLDS:) above each function, that expects the
+ given locks to be held.
+
+ * Changed try_lock to trylock throughout.
+
+ * glib.c: Eventually removed the #if 0'ed code for old GStaticMutex.
+
+ * glib.c: Corrected g_trylock macro for G_DEBUG_LOCKS.
+
+ * gmain.c (g_main_poll_add_unlocked): first take a new poll record
+ form the poll_free_list.
+
+ * gmem.c, gstrfuncs.c, gutils.c: Made it MT safe.
+
+ * gthraed/*.c: Added copyright headers.
+
+ * gthread/gthread-solaris.c: do not use g_log for errors, as g_log
+ uses these module and endless recursions might happen, just use a
+ plain fprintf(stderr,...).
+
+ * gthread/gthread.c (g_thread_try_init): Call g_mutex_init().
+
+ * gthread/testgthread.c: updated test program.
+
+Tue Dec 8 18:49:56 1998 Owen Taylor <otaylor@redhat.com>
+
+ * Start at adding thread-safety. (mostly work
+ of Sebastian Wilhelmi <wilhelmi@ira.uka.de>)
+
+ - configure.in now looks for a system thread implementation.
+ Currently support is included for POSIX threads
+ and Solaris threads. The default support is built
+ into a separate library -lgthread.
+
+ - The thread implementation can be modified by passing
+ a vector of functions g_thread_init().
+
+ - The default or supplied functions are used to
+ implement a small set of thread functions for
+ mutexes, condition variables, and thread-private
+ data.
+
+ - GLib now uses these functions to provide thread
+ safety. (In the sense that all global static
+ data is locked... individual structures must still
+ be locked by the caller.)
+
Sat Dec 12 19:08:59 1998 Tim Janik <timj@gtk.org>
* configure.in: always define G_HAVE_INLINE if __cplusplus is
diff --git a/ChangeLog.pre-2-6 b/ChangeLog.pre-2-6
index 7d1d0758f..dc3ecadc7 100644
--- a/ChangeLog.pre-2-6
+++ b/ChangeLog.pre-2-6
@@ -1,3 +1,87 @@
+1998-12-11 Sebastian Wilhelmi <wilhelmi@ira.uka.de>
+
+ * gthread/gthread-nspr.c, configure.in: Added new default thread
+ implementation on top of the mozilla nspr library.
+
+ * gmem.c, gmessaged.c, gthread/gthread.c, gthread/gthread-*.c:
+ Changed GStaticMutex and GStaticPrivate in gmem.c and gmessages.c
+ into GMutex and GPrivate resp. to make error reporting and use of
+ gmem possible in most (not all, though) gthread functions. Also
+ initialized the modules via new init functions.
+
+ * configure.in: Fixed syntax bug in definition of type
+ GStaticMutex.
+
+ * gthread/testgthread.c: Updated to work with nspr, but see note
+ there for remaining problems.
+
+1998-12-10 Sebastian Wilhelmi <wilhelmi@ira.uka.de>
+
+ * gmutex.c, glib.h: Now abort, if a mutex/cond/private is
+ allocated before the thread system is set up.
+
+ * gthread/gthread.c (g_thread_init): Removed g_thread_try_init(),
+ as it is not necessary. Changed the error message. Corrected logic
+ for g_thread_use_default_impl.
+
+ * gmutex.c (g_mutex_init): Keep the thread private data array
+ after calling g_thread_init().
+
+1998-12-09 Sebastian Wilhelmi <wilhelmi@ira.uka.de>
+
+ * gthread/testgthread.c (new_thread): Now also working for posix
+ threads; (wait_thread): Now a better implementation, that does not
+ use 100% CPU.
+
+ * Made the thread related code follow GNU coding standard.
+
+ * Made a comment (HOLDS:) above each function, that expects the
+ given locks to be held.
+
+ * Changed try_lock to trylock throughout.
+
+ * glib.c: Eventually removed the #if 0'ed code for old GStaticMutex.
+
+ * glib.c: Corrected g_trylock macro for G_DEBUG_LOCKS.
+
+ * gmain.c (g_main_poll_add_unlocked): first take a new poll record
+ form the poll_free_list.
+
+ * gmem.c, gstrfuncs.c, gutils.c: Made it MT safe.
+
+ * gthraed/*.c: Added copyright headers.
+
+ * gthread/gthread-solaris.c: do not use g_log for errors, as g_log
+ uses these module and endless recursions might happen, just use a
+ plain fprintf(stderr,...).
+
+ * gthread/gthread.c (g_thread_try_init): Call g_mutex_init().
+
+ * gthread/testgthread.c: updated test program.
+
+Tue Dec 8 18:49:56 1998 Owen Taylor <otaylor@redhat.com>
+
+ * Start at adding thread-safety. (mostly work
+ of Sebastian Wilhelmi <wilhelmi@ira.uka.de>)
+
+ - configure.in now looks for a system thread implementation.
+ Currently support is included for POSIX threads
+ and Solaris threads. The default support is built
+ into a separate library -lgthread.
+
+ - The thread implementation can be modified by passing
+ a vector of functions g_thread_init().
+
+ - The default or supplied functions are used to
+ implement a small set of thread functions for
+ mutexes, condition variables, and thread-private
+ data.
+
+ - GLib now uses these functions to provide thread
+ safety. (In the sense that all global static
+ data is locked... individual structures must still
+ be locked by the caller.)
+
Sat Dec 12 19:08:59 1998 Tim Janik <timj@gtk.org>
* configure.in: always define G_HAVE_INLINE if __cplusplus is
diff --git a/ChangeLog.pre-2-8 b/ChangeLog.pre-2-8
index 7d1d0758f..dc3ecadc7 100644
--- a/ChangeLog.pre-2-8
+++ b/ChangeLog.pre-2-8
@@ -1,3 +1,87 @@
+1998-12-11 Sebastian Wilhelmi <wilhelmi@ira.uka.de>
+
+ * gthread/gthread-nspr.c, configure.in: Added new default thread
+ implementation on top of the mozilla nspr library.
+
+ * gmem.c, gmessaged.c, gthread/gthread.c, gthread/gthread-*.c:
+ Changed GStaticMutex and GStaticPrivate in gmem.c and gmessages.c
+ into GMutex and GPrivate resp. to make error reporting and use of
+ gmem possible in most (not all, though) gthread functions. Also
+ initialized the modules via new init functions.
+
+ * configure.in: Fixed syntax bug in definition of type
+ GStaticMutex.
+
+ * gthread/testgthread.c: Updated to work with nspr, but see note
+ there for remaining problems.
+
+1998-12-10 Sebastian Wilhelmi <wilhelmi@ira.uka.de>
+
+ * gmutex.c, glib.h: Now abort, if a mutex/cond/private is
+ allocated before the thread system is set up.
+
+ * gthread/gthread.c (g_thread_init): Removed g_thread_try_init(),
+ as it is not necessary. Changed the error message. Corrected logic
+ for g_thread_use_default_impl.
+
+ * gmutex.c (g_mutex_init): Keep the thread private data array
+ after calling g_thread_init().
+
+1998-12-09 Sebastian Wilhelmi <wilhelmi@ira.uka.de>
+
+ * gthread/testgthread.c (new_thread): Now also working for posix
+ threads; (wait_thread): Now a better implementation, that does not
+ use 100% CPU.
+
+ * Made the thread related code follow GNU coding standard.
+
+ * Made a comment (HOLDS:) above each function, that expects the
+ given locks to be held.
+
+ * Changed try_lock to trylock throughout.
+
+ * glib.c: Eventually removed the #if 0'ed code for old GStaticMutex.
+
+ * glib.c: Corrected g_trylock macro for G_DEBUG_LOCKS.
+
+ * gmain.c (g_main_poll_add_unlocked): first take a new poll record
+ form the poll_free_list.
+
+ * gmem.c, gstrfuncs.c, gutils.c: Made it MT safe.
+
+ * gthraed/*.c: Added copyright headers.
+
+ * gthread/gthread-solaris.c: do not use g_log for errors, as g_log
+ uses these module and endless recursions might happen, just use a
+ plain fprintf(stderr,...).
+
+ * gthread/gthread.c (g_thread_try_init): Call g_mutex_init().
+
+ * gthread/testgthread.c: updated test program.
+
+Tue Dec 8 18:49:56 1998 Owen Taylor <otaylor@redhat.com>
+
+ * Start at adding thread-safety. (mostly work
+ of Sebastian Wilhelmi <wilhelmi@ira.uka.de>)
+
+ - configure.in now looks for a system thread implementation.
+ Currently support is included for POSIX threads
+ and Solaris threads. The default support is built
+ into a separate library -lgthread.
+
+ - The thread implementation can be modified by passing
+ a vector of functions g_thread_init().
+
+ - The default or supplied functions are used to
+ implement a small set of thread functions for
+ mutexes, condition variables, and thread-private
+ data.
+
+ - GLib now uses these functions to provide thread
+ safety. (In the sense that all global static
+ data is locked... individual structures must still
+ be locked by the caller.)
+
Sat Dec 12 19:08:59 1998 Tim Janik <timj@gtk.org>
* configure.in: always define G_HAVE_INLINE if __cplusplus is
diff --git a/Makefile.am b/Makefile.am
index d2a10f588..a06082fa3 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,7 +1,7 @@
## Process this file with automake to produce Makefile.in
# build . first, then SUBDIRS
-SUBDIRS = gmodule docs
+SUBDIRS = gmodule gthread docs
all-recursive-am: all-am
# alpha `automake' supports this better
#SUBDIRS = . gmodule docs
@@ -50,7 +50,8 @@ libglib_la_SOURCES = \
gstring.c \
gstrfuncs.c \
gscanner.c \
- gutils.c
+ gutils.c \
+ gmutex.c
include_HEADERS = \
glib.h
diff --git a/acconfig.h b/acconfig.h
index 93ecd556d..4396f7be4 100644
--- a/acconfig.h
+++ b/acconfig.h
@@ -84,6 +84,8 @@
#undef WIN32
#undef NATIVE_WIN32
+#undef G_THREAD_SOURCE
+
/* #undef PACKAGE */
/* #undef VERSION */
diff --git a/configure.in b/configure.in
index 2a91d1117..6b7fc2a19 100644
--- a/configure.in
+++ b/configure.in
@@ -508,6 +508,155 @@ AC_SUBST(G_MODULE_HAVE_DLERROR)
AC_SUBST(G_MODULE_NEED_USCORE)
AC_SUBST(GLIB_DEBUG_FLAGS)
+
+dnl ***********************
+dnl *** g_thread checks ***
+dnl ***********************
+
+AC_ARG_WITH(threads, [ --with-threads=[none/posix/solaris/nspr] specify a thread implementation to use.],,)
+
+dnl error and warning message
+dnl *************************
+
+THREAD_NO_IMPLEMENTATION="You do not have any known thread system on your
+ computer. glib will not be thread safe on your computer."
+
+THREAD_UNKNOWN_COMPILER="Your compiler is not known, so I cannot
+ determine the necessary compiler options to compile programs
+ which are using threads. Please provide such information."
+
+FLAG_DOES_NOT_WORK="I can't find the MACRO, that enables thread safety on your
+ platform (normaly it's "_REENTRANT"). I'll not use any flag on
+ compilation now, but then your programs might not work.
+ Please provide information on how it is done on your system."
+
+LIBS_NOT_FOUND_1="I can't find the libraries for the thread implementation
+ "
+
+LIBS_NOT_FOUND_2=". Please choose another thread implementation or
+ provide informationon your thread implementation."
+
+dnl determination of thread implementation
+dnl ***************************************
+
+if test x"$with_threads" = x; then
+ case $host in
+ *-*-solaris*)
+ AC_CHECK_LIB(thread,cond_init,with_threads=solaris)
+ ;;
+ esac
+ if test x"$with_threads" = x; then
+ AC_CHECK_LIB(pthread,pthread_cond_init,with_threads=posix)
+ AC_CHECK_LIB(pthreads,pthread_attr_init,with_threads=posix)
+ AC_CHECK_LIB(nspr21,PRP_NewNakedCondVar,with_threads=nspr)
+ fi
+fi
+
+AC_MSG_CHECKING(for thread implementation)
+
+if test x"$with_threads" = x; then
+ with_threads=none
+ AC_MSG_WARN($THREAD_NO_IMPLEMENTATION)
+fi
+
+AC_MSG_RESULT($with_threads)
+
+dnl determination of G_THREAD_LIBS
+dnl ******************************
+
+G_THREAD_LIBS=
+
+case $with_threads in
+ posix)
+ G_THREAD_LIBS=error
+ AC_CHECK_LIB(pthreads,pthread_cond_init,
+ G_THREAD_LIBS="-lpthreads")
+ AC_CHECK_LIB(pthread,pthread_cond_init,
+ G_THREAD_LIBS="-lpthread")
+ ;;
+ solaris)
+ G_THREAD_LIBS=error
+ AC_CHECK_LIB(thread,cond_init,G_THREAD_LIBS="-lthread")
+ # solaris has a broken initializer for mutexes, if we find it,
+ # we will replace it.
+ AC_MSG_CHECKING(for broken solaris mutex initialization)
+ AC_EGREP_CPP([ *begin *{ *0 *, *0 *, *0 *, *0 *, *0 *, *0 *, *0 *, *0 *, *0 *, *0 *, *0 *, *0 *, *0 *, *0 *} *end *],
+ [#include <thread.h>
+ begin DEFAULTMUTEX end],
+ [solaris_mutex_init_broken=yes],
+ [solaris_mutex_init_broken=no])
+ AC_MSG_RESULT($solaris_mutex_init_broken)
+ ;;
+ nspr)
+ AC_CHECK_LIB(nspr21,PRP_NewNakedCondVar,
+ G_THREAD_LIBS="-lnspr21")
+ ;;
+ none)
+ ;;
+ *)
+ G_THREAD_LIBS=error
+ ;;
+esac
+
+if test "x$G_THREAD_LIBS" = xerror; then
+ AC_MSG_ERROR($LIBS_NOT_FOUND_1$with_threads$LIBS_NOT_FOUND_2)
+fi
+
+AC_MSG_CHECKING(necessary linker options)
+AC_MSG_RESULT($G_THREAD_LIBS)
+
+dnl determination of G_THREAD_CFLAGS
+dnl ********************************
+
+if test x"$with_threads" != xnone; then
+ G_THREAD_CFLAGS="-D_REENTRANT" # good default
+
+ case $host in
+ -aix*)
+ # FIXME: can somebody confirm this -D_THREAD_SAFE ???
+ G_THREAD_CFLAGS="$G_THREAD_CFLAGS -D_THREAD_SAFE"
+ if test x"$GCC" = xyes; then
+ G_THREAD_CFLAGS="$G_THREAD_CFLAGS -mthreads"
+ fi
+ ;;
+ esac
+
+ # if we are not finding the ctime_r function, then we probably are
+ # not using the proper multithread flag
+ old_CPPFLAGS=$CPPFLAGS
+ CPPFLAGS="$CPPFLAGS $G_THREAD_CFLAGS"
+ AC_EGREP_HEADER([[^a-zA-Z_]ctime_r[^a-zA-Z_]], time.h, ,
+ G_THREAD_CFLAGS=
+ AC_MSG_WARN($FLAG_DOES_NOT_WORK))
+ CPPFLAGS=$old_CPPFLAGS
+
+ if test x"$GCC" = xyes; then
+ # older gcc's do not know the -fstack-check option and will
+ # stop compiling, so just check this here
+ old_CPPFLAGS="$CPPFLAGS"
+ CPPFLAGS="$CPPFLAGS -fstack-check"
+ AC_TRY_COMPILE(,,
+ G_THREAD_CFLAGS="$G_THREAD_CFLAGS -fstack-check")
+ CPPFLAGS=$old_CPPFLAGS
+ else
+ AC_MSG_WARN($THREAD_UNKNOWN_COMPILER)
+ fi
+
+ AC_MSG_CHECKING(necessary compiler options)
+
+ AC_MSG_RESULT($G_THREAD_CFLAGS)
+else
+ G_THREAD_CFLAGS=
+fi
+
+AC_DEFINE_UNQUOTED(G_THREAD_SOURCE,"gthread-$with_threads.c")
+AC_SUBST(G_THREAD_CFLAGS)
+AC_SUBST(G_THREAD_LIBS)
+
+dnl ******************************
+dnl *** output the whole stuff ***
+dnl ******************************
+
AC_OUTPUT_COMMANDS([
## Generate `glibconfig.h' in two cases
@@ -550,6 +699,9 @@ outfile_EOF
if test x$glib_values_h = xyes; then
echo '#include <values.h>' >> $outfile
fi
+ if test x$g_mutex_header_file != x; then
+ echo '#include <'"$g_mutex_header_file"'>' >> $outfile
+ fi
if test x$glib_sys_poll_h = xyes; then
echo '#include <sys/types.h>' >> $outfile
echo '#include <sys/poll.h>' >> $outfile
@@ -628,6 +780,34 @@ $glib_inline
#define G_BYTE_ORDER $g_byte_order
outfile_EOF
+cat >>$outfile <<outfile_EOF
+
+/* definitions for the default mutex implementation */
+outfile_EOF
+
+ if test x$g_mutex_has_default = xyes; then
+cat >>$outfile <<outfile_EOF
+
+typedef struct _GStaticMutex GStaticMutex;
+struct _GStaticMutex
+{
+ $g_mutex_default_type default_mutex;
+ struct _GMutex* runtime_mutex;
+};
+#define G_STATIC_MUTEX_INIT { $g_mutex_default_init, NULL }
+#define g_static_mutex_get_mutex(mutex) \
+ ( g_thread_use_default_impl ? (GMutex*)&mutex.default_mutex : \
+ g_static_mutex_get_mutex_impl(&mutex.runtime_mutex) )
+outfile_EOF
+ else
+cat >>$outfile <<outfile_EOF
+
+typedef struct _GMutex* GStaticMutex;
+#define G_STATIC_MUTEX_INIT NULL
+#define g_static_mutex_get_mutex(mutex) g_static_mutex_get_mutex_impl(&mutex)
+outfile_EOF
+ fi
+
g_bit_sizes="16 32"
if test -n "$gint64"; then
g_bit_sizes="$g_bit_sizes 64"
@@ -841,6 +1021,31 @@ if test x$glib_working_wctype = xno; then
glib_wc="\$glib_wc
#define G_HAVE_BROKEN_WCTYPE 1"
fi
+
+case $with_threads in
+ posix)
+ g_mutex_has_default=yes
+ g_mutex_default_type='pthread_mutex_t'
+ g_mutex_default_init='PTHREAD_MUTEX_INITIALIZER'
+ g_mutex_header_file='pthread.h'
+ ;;
+ solaris)
+ g_mutex_has_default=yes
+ g_mutex_default_type='mutex_t'
+ if test x$solaris_mutex_init_broken = xyes; then
+ g_mutex_default_init="{ { { 0, 0, 0, 0 }, USYNC_THREAD }, { { { 0, 0, 0, 0, 0, 0, 0, 0 } } }, 0}"
+ else
+ g_mutex_default_init="DEFAULTMUTEX"
+ fi
+ g_mutex_header_file='thread.h'
+ ;;
+ nspr)
+ g_mutex_has_default=no
+ ;;
+ *)
+ g_mutex_has_default=no
+ ;;
+esac
])
AC_OUTPUT([
@@ -848,6 +1053,7 @@ Makefile
glib-config
gmodule/gmoduleconf.h
gmodule/Makefile
+gthread/Makefile
docs/Makefile
],[case "$CONFIG_FILES" in
*glib-config*)chmod +x glib-config;;
diff --git a/garray.c b/garray.c
index 0247972ec..7f0803e3e 100644
--- a/garray.c
+++ b/garray.c
@@ -16,6 +16,11 @@
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
+
+/*
+ * MT safe
+ */
+
#include <string.h>
#include "glib.h"
@@ -40,9 +45,8 @@ static gint g_nearest_pow (gint num);
static void g_array_maybe_expand (GRealArray *array,
gint len);
-
static GMemChunk *array_mem_chunk = NULL;
-
+static G_LOCK_DEFINE(array_mem_chunk);
GArray*
g_array_new (gboolean zero_terminated,
@@ -51,12 +55,14 @@ g_array_new (gboolean zero_terminated,
{
GRealArray *array;
+ g_lock (array_mem_chunk);
if (!array_mem_chunk)
array_mem_chunk = g_mem_chunk_new ("array mem chunk",
sizeof (GRealArray),
1024, G_ALLOC_AND_FREE);
array = g_chunk_new (GRealArray, array_mem_chunk);
+ g_unlock (array_mem_chunk);
array->data = NULL;
array->len = 0;
@@ -75,7 +81,9 @@ g_array_free (GArray *array,
if (free_segment)
g_free (array->data);
+ g_lock (array_mem_chunk);
g_mem_chunk_free (array_mem_chunk, array);
+ g_unlock (array_mem_chunk);
}
GArray*
@@ -241,9 +249,8 @@ struct _GRealPtrArray
static void g_ptr_array_maybe_expand (GRealPtrArray *array,
gint len);
-
static GMemChunk *ptr_array_mem_chunk = NULL;
-
+static G_LOCK_DEFINE(ptr_array_mem_chunk);
GPtrArray*
@@ -251,12 +258,14 @@ g_ptr_array_new (void)
{
GRealPtrArray *array;
+ g_lock (ptr_array_mem_chunk);
if (!ptr_array_mem_chunk)
ptr_array_mem_chunk = g_mem_chunk_new ("array mem chunk",
sizeof (GRealPtrArray),
1024, G_ALLOC_AND_FREE);
array = g_chunk_new (GRealPtrArray, ptr_array_mem_chunk);
+ g_unlock (ptr_array_mem_chunk);
array->pdata = NULL;
array->len = 0;
@@ -274,7 +283,9 @@ g_ptr_array_free (GPtrArray *array,
if (free_segment)
g_free (array->pdata);
+ g_lock (ptr_array_mem_chunk);
g_mem_chunk_free (ptr_array_mem_chunk, array);
+ g_unlock (ptr_array_mem_chunk);
}
static void
diff --git a/gbacktrace.c b/gbacktrace.c
index 6aeb8b517..2615ce2b4 100644
--- a/gbacktrace.c
+++ b/gbacktrace.c
@@ -17,6 +17,11 @@
* Boston, MA 02111-1307, USA.
*/
+/*
+ * MT safe ; except for g_on_error_stack_trace, but who wants thread safety
+ * then
+ */
+
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
diff --git a/gcache.c b/gcache.c
index b2fe77910..800bb2b13 100644
--- a/gcache.c
+++ b/gcache.c
@@ -16,6 +16,11 @@
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
+
+/*
+ * MT safe
+ */
+
#include "glib.h"
@@ -56,7 +61,7 @@ static void g_cache_node_destroy (GCacheNode *node);
static GMemChunk *node_mem_chunk = NULL;
-
+static G_LOCK_DEFINE(node_mem_chunk);
GCache*
g_cache_new (GCacheNewFunc value_new_func,
@@ -193,11 +198,13 @@ g_cache_node_new (gpointer value)
{
GCacheNode *node;
+ g_lock (node_mem_chunk);
if (!node_mem_chunk)
node_mem_chunk = g_mem_chunk_new ("cache node mem chunk", sizeof (GCacheNode),
1024, G_ALLOC_AND_FREE);
node = g_chunk_new (GCacheNode, node_mem_chunk);
+ g_unlock (node_mem_chunk);
node->value = value;
node->ref_count = 1;
@@ -208,5 +215,7 @@ g_cache_node_new (gpointer value)
static void
g_cache_node_destroy (GCacheNode *node)
{
+ g_lock (node_mem_chunk);
g_mem_chunk_free (node_mem_chunk, node);
+ g_unlock (node_mem_chunk);
}
diff --git a/gcompletion.c b/gcompletion.c
index 62ec244bc..cba2a86cb 100644
--- a/gcompletion.c
+++ b/gcompletion.c
@@ -17,6 +17,10 @@
* Boston, MA 02111-1307, USA.
*/
+/*
+ * MT safe
+ */
+
#include "glib.h"
#include <string.h>
diff --git a/gdataset.c b/gdataset.c
index 7dafc2191..f22b21d59 100644
--- a/gdataset.c
+++ b/gdataset.c
@@ -18,6 +18,12 @@
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
*/
+
+/*
+ * MT safe ; FIXME: might still freeze, watch out, not thoroughly
+ * looked at yet.
+ */
+
#include <string.h>
#include "glib.h"
@@ -61,18 +67,24 @@ static inline GQuark g_quark_new (gchar *string);
/* --- variables --- */
+static G_LOCK_DEFINE(g_dataset_global);
static GHashTable *g_dataset_location_ht = NULL;
-static GDataset *g_dataset_cached = NULL;
+static GDataset *g_dataset_cached = NULL; /* should this be
+ threadspecific? */
static GMemChunk *g_dataset_mem_chunk = NULL;
static GMemChunk *g_data_mem_chunk = NULL;
static GData *g_data_cache = NULL;
static guint g_data_cache_length = 0;
+
+static G_LOCK_DEFINE(g_quark_global);
static GHashTable *g_quark_ht = NULL;
static gchar **g_quarks = NULL;
static GQuark g_quark_seq_id = 0;
/* --- functions --- */
+
+/* HOLDS: g_dataset_global_lock */
static inline void
g_datalist_clear_i (GData **datalist)
{
@@ -109,13 +121,16 @@ g_datalist_clear (GData **datalist)
{
g_return_if_fail (datalist != NULL);
+ g_lock (g_dataset_global);
if (!g_dataset_location_ht)
g_data_initialize ();
while (*datalist)
g_datalist_clear_i (datalist);
+ g_unlock (g_dataset_global);
}
+/* HOLDS: g_dataset_global_lock */
static inline GDataset*
g_dataset_lookup (gconstpointer dataset_location)
{
@@ -131,6 +146,7 @@ g_dataset_lookup (gconstpointer dataset_location)
return dataset;
}
+/* HOLDS: g_dataset_global_lock */
static void
g_dataset_destroy_internal (GDataset *dataset)
{
@@ -158,6 +174,7 @@ g_dataset_destroy (gconstpointer dataset_location)
{
g_return_if_fail (dataset_location != NULL);
+ g_lock (g_dataset_global);
if (g_dataset_location_ht)
{
register GDataset *dataset;
@@ -166,8 +183,10 @@ g_dataset_destroy (gconstpointer dataset_location)
if (dataset)
g_dataset_destroy_internal (dataset);
}
+ g_unlock (g_dataset_global);
}
+/* HOLDS: g_dataset_global_lock */
static inline void
g_data_set_internal (GData **datalist,
GQuark key_id,
@@ -293,9 +312,10 @@ g_dataset_id_set_data_full (gconstpointer dataset_location,
return;
}
+ g_lock (g_dataset_global);
if (!g_dataset_location_ht)
g_data_initialize ();
-
+
dataset = g_dataset_lookup (dataset_location);
if (!dataset)
{
@@ -308,6 +328,7 @@ g_dataset_id_set_data_full (gconstpointer dataset_location,
}
g_data_set_internal (&dataset->datalist, key_id, data, destroy_func, dataset);
+ g_unlock (g_dataset_global);
}
void
@@ -327,10 +348,12 @@ g_datalist_id_set_data_full (GData **datalist,
return;
}
+ g_lock (g_dataset_global);
if (!g_dataset_location_ht)
g_data_initialize ();
g_data_set_internal (datalist, key_id, data, destroy_func, NULL);
+ g_unlock (g_dataset_global);
}
void
@@ -339,6 +362,7 @@ g_dataset_id_remove_no_notify (gconstpointer dataset_location,
{
g_return_if_fail (dataset_location != NULL);
+ g_lock (g_dataset_global);
if (key_id && g_dataset_location_ht)
{
GDataset *dataset;
@@ -346,7 +370,8 @@ g_dataset_id_remove_no_notify (gconstpointer dataset_location,
dataset = g_dataset_lookup (dataset_location);
if (dataset)
g_data_set_internal (&dataset->datalist, key_id, NULL, (GDestroyNotify) 42, dataset);
- }
+ }
+ g_unlock (g_dataset_global);
}
void
@@ -355,8 +380,10 @@ g_datalist_id_remove_no_notify (GData **datalist,
{
g_return_if_fail (datalist != NULL);
+ g_lock (g_dataset_global);
if (key_id && g_dataset_location_ht)
g_data_set_internal (datalist, key_id, NULL, (GDestroyNotify) 42, NULL);
+ g_unlock (g_dataset_global);
}
gpointer
@@ -365,6 +392,7 @@ g_dataset_id_get_data (gconstpointer dataset_location,
{
g_return_val_if_fail (dataset_location != NULL, NULL);
+ g_lock (g_dataset_global);
if (key_id && g_dataset_location_ht)
{
register GDataset *dataset;
@@ -376,10 +404,14 @@ g_dataset_id_get_data (gconstpointer dataset_location,
for (list = dataset->datalist; list; list = list->next)
if (list->id == key_id)
- return list->data;
+ {
+ g_unlock (g_dataset_global);
+ return list->data;
+ }
}
}
-
+ g_unlock (g_dataset_global);
+
return NULL;
}
@@ -411,17 +443,23 @@ g_dataset_foreach (gconstpointer dataset_location,
g_return_if_fail (dataset_location != NULL);
g_return_if_fail (func != NULL);
+ g_lock (g_dataset_global);
if (g_dataset_location_ht)
{
dataset = g_dataset_lookup (dataset_location);
+ g_unlock (g_dataset_global);
if (dataset)
{
register GData *list;
for (list = dataset->datalist; list; list = list->next)
- func (list->id, list->data, user_data);
+ func (list->id, list->data, user_data);
}
}
+ else
+ {
+ g_unlock (g_dataset_global);
+ }
}
void
@@ -446,6 +484,7 @@ g_datalist_init (GData **datalist)
*datalist = NULL;
}
+/* HOLDS: g_dataset_global_lock */
static void
g_data_initialize (void)
{
@@ -468,12 +507,15 @@ g_data_initialize (void)
GQuark
g_quark_try_string (const gchar *string)
{
+ GQuark quark = 0;
g_return_val_if_fail (string != NULL, 0);
+ g_lock (g_quark_global);
if (g_quark_ht)
- return (gulong) g_hash_table_lookup (g_quark_ht, string);
- else
- return 0;
+ quark = GPOINTER_TO_UINT (g_hash_table_lookup (g_quark_ht, string));
+ g_unlock (g_quark_global);
+
+ return quark;
}
GQuark
@@ -483,6 +525,7 @@ g_quark_from_string (const gchar *string)
g_return_val_if_fail (string != NULL, 0);
+ g_lock (g_quark_global);
if (g_quark_ht)
quark = (gulong) g_hash_table_lookup (g_quark_ht, string);
else
@@ -493,6 +536,7 @@ g_quark_from_string (const gchar *string)
if (!quark)
quark = g_quark_new (g_strdup (string));
+ g_unlock (g_quark_global);
return quark;
}
@@ -504,6 +548,7 @@ g_quark_from_static_string (const gchar *string)
g_return_val_if_fail (string != NULL, 0);
+ g_lock (g_quark_global);
if (g_quark_ht)
quark = (gulong) g_hash_table_lookup (g_quark_ht, string);
else
@@ -514,19 +559,24 @@ g_quark_from_static_string (const gchar *string)
if (!quark)
quark = g_quark_new ((gchar*) string);
-
+ g_unlock (g_quark_global);
+
return quark;
}
gchar*
g_quark_to_string (GQuark quark)
{
+ gchar* result = NULL;
+ g_lock (g_quark_global);
if (quark > 0 && quark <= g_quark_seq_id)
- return g_quarks[quark - 1];
- else
- return NULL;
+ result = g_quarks[quark - 1];
+ g_unlock (g_quark_global);
+
+ return result;
}
+/* HOLDS: g_quark_global_lock */
static inline GQuark
g_quark_new (gchar *string)
{
diff --git a/gdate.c b/gdate.c
index 69c337def..7c60e23d9 100644
--- a/gdate.c
+++ b/gdate.c
@@ -16,6 +16,11 @@
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
+
+/*
+ * MT safe
+ */
+
#include "glib.h"
#include <time.h>
@@ -383,6 +388,8 @@ g_date_clear (GDate *d, guint ndates)
memset (d, 0x0, ndates*sizeof (GDate));
}
+static G_LOCK_DEFINE(g_date_global);
+
/* These are for the parser, output to the user should use *
* g_date_strftime () - this creates more never-freed memory to annoy
* all those memory debugger users. :-)
@@ -429,6 +436,7 @@ typedef struct _GDateParseTokens GDateParseTokens;
#define NUM_LEN 10
+/* HOLDS: g_date_global_lock */
static void
g_date_fill_parse_tokens (const gchar *str, GDateParseTokens *pt)
{
@@ -488,7 +496,7 @@ g_date_fill_parse_tokens (const gchar *str, GDateParseTokens *pt)
if (found != NULL)
{
pt->month = i;
- return;
+ return;
}
}
@@ -502,12 +510,13 @@ g_date_fill_parse_tokens (const gchar *str, GDateParseTokens *pt)
return;
}
}
-
+
++i;
- }
+ }
}
}
+/* HOLDS: g_date_global_lock */
static void
g_date_prepare_to_parse (const gchar *str, GDateParseTokens *pt)
{
@@ -641,6 +650,8 @@ g_date_set_parse (GDate *d,
/* set invalid */
g_date_clear (d, 1);
+ g_lock (g_date_global);
+
g_date_prepare_to_parse (str, &pt);
#ifdef G_ENABLE_DEBUG
@@ -649,7 +660,11 @@ g_date_set_parse (GDate *d,
#endif
- if (pt.num_ints == 4) return; /* presumably a typo; bail out. */
+ if (pt.num_ints == 4)
+ {
+ g_unlock (g_date_global);
+ return; /* presumably a typo; bail out. */
+ }
if (pt.num_ints > 1)
{
@@ -765,6 +780,7 @@ g_date_set_parse (GDate *d,
else
g_message ("Rejected DMY %u %u %u", day, m, y);
#endif
+ g_unlock (g_date_global);
}
void
diff --git a/gerror.c b/gerror.c
index 6aeb8b517..2615ce2b4 100644
--- a/gerror.c
+++ b/gerror.c
@@ -17,6 +17,11 @@
* Boston, MA 02111-1307, USA.
*/
+/*
+ * MT safe ; except for g_on_error_stack_trace, but who wants thread safety
+ * then
+ */
+
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
diff --git a/ghash.c b/ghash.c
index 4ab82b3fa..724036388 100644
--- a/ghash.c
+++ b/ghash.c
@@ -16,6 +16,11 @@
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
+
+/*
+ * MT safe
+ */
+
#include "glib.h"
@@ -52,6 +57,8 @@ static void g_hash_node_destroy (GHashNode *hash_node);
static void g_hash_nodes_destroy (GHashNode *hash_node);
+static G_LOCK_DEFINE(g_hash_global);
+
static GMemChunk *node_mem_chunk = NULL;
static GHashNode *node_free_list = NULL;
@@ -338,6 +345,7 @@ g_hash_node_new (gpointer key,
{
GHashNode *hash_node;
+ g_lock (g_hash_global);
if (node_free_list)
{
hash_node = node_free_list;
@@ -352,6 +360,7 @@ g_hash_node_new (gpointer key,
hash_node = g_chunk_new (GHashNode, node_mem_chunk);
}
+ g_unlock (g_hash_global);
hash_node->key = key;
hash_node->value = value;
@@ -363,8 +372,10 @@ g_hash_node_new (gpointer key,
static void
g_hash_node_destroy (GHashNode *hash_node)
{
+ g_lock (g_hash_global);
hash_node->next = node_free_list;
node_free_list = hash_node;
+ g_unlock (g_hash_global);
}
static void
@@ -380,6 +391,8 @@ g_hash_nodes_destroy (GHashNode *hash_node)
while (node->next)
node = node->next;
+ g_lock (g_hash_global);
node->next = node_free_list;
node_free_list = hash_node;
+ g_unlock (g_hash_global);
}
diff --git a/ghook.c b/ghook.c
index 47a2874a4..b683b7c31 100644
--- a/ghook.c
+++ b/ghook.c
@@ -19,6 +19,11 @@
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
+
+/*
+ * MT safe
+ */
+
#include "glib.h"
diff --git a/giochannel.c b/giochannel.c
index fa4262602..0693a084b 100644
--- a/giochannel.c
+++ b/giochannel.c
@@ -20,6 +20,10 @@
* Boston, MA 02111-1307, USA.
*/
+/*
+ * MT safe
+ */
+
#include "glib.h"
#include <unistd.h>
diff --git a/giounix.c b/giounix.c
index 5e605a478..82944be89 100644
--- a/giounix.c
+++ b/giounix.c
@@ -20,6 +20,10 @@
* Boston, MA 02111-1307, USA.
*/
+/*
+ * MT safe
+ */
+
#include "glib.h"
#include <sys/types.h>
#include <unistd.h>
diff --git a/glib-config.in b/glib-config.in
index a3b264c13..36192c9c9 100644
--- a/glib-config.in
+++ b/glib-config.in
@@ -17,6 +17,7 @@ Options:
Libraries:
glib
gmodule
+ gthread
EOF
exit $1
}
@@ -69,6 +70,9 @@ while test $# -gt 0; do
gmodule)
lib_gmodule=yes
;;
+ gthread)
+ lib_gthread=yes
+ ;;
*)
usage 1 1>&2
;;
@@ -83,7 +87,11 @@ if test "$echo_exec_prefix" = "yes"; then
echo $exec_prefix
fi
if test "$echo_cflags" = "yes"; then
- echo -I@libdir@/glib/include $includes
+ cflags=""
+ if test "$lib_gthread" = "yes"; then
+ cflags="$cflags @G_THREAD_CFLAGS@"
+ fi
+ echo -I@libdir@/glib/include $includes $cflags
fi
if test "$echo_libs" = "yes"; then
libs=""
@@ -93,5 +101,8 @@ if test "$echo_libs" = "yes"; then
if test "$lib_gmodule" = "yes"; then
libs="@G_MODULE_LDFLAGS@ -lgmodule $libs @G_MODULE_LIBS@"
fi
- echo "-L@libdir@ $libs"
+ if test "$lib_gthread" = "yes"; then
+ libs="-lgthread $libs @G_THREAD_LIBS@"
+ fi
+ echo -L@libdir@ $libs
fi
diff --git a/glib.h b/glib.h
index 33fa042e9..d4d1aaa77 100644
--- a/glib.h
+++ b/glib.h
@@ -2597,6 +2597,140 @@ gint gwin_closedir (DIR *dir);
#endif /* NATIVE_WIN32 */
+/* functions for thread support for glib. */
+
+typedef struct _GMutex GMutex;
+typedef struct _GCond GCond;
+typedef struct _GPrivate GPrivate;
+typedef struct _GStaticPrivate GStaticPrivate;
+
+typedef struct _GThreadFunctions GThreadFunctions;
+struct _GThreadFunctions
+{
+ GMutex* (*mutex_new) (void);
+ void (*mutex_lock) (GMutex* mutex);
+ gboolean (*mutex_trylock) (GMutex* mutex);
+ void (*mutex_unlock) (GMutex* mutex);
+ void (*mutex_free) (GMutex* mutex);
+ GCond* (*cond_new) (void);
+ void (*cond_signal) (GCond* cond);
+ void (*cond_broadcast) (GCond* cond);
+ void (*cond_wait) (GCond* cond, GMutex* mutex);
+ gboolean (*cond_timed_wait) (GCond* cond, GMutex* mutex,
+ GTimeVal *end_time);
+ void (*cond_free) (GCond* cond);
+ GPrivate* (*private_new) (GDestroyNotify destructor);
+ gpointer (*private_get) (GPrivate* private);
+ void (*private_set) (GPrivate* private, gpointer value);
+};
+
+GUTILS_C_VAR GThreadFunctions g_thread_functions_for_glib_use;
+GUTILS_C_VAR gboolean g_thread_use_default_impl;
+GUTILS_C_VAR gboolean g_thread_supported;
+
+/* initializes the mutex/cond/private implementation for glib, might
+ * only be called once, and must not be called directly or indirectly
+ * from another glib-function, e.g. as a callback. */
+void g_thread_init(GThreadFunctions* init);
+
+/* Internal functions for fallback static mutex implementation
+ * Please don't use it directly
+ */
+GMutex* g_static_mutex_get_mutex_impl(GMutex** mutex);
+
+#define G_USE_THREAD_FUNC_UNCOND(name,arg) \
+ (*g_thread_functions_for_glib_use.name)arg
+#define G_USE_THREAD_FUNC(name,fail,arg) \
+ (g_thread_supported ? G_USE_THREAD_FUNC_UNCOND(name,arg) : (fail))
+
+/* keep in mind, all those mutexes and static mutexes are not
+ * recursive in general, don't rely on that */
+#define g_mutex_new() G_USE_THREAD_FUNC_UNCOND(mutex_new,())
+#define g_mutex_lock(mutex) G_USE_THREAD_FUNC(mutex_lock,(void)0,(mutex))
+#define g_mutex_trylock(mutex) G_USE_THREAD_FUNC(mutex_trylock,TRUE,(mutex))
+#define g_mutex_unlock(mutex) G_USE_THREAD_FUNC(mutex_unlock,(void)0,(mutex))
+#define g_mutex_free(mutex) G_USE_THREAD_FUNC(mutex_free,(void)0,(mutex))
+#define g_cond_new() G_USE_THREAD_FUNC_UNCOND(cond_new,())
+#define g_cond_signal(cond) G_USE_THREAD_FUNC(cond_signal,(void)0,(cond))
+#define g_cond_broadcast(cond) G_USE_THREAD_FUNC(cond_broadcast,(void)0,(cond))
+#define g_cond_wait(cond,mutex) G_USE_THREAD_FUNC(cond_wait,(void)0,(cond,mutex))
+#define g_cond_timed_wait(cond,mutex,abs_time) \
+ G_USE_THREAD_FUNC(cond_timed_wait,TRUE,(cond,mutex,abs_time))
+#define g_cond_free(cond) G_USE_THREAD_FUNC(cond_free,(void)0,(cond))
+
+#define g_private_new(destructor) \
+ G_USE_THREAD_FUNC_UNCOND(private_new,(destructor))
+#define g_private_get(private) \
+ G_USE_THREAD_FUNC(private_get,((gpointer)private),(private))
+#define g_private_set(private,value) \
+ G_USE_THREAD_FUNC(private_set,(void)(private=(GPrivate *)(value)), \
+ (private,value))
+
+/* GStaticMutex'es can be statically initialized with the value
+ * G_STATIC_MUTEX_INIT, and then they can directly be used, that is
+ * much easier, than having to explicitly allocate the mutex before
+ * use */
+#define g_static_mutex_lock(mutex) \
+ g_mutex_lock( g_static_mutex_get_mutex(mutex) )
+#define g_static_mutex_trylock(mutex) \
+ g_mutex_trylock( g_static_mutex_get_mutex(mutex) )
+#define g_static_mutex_unlock(mutex) \
+ g_mutex_unlock( g_static_mutex_get_mutex(mutex) )
+
+struct _GStaticPrivate
+{
+ guint index;
+};
+
+#define G_STATIC_PRIVATE_INIT { 0 }
+
+gpointer g_static_private_get (GStaticPrivate* private);
+void g_static_private_set (GStaticPrivate *private,
+ gpointer data,
+ GDestroyNotify notify);
+
+/* these are some convenience macros, for using StaticMutex'es, you
+ * define them by G_LOCK_DEFINE(name), where name could for example be the
+ * name of the protected varibale, and you (un)lock them with
+ * g_(un)lock(name) */
+#define g_lock_name(name) (name ## _lock)
+#define G_LOCK_DEFINE(name) GStaticMutex g_lock_name(name)=G_STATIC_MUTEX_INIT
+
+#ifdef G_DEBUG_LOCKS
+#define g_lock(name) G_STMT_START{ \
+ g_log (G_LOG_DOMAIN, \
+ G_LOG_LEVEL_MESSAGE, \
+ "file %s: line %d (%s): locking: %s ", \
+ __FILE__, \
+ __LINE__, \
+ __PRETTY_FUNCTION__, \
+ #name); \
+ g_static_mutex_lock(g_lock_name(name)); \
+ }G_STMT_END
+#define g_unlock(name) G_STMT_START{ \
+ g_log (G_LOG_DOMAIN, \
+ G_LOG_LEVEL_MESSAGE, \
+ "file %s: line %d (%s): unlocking: %s ", \
+ __FILE__, \
+ __LINE__, \
+ __PRETTY_FUNCTION__, \
+ #name); \
+ g_static_mutex_unlock(g_lock_name(name)); \
+ }G_STMT_END
+#define g_trylock(name) G_STMT_START{ \
+ g_log (G_LOG_DOMAIN, \
+ G_LOG_LEVEL_MESSAGE, \
+ "file %s: line %d (%s): try locking: %s ", \
+ __FILE__, \
+ __LINE__, \
+ __PRETTY_FUNCTION__, \
+ #name); \
+ }G_STMT_END, g_static_mutex_trylock(g_lock_name(name))
+#else /* !G_DEBUG_LOCKS */
+#define g_lock(name) g_static_mutex_lock(g_lock_name(name))
+#define g_unlock(name) g_static_mutex_unlock(g_lock_name(name))
+#define g_trylock(name) g_static_mutex_trylock(g_lock_name(name))
+#endif
#ifdef __cplusplus
}
diff --git a/glib/Makefile.am b/glib/Makefile.am
index d2a10f588..a06082fa3 100644
--- a/glib/Makefile.am
+++ b/glib/Makefile.am
@@ -1,7 +1,7 @@
## Process this file with automake to produce Makefile.in
# build . first, then SUBDIRS
-SUBDIRS = gmodule docs
+SUBDIRS = gmodule gthread docs
all-recursive-am: all-am
# alpha `automake' supports this better
#SUBDIRS = . gmodule docs
@@ -50,7 +50,8 @@ libglib_la_SOURCES = \
gstring.c \
gstrfuncs.c \
gscanner.c \
- gutils.c
+ gutils.c \
+ gmutex.c
include_HEADERS = \
glib.h
diff --git a/glib/garray.c b/glib/garray.c
index 0247972ec..7f0803e3e 100644
--- a/glib/garray.c
+++ b/glib/garray.c
@@ -16,6 +16,11 @@
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
+
+/*
+ * MT safe
+ */
+
#include <string.h>
#include "glib.h"
@@ -40,9 +45,8 @@ static gint g_nearest_pow (gint num);
static void g_array_maybe_expand (GRealArray *array,
gint len);
-
static GMemChunk *array_mem_chunk = NULL;
-
+static G_LOCK_DEFINE(array_mem_chunk);
GArray*
g_array_new (gboolean zero_terminated,
@@ -51,12 +55,14 @@ g_array_new (gboolean zero_terminated,
{
GRealArray *array;
+ g_lock (array_mem_chunk);
if (!array_mem_chunk)
array_mem_chunk = g_mem_chunk_new ("array mem chunk",
sizeof (GRealArray),
1024, G_ALLOC_AND_FREE);
array = g_chunk_new (GRealArray, array_mem_chunk);
+ g_unlock (array_mem_chunk);
array->data = NULL;
array->len = 0;
@@ -75,7 +81,9 @@ g_array_free (GArray *array,
if (free_segment)
g_free (array->data);
+ g_lock (array_mem_chunk);
g_mem_chunk_free (array_mem_chunk, array);
+ g_unlock (array_mem_chunk);
}
GArray*
@@ -241,9 +249,8 @@ struct _GRealPtrArray
static void g_ptr_array_maybe_expand (GRealPtrArray *array,
gint len);
-
static GMemChunk *ptr_array_mem_chunk = NULL;
-
+static G_LOCK_DEFINE(ptr_array_mem_chunk);
GPtrArray*
@@ -251,12 +258,14 @@ g_ptr_array_new (void)
{
GRealPtrArray *array;
+ g_lock (ptr_array_mem_chunk);
if (!ptr_array_mem_chunk)
ptr_array_mem_chunk = g_mem_chunk_new ("array mem chunk",
sizeof (GRealPtrArray),
1024, G_ALLOC_AND_FREE);
array = g_chunk_new (GRealPtrArray, ptr_array_mem_chunk);
+ g_unlock (ptr_array_mem_chunk);
array->pdata = NULL;
array->len = 0;
@@ -274,7 +283,9 @@ g_ptr_array_free (GPtrArray *array,
if (free_segment)
g_free (array->pdata);
+ g_lock (ptr_array_mem_chunk);
g_mem_chunk_free (ptr_array_mem_chunk, array);
+ g_unlock (ptr_array_mem_chunk);
}
static void
diff --git a/glib/gbacktrace.c b/glib/gbacktrace.c
index 6aeb8b517..2615ce2b4 100644
--- a/glib/gbacktrace.c
+++ b/glib/gbacktrace.c
@@ -17,6 +17,11 @@
* Boston, MA 02111-1307, USA.
*/
+/*
+ * MT safe ; except for g_on_error_stack_trace, but who wants thread safety
+ * then
+ */
+
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
diff --git a/glib/gcache.c b/glib/gcache.c
index b2fe77910..800bb2b13 100644
--- a/glib/gcache.c
+++ b/glib/gcache.c
@@ -16,6 +16,11 @@
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
+
+/*
+ * MT safe
+ */
+
#include "glib.h"
@@ -56,7 +61,7 @@ static void g_cache_node_destroy (GCacheNode *node);
static GMemChunk *node_mem_chunk = NULL;
-
+static G_LOCK_DEFINE(node_mem_chunk);
GCache*
g_cache_new (GCacheNewFunc value_new_func,
@@ -193,11 +198,13 @@ g_cache_node_new (gpointer value)
{
GCacheNode *node;
+ g_lock (node_mem_chunk);
if (!node_mem_chunk)
node_mem_chunk = g_mem_chunk_new ("cache node mem chunk", sizeof (GCacheNode),
1024, G_ALLOC_AND_FREE);
node = g_chunk_new (GCacheNode, node_mem_chunk);
+ g_unlock (node_mem_chunk);
node->value = value;
node->ref_count = 1;
@@ -208,5 +215,7 @@ g_cache_node_new (gpointer value)
static void
g_cache_node_destroy (GCacheNode *node)
{
+ g_lock (node_mem_chunk);
g_mem_chunk_free (node_mem_chunk, node);
+ g_unlock (node_mem_chunk);
}
diff --git a/glib/gcompletion.c b/glib/gcompletion.c
index 62ec244bc..cba2a86cb 100644
--- a/glib/gcompletion.c
+++ b/glib/gcompletion.c
@@ -17,6 +17,10 @@
* Boston, MA 02111-1307, USA.
*/
+/*
+ * MT safe
+ */
+
#include "glib.h"
#include <string.h>
diff --git a/glib/gdataset.c b/glib/gdataset.c
index 7dafc2191..f22b21d59 100644
--- a/glib/gdataset.c
+++ b/glib/gdataset.c
@@ -18,6 +18,12 @@
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
*/
+
+/*
+ * MT safe ; FIXME: might still freeze, watch out, not thoroughly
+ * looked at yet.
+ */
+
#include <string.h>
#include "glib.h"
@@ -61,18 +67,24 @@ static inline GQuark g_quark_new (gchar *string);
/* --- variables --- */
+static G_LOCK_DEFINE(g_dataset_global);
static GHashTable *g_dataset_location_ht = NULL;
-static GDataset *g_dataset_cached = NULL;
+static GDataset *g_dataset_cached = NULL; /* should this be
+ threadspecific? */
static GMemChunk *g_dataset_mem_chunk = NULL;
static GMemChunk *g_data_mem_chunk = NULL;
static GData *g_data_cache = NULL;
static guint g_data_cache_length = 0;
+
+static G_LOCK_DEFINE(g_quark_global);
static GHashTable *g_quark_ht = NULL;
static gchar **g_quarks = NULL;
static GQuark g_quark_seq_id = 0;
/* --- functions --- */
+
+/* HOLDS: g_dataset_global_lock */
static inline void
g_datalist_clear_i (GData **datalist)
{
@@ -109,13 +121,16 @@ g_datalist_clear (GData **datalist)
{
g_return_if_fail (datalist != NULL);
+ g_lock (g_dataset_global);
if (!g_dataset_location_ht)
g_data_initialize ();
while (*datalist)
g_datalist_clear_i (datalist);
+ g_unlock (g_dataset_global);
}
+/* HOLDS: g_dataset_global_lock */
static inline GDataset*
g_dataset_lookup (gconstpointer dataset_location)
{
@@ -131,6 +146,7 @@ g_dataset_lookup (gconstpointer dataset_location)
return dataset;
}
+/* HOLDS: g_dataset_global_lock */
static void
g_dataset_destroy_internal (GDataset *dataset)
{
@@ -158,6 +174,7 @@ g_dataset_destroy (gconstpointer dataset_location)
{
g_return_if_fail (dataset_location != NULL);
+ g_lock (g_dataset_global);
if (g_dataset_location_ht)
{
register GDataset *dataset;
@@ -166,8 +183,10 @@ g_dataset_destroy (gconstpointer dataset_location)
if (dataset)
g_dataset_destroy_internal (dataset);
}
+ g_unlock (g_dataset_global);
}
+/* HOLDS: g_dataset_global_lock */
static inline void
g_data_set_internal (GData **datalist,
GQuark key_id,
@@ -293,9 +312,10 @@ g_dataset_id_set_data_full (gconstpointer dataset_location,
return;
}
+ g_lock (g_dataset_global);
if (!g_dataset_location_ht)
g_data_initialize ();
-
+
dataset = g_dataset_lookup (dataset_location);
if (!dataset)
{
@@ -308,6 +328,7 @@ g_dataset_id_set_data_full (gconstpointer dataset_location,
}
g_data_set_internal (&dataset->datalist, key_id, data, destroy_func, dataset);
+ g_unlock (g_dataset_global);
}
void
@@ -327,10 +348,12 @@ g_datalist_id_set_data_full (GData **datalist,
return;
}
+ g_lock (g_dataset_global);
if (!g_dataset_location_ht)
g_data_initialize ();
g_data_set_internal (datalist, key_id, data, destroy_func, NULL);
+ g_unlock (g_dataset_global);
}
void
@@ -339,6 +362,7 @@ g_dataset_id_remove_no_notify (gconstpointer dataset_location,
{
g_return_if_fail (dataset_location != NULL);
+ g_lock (g_dataset_global);
if (key_id && g_dataset_location_ht)
{
GDataset *dataset;
@@ -346,7 +370,8 @@ g_dataset_id_remove_no_notify (gconstpointer dataset_location,
dataset = g_dataset_lookup (dataset_location);
if (dataset)
g_data_set_internal (&dataset->datalist, key_id, NULL, (GDestroyNotify) 42, dataset);
- }
+ }
+ g_unlock (g_dataset_global);
}
void
@@ -355,8 +380,10 @@ g_datalist_id_remove_no_notify (GData **datalist,
{
g_return_if_fail (datalist != NULL);
+ g_lock (g_dataset_global);
if (key_id && g_dataset_location_ht)
g_data_set_internal (datalist, key_id, NULL, (GDestroyNotify) 42, NULL);
+ g_unlock (g_dataset_global);
}
gpointer
@@ -365,6 +392,7 @@ g_dataset_id_get_data (gconstpointer dataset_location,
{
g_return_val_if_fail (dataset_location != NULL, NULL);
+ g_lock (g_dataset_global);
if (key_id && g_dataset_location_ht)
{
register GDataset *dataset;
@@ -376,10 +404,14 @@ g_dataset_id_get_data (gconstpointer dataset_location,
for (list = dataset->datalist; list; list = list->next)
if (list->id == key_id)
- return list->data;
+ {
+ g_unlock (g_dataset_global);
+ return list->data;
+ }
}
}
-
+ g_unlock (g_dataset_global);
+
return NULL;
}
@@ -411,17 +443,23 @@ g_dataset_foreach (gconstpointer dataset_location,
g_return_if_fail (dataset_location != NULL);
g_return_if_fail (func != NULL);
+ g_lock (g_dataset_global);
if (g_dataset_location_ht)
{
dataset = g_dataset_lookup (dataset_location);
+ g_unlock (g_dataset_global);
if (dataset)
{
register GData *list;
for (list = dataset->datalist; list; list = list->next)
- func (list->id, list->data, user_data);
+ func (list->id, list->data, user_data);
}
}
+ else
+ {
+ g_unlock (g_dataset_global);
+ }
}
void
@@ -446,6 +484,7 @@ g_datalist_init (GData **datalist)
*datalist = NULL;
}
+/* HOLDS: g_dataset_global_lock */
static void
g_data_initialize (void)
{
@@ -468,12 +507,15 @@ g_data_initialize (void)
GQuark
g_quark_try_string (const gchar *string)
{
+ GQuark quark = 0;
g_return_val_if_fail (string != NULL, 0);
+ g_lock (g_quark_global);
if (g_quark_ht)
- return (gulong) g_hash_table_lookup (g_quark_ht, string);
- else
- return 0;
+ quark = GPOINTER_TO_UINT (g_hash_table_lookup (g_quark_ht, string));
+ g_unlock (g_quark_global);
+
+ return quark;
}
GQuark
@@ -483,6 +525,7 @@ g_quark_from_string (const gchar *string)
g_return_val_if_fail (string != NULL, 0);
+ g_lock (g_quark_global);
if (g_quark_ht)
quark = (gulong) g_hash_table_lookup (g_quark_ht, string);
else
@@ -493,6 +536,7 @@ g_quark_from_string (const gchar *string)
if (!quark)
quark = g_quark_new (g_strdup (string));
+ g_unlock (g_quark_global);
return quark;
}
@@ -504,6 +548,7 @@ g_quark_from_static_string (const gchar *string)
g_return_val_if_fail (string != NULL, 0);
+ g_lock (g_quark_global);
if (g_quark_ht)
quark = (gulong) g_hash_table_lookup (g_quark_ht, string);
else
@@ -514,19 +559,24 @@ g_quark_from_static_string (const gchar *string)
if (!quark)
quark = g_quark_new ((gchar*) string);
-
+ g_unlock (g_quark_global);
+
return quark;
}
gchar*
g_quark_to_string (GQuark quark)
{
+ gchar* result = NULL;
+ g_lock (g_quark_global);
if (quark > 0 && quark <= g_quark_seq_id)
- return g_quarks[quark - 1];
- else
- return NULL;
+ result = g_quarks[quark - 1];
+ g_unlock (g_quark_global);
+
+ return result;
}
+/* HOLDS: g_quark_global_lock */
static inline GQuark
g_quark_new (gchar *string)
{
diff --git a/glib/gdate.c b/glib/gdate.c
index 69c337def..7c60e23d9 100644
--- a/glib/gdate.c
+++ b/glib/gdate.c
@@ -16,6 +16,11 @@
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
+
+/*
+ * MT safe
+ */
+
#include "glib.h"
#include <time.h>
@@ -383,6 +388,8 @@ g_date_clear (GDate *d, guint ndates)
memset (d, 0x0, ndates*sizeof (GDate));
}
+static G_LOCK_DEFINE(g_date_global);
+
/* These are for the parser, output to the user should use *
* g_date_strftime () - this creates more never-freed memory to annoy
* all those memory debugger users. :-)
@@ -429,6 +436,7 @@ typedef struct _GDateParseTokens GDateParseTokens;
#define NUM_LEN 10
+/* HOLDS: g_date_global_lock */
static void
g_date_fill_parse_tokens (const gchar *str, GDateParseTokens *pt)
{
@@ -488,7 +496,7 @@ g_date_fill_parse_tokens (const gchar *str, GDateParseTokens *pt)
if (found != NULL)
{
pt->month = i;
- return;
+ return;
}
}
@@ -502,12 +510,13 @@ g_date_fill_parse_tokens (const gchar *str, GDateParseTokens *pt)
return;
}
}
-
+
++i;
- }
+ }
}
}
+/* HOLDS: g_date_global_lock */
static void
g_date_prepare_to_parse (const gchar *str, GDateParseTokens *pt)
{
@@ -641,6 +650,8 @@ g_date_set_parse (GDate *d,
/* set invalid */
g_date_clear (d, 1);
+ g_lock (g_date_global);
+
g_date_prepare_to_parse (str, &pt);
#ifdef G_ENABLE_DEBUG
@@ -649,7 +660,11 @@ g_date_set_parse (GDate *d,
#endif
- if (pt.num_ints == 4) return; /* presumably a typo; bail out. */
+ if (pt.num_ints == 4)
+ {
+ g_unlock (g_date_global);
+ return; /* presumably a typo; bail out. */
+ }
if (pt.num_ints > 1)
{
@@ -765,6 +780,7 @@ g_date_set_parse (GDate *d,
else
g_message ("Rejected DMY %u %u %u", day, m, y);
#endif
+ g_unlock (g_date_global);
}
void
diff --git a/glib/gerror.c b/glib/gerror.c
index 6aeb8b517..2615ce2b4 100644
--- a/glib/gerror.c
+++ b/glib/gerror.c
@@ -17,6 +17,11 @@
* Boston, MA 02111-1307, USA.
*/
+/*
+ * MT safe ; except for g_on_error_stack_trace, but who wants thread safety
+ * then
+ */
+
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
diff --git a/glib/ghash.c b/glib/ghash.c
index 4ab82b3fa..724036388 100644
--- a/glib/ghash.c
+++ b/glib/ghash.c
@@ -16,6 +16,11 @@
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
+
+/*
+ * MT safe
+ */
+
#include "glib.h"
@@ -52,6 +57,8 @@ static void g_hash_node_destroy (GHashNode *hash_node);
static void g_hash_nodes_destroy (GHashNode *hash_node);
+static G_LOCK_DEFINE(g_hash_global);
+
static GMemChunk *node_mem_chunk = NULL;
static GHashNode *node_free_list = NULL;
@@ -338,6 +345,7 @@ g_hash_node_new (gpointer key,
{
GHashNode *hash_node;
+ g_lock (g_hash_global);
if (node_free_list)
{
hash_node = node_free_list;
@@ -352,6 +360,7 @@ g_hash_node_new (gpointer key,
hash_node = g_chunk_new (GHashNode, node_mem_chunk);
}
+ g_unlock (g_hash_global);
hash_node->key = key;
hash_node->value = value;
@@ -363,8 +372,10 @@ g_hash_node_new (gpointer key,
static void
g_hash_node_destroy (GHashNode *hash_node)
{
+ g_lock (g_hash_global);
hash_node->next = node_free_list;
node_free_list = hash_node;
+ g_unlock (g_hash_global);
}
static void
@@ -380,6 +391,8 @@ g_hash_nodes_destroy (GHashNode *hash_node)
while (node->next)
node = node->next;
+ g_lock (g_hash_global);
node->next = node_free_list;
node_free_list = hash_node;
+ g_unlock (g_hash_global);
}
diff --git a/glib/ghook.c b/glib/ghook.c
index 47a2874a4..b683b7c31 100644
--- a/glib/ghook.c
+++ b/glib/ghook.c
@@ -19,6 +19,11 @@
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
+
+/*
+ * MT safe
+ */
+
#include "glib.h"
diff --git a/glib/giochannel.c b/glib/giochannel.c
index fa4262602..0693a084b 100644
--- a/glib/giochannel.c
+++ b/glib/giochannel.c
@@ -20,6 +20,10 @@
* Boston, MA 02111-1307, USA.
*/
+/*
+ * MT safe
+ */
+
#include "glib.h"
#include <unistd.h>
diff --git a/glib/giounix.c b/glib/giounix.c
index 5e605a478..82944be89 100644
--- a/glib/giounix.c
+++ b/glib/giounix.c
@@ -20,6 +20,10 @@
* Boston, MA 02111-1307, USA.
*/
+/*
+ * MT safe
+ */
+
#include "glib.h"
#include <sys/types.h>
#include <unistd.h>
diff --git a/glib/glib.h b/glib/glib.h
index 33fa042e9..d4d1aaa77 100644
--- a/glib/glib.h
+++ b/glib/glib.h
@@ -2597,6 +2597,140 @@ gint gwin_closedir (DIR *dir);
#endif /* NATIVE_WIN32 */
+/* functions for thread support for glib. */
+
+typedef struct _GMutex GMutex;
+typedef struct _GCond GCond;
+typedef struct _GPrivate GPrivate;
+typedef struct _GStaticPrivate GStaticPrivate;
+
+typedef struct _GThreadFunctions GThreadFunctions;
+struct _GThreadFunctions
+{
+ GMutex* (*mutex_new) (void);
+ void (*mutex_lock) (GMutex* mutex);
+ gboolean (*mutex_trylock) (GMutex* mutex);
+ void (*mutex_unlock) (GMutex* mutex);
+ void (*mutex_free) (GMutex* mutex);
+ GCond* (*cond_new) (void);
+ void (*cond_signal) (GCond* cond);
+ void (*cond_broadcast) (GCond* cond);
+ void (*cond_wait) (GCond* cond, GMutex* mutex);
+ gboolean (*cond_timed_wait) (GCond* cond, GMutex* mutex,
+ GTimeVal *end_time);
+ void (*cond_free) (GCond* cond);
+ GPrivate* (*private_new) (GDestroyNotify destructor);
+ gpointer (*private_get) (GPrivate* private);
+ void (*private_set) (GPrivate* private, gpointer value);
+};
+
+GUTILS_C_VAR GThreadFunctions g_thread_functions_for_glib_use;
+GUTILS_C_VAR gboolean g_thread_use_default_impl;
+GUTILS_C_VAR gboolean g_thread_supported;
+
+/* initializes the mutex/cond/private implementation for glib, might
+ * only be called once, and must not be called directly or indirectly
+ * from another glib-function, e.g. as a callback. */
+void g_thread_init(GThreadFunctions* init);
+
+/* Internal functions for fallback static mutex implementation
+ * Please don't use it directly
+ */
+GMutex* g_static_mutex_get_mutex_impl(GMutex** mutex);
+
+#define G_USE_THREAD_FUNC_UNCOND(name,arg) \
+ (*g_thread_functions_for_glib_use.name)arg
+#define G_USE_THREAD_FUNC(name,fail,arg) \
+ (g_thread_supported ? G_USE_THREAD_FUNC_UNCOND(name,arg) : (fail))
+
+/* keep in mind, all those mutexes and static mutexes are not
+ * recursive in general, don't rely on that */
+#define g_mutex_new() G_USE_THREAD_FUNC_UNCOND(mutex_new,())
+#define g_mutex_lock(mutex) G_USE_THREAD_FUNC(mutex_lock,(void)0,(mutex))
+#define g_mutex_trylock(mutex) G_USE_THREAD_FUNC(mutex_trylock,TRUE,(mutex))
+#define g_mutex_unlock(mutex) G_USE_THREAD_FUNC(mutex_unlock,(void)0,(mutex))
+#define g_mutex_free(mutex) G_USE_THREAD_FUNC(mutex_free,(void)0,(mutex))
+#define g_cond_new() G_USE_THREAD_FUNC_UNCOND(cond_new,())
+#define g_cond_signal(cond) G_USE_THREAD_FUNC(cond_signal,(void)0,(cond))
+#define g_cond_broadcast(cond) G_USE_THREAD_FUNC(cond_broadcast,(void)0,(cond))
+#define g_cond_wait(cond,mutex) G_USE_THREAD_FUNC(cond_wait,(void)0,(cond,mutex))
+#define g_cond_timed_wait(cond,mutex,abs_time) \
+ G_USE_THREAD_FUNC(cond_timed_wait,TRUE,(cond,mutex,abs_time))
+#define g_cond_free(cond) G_USE_THREAD_FUNC(cond_free,(void)0,(cond))
+
+#define g_private_new(destructor) \
+ G_USE_THREAD_FUNC_UNCOND(private_new,(destructor))
+#define g_private_get(private) \
+ G_USE_THREAD_FUNC(private_get,((gpointer)private),(private))
+#define g_private_set(private,value) \
+ G_USE_THREAD_FUNC(private_set,(void)(private=(GPrivate *)(value)), \
+ (private,value))
+
+/* GStaticMutex'es can be statically initialized with the value
+ * G_STATIC_MUTEX_INIT, and then they can directly be used, that is
+ * much easier, than having to explicitly allocate the mutex before
+ * use */
+#define g_static_mutex_lock(mutex) \
+ g_mutex_lock( g_static_mutex_get_mutex(mutex) )
+#define g_static_mutex_trylock(mutex) \
+ g_mutex_trylock( g_static_mutex_get_mutex(mutex) )
+#define g_static_mutex_unlock(mutex) \
+ g_mutex_unlock( g_static_mutex_get_mutex(mutex) )
+
+struct _GStaticPrivate
+{
+ guint index;
+};
+
+#define G_STATIC_PRIVATE_INIT { 0 }
+
+gpointer g_static_private_get (GStaticPrivate* private);
+void g_static_private_set (GStaticPrivate *private,
+ gpointer data,
+ GDestroyNotify notify);
+
+/* these are some convenience macros, for using StaticMutex'es, you
+ * define them by G_LOCK_DEFINE(name), where name could for example be the
+ * name of the protected varibale, and you (un)lock them with
+ * g_(un)lock(name) */
+#define g_lock_name(name) (name ## _lock)
+#define G_LOCK_DEFINE(name) GStaticMutex g_lock_name(name)=G_STATIC_MUTEX_INIT
+
+#ifdef G_DEBUG_LOCKS
+#define g_lock(name) G_STMT_START{ \
+ g_log (G_LOG_DOMAIN, \
+ G_LOG_LEVEL_MESSAGE, \
+ "file %s: line %d (%s): locking: %s ", \
+ __FILE__, \
+ __LINE__, \
+ __PRETTY_FUNCTION__, \
+ #name); \
+ g_static_mutex_lock(g_lock_name(name)); \
+ }G_STMT_END
+#define g_unlock(name) G_STMT_START{ \
+ g_log (G_LOG_DOMAIN, \
+ G_LOG_LEVEL_MESSAGE, \
+ "file %s: line %d (%s): unlocking: %s ", \
+ __FILE__, \
+ __LINE__, \
+ __PRETTY_FUNCTION__, \
+ #name); \
+ g_static_mutex_unlock(g_lock_name(name)); \
+ }G_STMT_END
+#define g_trylock(name) G_STMT_START{ \
+ g_log (G_LOG_DOMAIN, \
+ G_LOG_LEVEL_MESSAGE, \
+ "file %s: line %d (%s): try locking: %s ", \
+ __FILE__, \
+ __LINE__, \
+ __PRETTY_FUNCTION__, \
+ #name); \
+ }G_STMT_END, g_static_mutex_trylock(g_lock_name(name))
+#else /* !G_DEBUG_LOCKS */
+#define g_lock(name) g_static_mutex_lock(g_lock_name(name))
+#define g_unlock(name) g_static_mutex_unlock(g_lock_name(name))
+#define g_trylock(name) g_static_mutex_trylock(g_lock_name(name))
+#endif
#ifdef __cplusplus
}
diff --git a/glib/glist.c b/glib/glist.c
index 41a09dd18..e74dee872 100644
--- a/glib/glist.c
+++ b/glib/glist.c
@@ -16,6 +16,11 @@
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
+
+/*
+ * MT safe
+ */
+
#include "glib.h"
@@ -31,9 +36,11 @@ struct _GAllocator /* from gmem.c */
};
static GAllocator *current_allocator = NULL;
+static G_LOCK_DEFINE(current_allocator);
-void
-g_list_push_allocator (GAllocator *allocator)
+/* HOLDS: current_allocator_lock */
+static void
+g_list_validate_allocator (GAllocator *allocator)
{
g_return_if_fail (allocator != NULL);
g_return_if_fail (allocator->is_unused == TRUE);
@@ -58,13 +65,22 @@ g_list_push_allocator (GAllocator *allocator)
}
allocator->is_unused = FALSE;
+}
+
+void
+g_list_push_allocator(GAllocator *allocator)
+{
+ g_list_validate_allocator ( allocator );
+ g_lock (current_allocator);
allocator->last = current_allocator;
current_allocator = allocator;
+ g_unlock (current_allocator);
}
void
g_list_pop_allocator (void)
{
+ g_lock (current_allocator);
if (current_allocator)
{
GAllocator *allocator;
@@ -74,6 +90,7 @@ g_list_pop_allocator (void)
allocator->last = NULL;
allocator->is_unused = TRUE;
}
+ g_unlock (current_allocator);
}
GList*
@@ -81,9 +98,15 @@ g_list_alloc (void)
{
GList *list;
+ g_lock (current_allocator);
if (!current_allocator)
- g_list_push_allocator (g_allocator_new ("GLib default GList allocator", 1024));
-
+ {
+ GAllocator *allocator = g_allocator_new ("GLib default GList allocator",
+ 1024);
+ g_list_validate_allocator (allocator);
+ allocator->last = NULL;
+ current_allocator = allocator;
+ }
if (!current_allocator->free_lists)
{
list = g_chunk_new (GList, current_allocator->mem_chunk);
@@ -103,6 +126,7 @@ g_list_alloc (void)
current_allocator->free_lists = list->next;
}
}
+ g_unlock (current_allocator);
list->next = NULL;
list->prev = NULL;
@@ -112,23 +136,31 @@ g_list_alloc (void)
void
g_list_free (GList *list)
{
+#if 0
if (list)
{
- list->data = list->next;
+ list->data = list->next;
+ g_lock (current_allocator);
list->next = current_allocator->free_lists;
current_allocator->free_lists = list;
+ g_unlock (current_allocator);
}
+#endif
}
void
g_list_free_1 (GList *list)
{
+#if 0
if (list)
{
- list->data = NULL;
+ list->data = NULL;
+ g_lock (current_allocator);
list->next = current_allocator->free_lists;
current_allocator->free_lists = list;
+ g_unlock (current_allocator);
}
+#endif
}
GList*
diff --git a/glib/gmain.c b/glib/gmain.c
index 1f13e9097..5d3ae8d46 100644
--- a/glib/gmain.c
+++ b/glib/gmain.c
@@ -20,9 +20,14 @@
* Boston, MA 02111-1307, USA.
*/
+/*
+ * MT safe
+ */
+
#include "glib.h"
#include <sys/time.h>
#include <unistd.h>
+#include <errno.h>
#include "config.h"
/* Types */
@@ -65,9 +70,12 @@ struct _GPollRec {
/* Forward declarations */
-static void g_main_poll (gint timeout,
- gboolean use_priority,
- gint priority);
+static void g_main_poll (gint timeout,
+ gboolean use_priority,
+ gint priority);
+static void g_main_poll_add_unlocked (gint priority,
+ GPollFD *fd);
+
static gboolean g_timeout_prepare (gpointer source_data,
GTimeVal *current_time,
gint *timeout);
@@ -90,6 +98,11 @@ static gboolean g_idle_dispatch (gpointer source_data,
static GSList *pending_dispatches = NULL;
static GHookList source_list = { 0 };
+/* The following lock is used for both the list of sources
+ * and the list of poll records
+ */
+static G_LOCK_DEFINE (main_loop);
+
static GSourceFuncs timeout_funcs = {
g_timeout_prepare,
g_timeout_check,
@@ -104,6 +117,17 @@ static GSourceFuncs idle_funcs = {
(GDestroyNotify)g_free
};
+static GPollRec *poll_records = NULL;
+static GPollRec *poll_free_list = NULL;
+static GMemChunk *poll_chunk;
+static guint n_poll_records = 0;
+
+/* this pipe is used to wake up the main loop when a source is added.
+ */
+static gint wake_up_pipe[2] = { -1, -1 };
+static GPollFD wake_up_rec;
+static gboolean poll_waiting = FALSE;
+
#ifdef HAVE_POLL
static GPollFunc poll_func = (GPollFunc)poll;
#else
@@ -205,8 +229,11 @@ g_source_add (gint priority,
gpointer user_data,
GDestroyNotify notify)
{
+ guint return_val;
GSource *source;
+ g_lock (main_loop);
+
if (!source_list.is_setup)
g_hook_list_init (&source_list, sizeof(GSource));
@@ -224,31 +251,55 @@ g_source_add (gint priority,
if (can_recurse)
source->hook.flags |= G_SOURCE_CAN_RECURSE;
- return source->hook.hook_id;
+ return_val = source->hook.hook_id;
+
+ /* Now wake up the main loop if it is waiting in the poll() */
+
+ if (poll_waiting)
+ {
+ poll_waiting = FALSE;
+ write (wake_up_pipe[1], "A", 1);
+ }
+
+ g_unlock (main_loop);
+
+ return return_val;
}
void
g_source_remove (guint tag)
{
- GHook *hook = g_hook_get (&source_list, tag);
+ GHook *hook;
+
+ g_lock (main_loop);
+
+ hook = g_hook_get (&source_list, tag);
if (hook)
{
GSource *source = (GSource *)hook;
((GSourceFuncs *)source->hook.func)->destroy (source->source_data);
g_hook_destroy_link (&source_list, hook);
}
+
+ g_unlock (main_loop);
}
void
g_source_remove_by_user_data (gpointer user_data)
{
- GHook *hook = g_hook_find_data (&source_list, TRUE, user_data);
+ GHook *hook;
+
+ g_lock (main_loop);
+
+ hook = g_hook_find_data (&source_list, TRUE, user_data);
if (hook)
{
GSource *source = (GSource *)hook;
((GSourceFuncs *)source->hook.func)->destroy (source->source_data);
g_hook_destroy_link (&source_list, hook);
}
+
+ g_unlock (main_loop);
}
static gboolean
@@ -262,7 +313,11 @@ g_source_find_source_data (GHook *hook,
void
g_source_remove_by_source_data (gpointer source_data)
{
- GHook *hook = g_hook_find (&source_list, TRUE,
+ GHook *hook;
+
+ g_lock (main_loop);
+
+ hook = g_hook_find (&source_list, TRUE,
g_source_find_source_data, source_data);
if (hook)
{
@@ -270,6 +325,8 @@ g_source_remove_by_source_data (gpointer source_data)
((GSourceFuncs *)source->hook.func)->destroy (source->source_data);
g_hook_destroy_link (&source_list, hook);
}
+
+ g_unlock (main_loop);
}
void g_get_current_time (GTimeVal *result)
@@ -279,6 +336,7 @@ void g_get_current_time (GTimeVal *result)
/* Running the main loop */
+/* HOLDS: main_loop_lock */
static void
g_main_dispatch (GTimeVal *current_time)
{
@@ -294,10 +352,20 @@ g_main_dispatch (GTimeVal *current_time)
if (G_HOOK_IS_VALID (source))
{
+ gboolean (*dispatch) (gpointer, GTimeVal *, gpointer);
+ gpointer hook_data = source->hook.data;
+ gpointer source_data = source->source_data;
+
+ dispatch = ((GSourceFuncs *)source->hook.func)->dispatch;
+
source->hook.flags |= G_HOOK_FLAG_IN_CALL;
- need_destroy = !((GSourceFuncs *)source->hook.func)->dispatch (source->source_data,
- current_time,
- source->hook.data);
+
+ g_unlock (main_loop);
+ need_destroy = ! dispatch(source_data,
+ current_time,
+ hook_data);
+ g_lock (main_loop);
+
source->hook.flags &= ~G_HOOK_FLAG_IN_CALL;
if (need_destroy)
@@ -320,10 +388,13 @@ g_main_iterate (gboolean block, gboolean dispatch)
gint nready = 0;
gint current_priority = 0;
gint timeout;
+ gboolean retval = FALSE;
g_return_val_if_fail (!block || dispatch, FALSE);
g_get_current_time (&current_time);
+
+ g_lock (main_loop);
/* If recursing, finish up current dispatch, before starting over */
if (pending_dispatches)
@@ -331,6 +402,7 @@ g_main_iterate (gboolean block, gboolean dispatch)
if (dispatch)
g_main_dispatch (&current_time);
+ g_unlock (main_loop);
return TRUE;
}
@@ -362,6 +434,7 @@ g_main_iterate (gboolean block, gboolean dispatch)
if (!dispatch)
{
g_hook_unref (&source_list, hook);
+ g_unlock (main_loop);
return TRUE;
}
else
@@ -426,6 +499,7 @@ g_main_iterate (gboolean block, gboolean dispatch)
else
{
g_hook_unref (&source_list, hook);
+ g_unlock (main_loop);
return TRUE;
}
}
@@ -442,10 +516,12 @@ g_main_iterate (gboolean block, gboolean dispatch)
{
pending_dispatches = g_slist_reverse (pending_dispatches);
g_main_dispatch (&current_time);
- return TRUE;
+ retval = TRUE;
}
- else
- return FALSE;
+
+ g_unlock (main_loop);
+
+ return retval;
}
/* See if any events are pending
@@ -494,11 +570,7 @@ g_main_destroy (GMainLoop *loop)
g_free (loop);
}
-static GPollRec *poll_records = NULL;
-static GPollRec *poll_free_list = NULL;
-static GMemChunk *poll_chunk;
-static guint n_poll_records = 0;
-
+/* HOLDS: main_loop_lock */
static void
g_main_poll (gint timeout, gboolean use_priority, gint priority)
{
@@ -508,6 +580,17 @@ g_main_poll (gint timeout, gboolean use_priority, gint priority)
gint i;
gint npoll;
+ if (wake_up_pipe[0] < 0)
+ {
+ if (pipe (wake_up_pipe) < 0)
+ g_error ("Cannot create pipe main loop wake-up: %s\n",
+ g_strerror(errno));
+
+ wake_up_rec.fd = wake_up_pipe[0];
+ wake_up_rec.events = G_IO_IN;
+ g_main_poll_add_unlocked (0, &wake_up_rec);
+ }
+
pollrec = poll_records;
i = 0;
while (pollrec && (!use_priority || priority >= pollrec->priority))
@@ -520,8 +603,20 @@ g_main_poll (gint timeout, gboolean use_priority, gint priority)
i++;
}
+ poll_waiting = TRUE;
+
+ g_unlock (main_loop);
npoll = i;
(*poll_func) (fd_array, npoll, timeout);
+ g_lock (main_loop);
+
+ if (!poll_waiting)
+ {
+ gchar c;
+ read (wake_up_pipe[0], &c, 1);
+ }
+ else
+ poll_waiting = FALSE;
pollrec = poll_records;
i = 0;
@@ -539,12 +634,28 @@ void
g_main_poll_add (gint priority,
GPollFD *fd)
{
+ g_lock (main_loop);
+ g_main_poll_add_unlocked (priority, fd);
+ g_unlock (main_loop);
+}
+
+static void
+g_main_poll_add_unlocked (gint priority,
+ GPollFD *fd)
+{
GPollRec *lastrec, *pollrec, *newrec;
if (!poll_chunk)
poll_chunk = g_mem_chunk_create (GPollRec, 32, G_ALLOC_ONLY);
- newrec = g_chunk_new (GPollRec, poll_chunk);
+ if (poll_free_list)
+ {
+ newrec = poll_free_list;
+ poll_free_list = newrec->next;
+ }
+ else
+ newrec = g_chunk_new (GPollRec, poll_chunk);
+
newrec->fd = fd;
newrec->priority = priority;
@@ -564,6 +675,8 @@ g_main_poll_add (gint priority,
newrec->next = pollrec;
n_poll_records++;
+
+ g_unlock (main_loop);
}
void
@@ -571,6 +684,8 @@ g_main_poll_remove (GPollFD *fd)
{
GPollRec *pollrec, *lastrec;
+ g_lock (main_loop);
+
lastrec = NULL;
pollrec = poll_records;
@@ -585,12 +700,15 @@ g_main_poll_remove (GPollFD *fd)
pollrec->next = poll_free_list;
poll_free_list = pollrec;
+
+ n_poll_records--;
+ break;
}
lastrec = pollrec;
pollrec = pollrec->next;
}
- n_poll_records--;
+ g_unlock (main_loop);
}
void
diff --git a/glib/gmem.c b/glib/gmem.c
index c29ee660f..a4907ffca 100644
--- a/glib/gmem.c
+++ b/glib/gmem.c
@@ -17,6 +17,10 @@
* Boston, MA 02111-1307, USA.
*/
+/*
+ * MT safe
+ */
+
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
@@ -48,8 +52,12 @@
*/
#if defined(ENABLE_MEM_PROFILE) && defined(ENABLE_MEM_PROFILE_EXCLUDES_MEM_CHUNKS)
-#define ENTER_MEM_CHUNK_ROUTINE() allocating_for_mem_chunk++
-#define LEAVE_MEM_CHUNK_ROUTINE() allocating_for_mem_chunk--
+#define ENTER_MEM_CHUNK_ROUTINE() \
+ g_static_set (allocating_for_mem_chunk, \
+ g_static_get (allocating_for_mem_chunk) + 1)
+#define ENTER_MEM_CHUNK_ROUTINE() \
+ g_static_set (allocating_for_mem_chunk, \
+ g_static_get (allocating_for_mem_chunk) - 1)
#else
#define ENTER_MEM_CHUNK_ROUTINE()
#define LEAVE_MEM_CHUNK_ROUTINE()
@@ -117,13 +125,19 @@ static gint g_mem_chunk_area_search (GMemArea *a,
gchar *addr);
+/* here we can't use StaticMutexes, as they depend upon a working
+ * g_malloc, the same holds true for StaticPrivate */
+static GMutex* mem_chunks_lock = NULL;
static GRealMemChunk *mem_chunks = NULL;
#ifdef ENABLE_MEM_PROFILE
+static GMutex* mem_profile_lock;
static gulong allocations[MEM_PROFILE_TABLE_SIZE] = { 0 };
static gulong allocated_mem = 0;
static gulong freed_mem = 0;
-static gint allocating_for_mem_chunk = 0;
+static GPrivate* allocating_for_mem_chunk = NULL;
+#define IS_IN_MEM_CHUNK_ROUTINE() \
+ GPOINTER_TO_UINT (g_static_get (allocating_for_mem_chunk))
#endif /* ENABLE_MEM_PROFILE */
@@ -174,8 +188,9 @@ g_malloc (gulong size)
*t = size;
#ifdef ENABLE_MEM_PROFILE
+ g_mutex_lock (mem_profile_lock);
# ifdef ENABLE_MEM_PROFILE_EXCLUDES_MEM_CHUNKS
- if(!allocating_for_mem_chunk) {
+ if(!IS_IN_MEM_CHUNK_ROUTINE()) {
# endif
if (size <= MEM_PROFILE_TABLE_SIZE - 1)
allocations[size-1] += 1;
@@ -185,6 +200,7 @@ g_malloc (gulong size)
# ifdef ENABLE_MEM_PROFILE_EXCLUDES_MEM_CHUNKS
}
# endif
+ g_mutex_unlock (mem_profile_lock);
#endif /* ENABLE_MEM_PROFILE */
#endif /* ENABLE_MEM_PROFILE || ENABLE_MEM_CHECK */
@@ -237,8 +253,9 @@ g_malloc0 (gulong size)
*t = size;
# ifdef ENABLE_MEM_PROFILE
+ g_mutex_lock (mem_profile_lock);
# ifdef ENABLE_MEM_PROFILE_EXCLUDES_MEM_CHUNKS
- if(!allocating_for_mem_chunk) {
+ if(!IS_IN_MEM_CHUNK_ROUTINE()) {
# endif
if (size <= (MEM_PROFILE_TABLE_SIZE - 1))
allocations[size-1] += 1;
@@ -248,8 +265,9 @@ g_malloc0 (gulong size)
# ifdef ENABLE_MEM_PROFILE_EXCLUDES_MEM_CHUNKS
}
# endif
+ g_mutex_unlock (mem_profile_lock);
# endif /* ENABLE_MEM_PROFILE */
-#endif /* ENABLE_MEM_PROFILE */
+#endif /* ENABLE_MEM_PROFILE || ENABLE_MEM_CHECK */
return p;
@@ -286,7 +304,9 @@ g_realloc (gpointer mem,
#if defined(ENABLE_MEM_PROFILE) || defined(ENABLE_MEM_CHECK)
t = (gulong*) ((guchar*) mem - SIZEOF_LONG);
#ifdef ENABLE_MEM_PROFILE
+ g_mutex_lock (mem_profile);
freed_mem += *t;
+ g_mutex_unlock (mem_profile);
#endif /* ENABLE_MEM_PROFILE */
mem = t;
#endif /* ENABLE_MEM_PROFILE || ENABLE_MEM_CHECK */
@@ -321,8 +341,9 @@ g_realloc (gpointer mem,
*t = size;
#ifdef ENABLE_MEM_PROFILE
+ g_mutex_lock (mem_profile_lock);
#ifdef ENABLE_MEM_PROFILE_EXCLUDES_MEM_CHUNKS
- if(!allocating_for_mem_chunk) {
+ if(!IS_IN_MEM_CHUNK_ROUTINE()) {
#endif
if (size <= (MEM_PROFILE_TABLE_SIZE - 1))
allocations[size-1] += 1;
@@ -332,6 +353,7 @@ g_realloc (gpointer mem,
#ifdef ENABLE_MEM_PROFILE_EXCLUDES_MEM_CHUNKS
}
#endif
+ g_mutex_unlock (mem_profile_lock);
#endif /* ENABLE_MEM_PROFILE */
#endif /* ENABLE_MEM_PROFILE || ENABLE_MEM_CHECK */
@@ -352,8 +374,10 @@ g_free (gpointer mem)
#if defined(ENABLE_MEM_PROFILE) || defined(ENABLE_MEM_CHECK)
t = (gulong*) ((guchar*) mem - SIZEOF_LONG);
size = *t;
-#ifdef ENABLE_MEM_PROFILE
+#ifdef ENABLE_MEM_PROFILE
+ g_mutex_lock (mem_profile);
freed_mem += size;
+ g_mutex_unlock (mem_profile);
#endif /* ENABLE_MEM_PROFILE */
mem = t;
#endif /* ENABLE_MEM_PROFILE || ENABLE_MEM_CHECK */
@@ -380,19 +404,29 @@ g_mem_profile (void)
{
#ifdef ENABLE_MEM_PROFILE
gint i;
-
+ gulong local_allocations[MEM_PROFILE_TABLE_SIZE];
+ gulong local_allocated_mem;
+ gulong local_freed_mem;
+
+ g_mutex_lock (mem_profile);
+ for (i = 0; i < (MEM_PROFILE_TABLE_SIZE - 1); i++)
+ local_allocations[i] = allocations[i];
+ local_allocated_mem = allocated_mem;
+ local_freed_mem = freed_mem;
+ g_mutex_unlock (mem_profile);
+
for (i = 0; i < (MEM_PROFILE_TABLE_SIZE - 1); i++)
- if (allocations[i] > 0)
+ if (local_allocations[i] > 0)
g_log (g_log_domain_glib, G_LOG_LEVEL_INFO,
- "%lu allocations of %d bytes\n", allocations[i], i + 1);
+ "%lu allocations of %d bytes\n", local_allocations[i], i + 1);
- if (allocations[MEM_PROFILE_TABLE_SIZE - 1] > 0)
+ if (local_allocations[MEM_PROFILE_TABLE_SIZE - 1] > 0)
g_log (g_log_domain_glib, G_LOG_LEVEL_INFO,
"%lu allocations of greater than %d bytes\n",
- allocations[MEM_PROFILE_TABLE_SIZE - 1], MEM_PROFILE_TABLE_SIZE - 1);
- g_log (g_log_domain_glib, G_LOG_LEVEL_INFO, "%lu bytes allocated\n", allocated_mem);
- g_log (g_log_domain_glib, G_LOG_LEVEL_INFO, "%lu bytes freed\n", freed_mem);
- g_log (g_log_domain_glib, G_LOG_LEVEL_INFO, "%lu bytes in use\n", allocated_mem - freed_mem);
+ local_allocations[MEM_PROFILE_TABLE_SIZE - 1], MEM_PROFILE_TABLE_SIZE - 1);
+ g_log (g_log_domain_glib, G_LOG_LEVEL_INFO, "%lu bytes allocated\n", local_allocated_mem);
+ g_log (g_log_domain_glib, G_LOG_LEVEL_INFO, "%lu bytes freed\n", local_freed_mem);
+ g_log (g_log_domain_glib, G_LOG_LEVEL_INFO, "%lu bytes in use\n", local_allocated_mem - local_freed_mem);
#endif /* ENABLE_MEM_PROFILE */
}
@@ -460,11 +494,13 @@ g_mem_chunk_new (gchar *name,
mem_chunk->area_size += mem_chunk->atom_size - (mem_chunk->area_size % mem_chunk->atom_size);
*/
+ g_mutex_lock (mem_chunks_lock);
mem_chunk->next = mem_chunks;
mem_chunk->prev = NULL;
if (mem_chunks)
mem_chunks->prev = mem_chunk;
mem_chunks = mem_chunk;
+ g_mutex_unlock (mem_chunks_lock);
LEAVE_MEM_CHUNK_ROUTINE();
@@ -497,8 +533,10 @@ g_mem_chunk_destroy (GMemChunk *mem_chunk)
if (rmem_chunk->prev)
rmem_chunk->prev->next = rmem_chunk->next;
+ g_mutex_lock (mem_chunks_lock);
if (rmem_chunk == mem_chunks)
mem_chunks = mem_chunks->next;
+ g_mutex_unlock (mem_chunks_lock);
if (rmem_chunk->type == G_ALLOC_AND_FREE)
g_tree_destroy (rmem_chunk->mem_tree);
@@ -826,21 +864,26 @@ g_mem_chunk_info (void)
gint count;
count = 0;
+ g_mutex_lock (mem_chunks_lock);
mem_chunk = mem_chunks;
while (mem_chunk)
{
count += 1;
mem_chunk = mem_chunk->next;
}
+ g_mutex_unlock (mem_chunks_lock);
g_log (g_log_domain_glib, G_LOG_LEVEL_INFO, "%d mem chunks\n", count);
+ g_mutex_lock (mem_chunks_lock);
mem_chunk = mem_chunks;
+ g_mutex_unlock (mem_chunks_lock);
+
while (mem_chunk)
{
g_mem_chunk_print ((GMemChunk*) mem_chunk);
mem_chunk = mem_chunk->next;
- }
+ }
}
void
@@ -848,7 +891,9 @@ g_blow_chunks (void)
{
GRealMemChunk *mem_chunk;
+ g_mutex_lock (mem_chunks_lock);
mem_chunk = mem_chunks;
+ g_mutex_unlock (mem_chunks_lock);
while (mem_chunk)
{
g_mem_chunk_clean ((GMemChunk*) mem_chunk);
@@ -940,3 +985,13 @@ g_allocator_free (GAllocator *allocator)
g_free (allocator);
}
+
+void
+g_mem_init (void)
+{
+ mem_chunks_lock = g_mutex_new();
+#ifdef ENABLE_MEM_PROFILE
+ mem_profile_lock = g_mutex_new();
+ allocating_for_mem_chunk = g_private_new(NULL);
+#endif
+}
diff --git a/glib/gmessages.c b/glib/gmessages.c
index e0c6eacb1..eb8aed7a8 100644
--- a/glib/gmessages.c
+++ b/glib/gmessages.c
@@ -17,6 +17,10 @@
* Boston, MA 02111-1307, USA.
*/
+/*
+ * MT safe
+ */
+
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
@@ -31,7 +35,7 @@
#endif
#ifdef NATIVE_WIN32
-/* Just use stdio. If we're out of memroy, we're hosed anyway. */
+/* Just use stdio. If we're out of memory, we're hosed anyway. */
#undef write
static inline int
@@ -67,6 +71,9 @@ struct _GLogHandler
/* --- variables --- */
+
+static GMutex* g_messages_lock = NULL;
+
const gchar *g_log_domain_glib = "GLib";
static GLogDomain *g_log_domains = NULL;
static GLogLevelFlags g_log_always_fatal = G_LOG_FATAL_MASK;
@@ -76,20 +83,27 @@ static GErrorFunc glib_error_func = NULL;
static GWarningFunc glib_warning_func = NULL;
static GPrintFunc glib_message_func = NULL;
+static GPrivate* g_log_depth = NULL;
+
/* --- functions --- */
static inline GLogDomain*
g_log_find_domain (const gchar *log_domain)
{
register GLogDomain *domain;
-
+
+ g_mutex_lock (g_messages_lock);
domain = g_log_domains;
while (domain)
{
if (strcmp (domain->log_domain, log_domain) == 0)
- return domain;
+ {
+ g_mutex_unlock (g_messages_lock);
+ return domain;
+ }
domain = domain->next;
}
+ g_mutex_unlock (g_messages_lock);
return NULL;
}
@@ -102,8 +116,11 @@ g_log_domain_new (const gchar *log_domain)
domain->log_domain = g_strdup (log_domain);
domain->fatal_mask = G_LOG_FATAL_MASK;
domain->handlers = NULL;
+
+ g_mutex_lock (g_messages_lock);
domain->next = g_log_domains;
g_log_domains = domain;
+ g_mutex_unlock (g_messages_lock);
return domain;
}
@@ -116,7 +133,9 @@ g_log_domain_check_free (GLogDomain *domain)
{
register GLogDomain *last, *work;
- last = NULL;
+ last = NULL;
+
+ g_mutex_lock (g_messages_lock);
work = g_log_domains;
while (work)
{
@@ -131,7 +150,8 @@ g_log_domain_check_free (GLogDomain *domain)
break;
}
work = work->next;
- }
+ }
+ g_mutex_unlock (g_messages_lock);
}
}
@@ -170,8 +190,10 @@ g_log_set_always_fatal (GLogLevelFlags fatal_mask)
/* remove bogus flag */
fatal_mask &= ~G_LOG_FLAG_FATAL;
+ g_mutex_lock (g_messages_lock);
old_mask = g_log_always_fatal;
g_log_always_fatal = fatal_mask;
+ g_mutex_unlock (g_messages_lock);
return old_mask;
}
@@ -223,7 +245,9 @@ g_log_set_handler (const gchar *log_domain,
domain = g_log_domain_new (log_domain);
handler = g_new (GLogHandler, 1);
+ g_mutex_lock (g_messages_lock);
handler->id = ++handler_id;
+ g_mutex_unlock (g_messages_lock);
handler->log_level = log_levels;
handler->log_func = log_func;
handler->data = user_data;
@@ -311,19 +335,25 @@ g_logv (const gchar *log_domain,
test_level = 1 << i;
if (log_level & test_level)
{
- static guint g_log_depth = 0;
+ guint depth = GPOINTER_TO_UINT (g_private_get (g_log_depth));
GLogDomain *domain;
GLogFunc log_func;
gpointer data = NULL;
domain = g_log_find_domain (log_domain ? log_domain : "");
- if (g_log_depth++)
+ if (depth)
test_level |= G_LOG_FLAG_RECURSION;
- if ((((domain ? domain->fatal_mask : G_LOG_FATAL_MASK) | g_log_always_fatal) &
- test_level) != 0)
- test_level |= G_LOG_FLAG_FATAL;
+ depth++;
+ g_private_set (g_log_depth, GUINT_TO_POINTER (depth));
+
+ g_mutex_lock (g_messages_lock);
+ if ((((domain ? domain->fatal_mask : G_LOG_FATAL_MASK) |
+ g_log_always_fatal) & test_level) != 0)
+ test_level |= G_LOG_FLAG_FATAL;
+ g_mutex_unlock (g_messages_lock);
+
log_func = g_log_domain_get_handler (domain, test_level, &data);
log_func (log_domain, test_level, buffer, data);
@@ -332,7 +362,8 @@ g_logv (const gchar *log_domain,
if (test_level & G_LOG_FLAG_FATAL)
abort ();
- g_log_depth--;
+ depth--;
+ g_private_set (g_log_depth, GUINT_TO_POINTER (depth));
}
}
}
@@ -362,8 +393,11 @@ g_log_default_handler (const gchar *log_domain,
gint fd;
#endif
gboolean in_recursion;
- gboolean is_fatal;
-
+ gboolean is_fatal;
+ GErrorFunc local_glib_error_func;
+ GWarningFunc local_glib_warning_func;
+ GPrintFunc local_glib_message_func;
+
in_recursion = (log_level & G_LOG_FLAG_RECURSION) != 0;
is_fatal = (log_level & G_LOG_FLAG_FATAL) != 0;
log_level &= G_LOG_LEVEL_MASK;
@@ -380,13 +414,19 @@ g_log_default_handler (const gchar *log_domain,
fd = (log_level >= G_LOG_LEVEL_MESSAGE) ? 1 : 2;
#endif
+ g_mutex_lock (g_messages_lock);
+ local_glib_error_func = glib_error_func;
+ local_glib_warning_func = glib_warning_func;
+ local_glib_message_func = glib_message_func;
+ g_mutex_unlock (g_messages_lock);
+
switch (log_level)
{
case G_LOG_LEVEL_ERROR:
- if (!log_domain && glib_error_func)
+ if (!log_domain && local_glib_error_func)
{
/* compatibility code */
- glib_error_func (message);
+ local_glib_error_func (message);
return;
}
/* use write(2) for output, in case we are out of memeory */
@@ -428,10 +468,10 @@ g_log_default_handler (const gchar *log_domain,
write (fd, "\n", 1);
break;
case G_LOG_LEVEL_WARNING:
- if (!log_domain && glib_warning_func)
+ if (!log_domain && local_glib_warning_func)
{
/* compatibility code */
- glib_warning_func (message);
+ local_glib_warning_func (message);
return;
}
if (log_domain)
@@ -453,10 +493,10 @@ g_log_default_handler (const gchar *log_domain,
write (fd, "\n", 1);
break;
case G_LOG_LEVEL_MESSAGE:
- if (!log_domain && glib_message_func)
+ if (!log_domain && local_glib_message_func)
{
/* compatibility code */
- glib_message_func (message);
+ local_glib_message_func (message);
return;
}
if (log_domain)
@@ -553,8 +593,10 @@ g_set_print_handler (GPrintFunc func)
{
GPrintFunc old_print_func;
+ g_mutex_lock (g_messages_lock);
old_print_func = glib_print_func;
glib_print_func = func;
+ g_mutex_unlock (g_messages_lock);
return old_print_func;
}
@@ -565,6 +607,7 @@ g_print (const gchar *format,
{
va_list args;
gchar *string;
+ GPrintFunc local_glib_print_func;
g_return_if_fail (format != NULL);
@@ -572,8 +615,12 @@ g_print (const gchar *format,
string = g_strdup_vprintf (format, args);
va_end (args);
- if (glib_print_func)
- glib_print_func (string);
+ g_mutex_lock (g_messages_lock);
+ local_glib_print_func = glib_print_func;
+ g_mutex_unlock (g_messages_lock);
+
+ if (local_glib_print_func)
+ local_glib_print_func (string);
else
{
fputs (string, stdout);
@@ -587,8 +634,10 @@ g_set_printerr_handler (GPrintFunc func)
{
GPrintFunc old_printerr_func;
+ g_mutex_lock (g_messages_lock);
old_printerr_func = glib_printerr_func;
glib_printerr_func = func;
+ g_mutex_unlock (g_messages_lock);
return old_printerr_func;
}
@@ -599,6 +648,7 @@ g_printerr (const gchar *format,
{
va_list args;
gchar *string;
+ GPrintFunc local_glib_printerr_func;
g_return_if_fail (format != NULL);
@@ -606,8 +656,12 @@ g_printerr (const gchar *format,
string = g_strdup_vprintf (format, args);
va_end (args);
- if (glib_printerr_func)
- glib_printerr_func (string);
+ g_mutex_lock (g_messages_lock);
+ local_glib_printerr_func = glib_printerr_func;
+ g_mutex_unlock (g_messages_lock);
+
+ if (local_glib_printerr_func)
+ local_glib_printerr_func (string);
else
{
fputs (string, stderr);
@@ -622,9 +676,11 @@ g_set_error_handler (GErrorFunc func)
{
GErrorFunc old_error_func;
+ g_mutex_lock (g_messages_lock);
old_error_func = glib_error_func;
glib_error_func = func;
-
+ g_mutex_unlock (g_messages_lock);
+
return old_error_func;
}
@@ -634,8 +690,10 @@ g_set_warning_handler (GWarningFunc func)
{
GWarningFunc old_warning_func;
+ g_mutex_lock (g_messages_lock);
old_warning_func = glib_warning_func;
glib_warning_func = func;
+ g_mutex_unlock (g_messages_lock);
return old_warning_func;
}
@@ -646,8 +704,17 @@ g_set_message_handler (GPrintFunc func)
{
GPrintFunc old_message_func;
+ g_mutex_lock (g_messages_lock);
old_message_func = glib_message_func;
glib_message_func = func;
+ g_mutex_unlock (g_messages_lock);
return old_message_func;
}
+
+void
+g_messages_init (void)
+{
+ g_messages_lock = g_mutex_new();
+ g_log_depth = g_private_new(NULL);
+}
diff --git a/glib/gnode.c b/glib/gnode.c
index 9f6e544ba..089a4996d 100644
--- a/glib/gnode.c
+++ b/glib/gnode.c
@@ -19,6 +19,11 @@
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
+
+/*
+ * MT safe
+ */
+
#include "glib.h"
/* node allocation
@@ -34,10 +39,12 @@ struct _GAllocator /* from gmem.c */
GNode *free_nodes; /* implementation specific */
};
+static G_LOCK_DEFINE(current_allocator);
static GAllocator *current_allocator = NULL;
-void
-g_node_push_allocator (GAllocator *allocator)
+/* HOLDS: current_allocator_lock */
+static void
+g_node_validate_allocator (GAllocator *allocator)
{
g_return_if_fail (allocator != NULL);
g_return_if_fail (allocator->is_unused == TRUE);
@@ -62,13 +69,22 @@ g_node_push_allocator (GAllocator *allocator)
}
allocator->is_unused = FALSE;
+}
+
+void
+g_node_push_allocator (GAllocator *allocator)
+{
+ g_node_validate_allocator ( allocator );
+ g_lock (current_allocator);
allocator->last = current_allocator;
current_allocator = allocator;
+ g_unlock (current_allocator);
}
void
g_node_pop_allocator (void)
{
+ g_lock (current_allocator);
if (current_allocator)
{
GAllocator *allocator;
@@ -78,6 +94,7 @@ g_node_pop_allocator (void)
allocator->last = NULL;
allocator->is_unused = TRUE;
}
+ g_unlock (current_allocator);
}
@@ -87,9 +104,15 @@ g_node_new (gpointer data)
{
GNode *node;
+ g_lock (current_allocator);
if (!current_allocator)
- g_node_push_allocator (g_allocator_new ("GLib default GNode allocator", 1024));
-
+ {
+ GAllocator *allocator = g_allocator_new ("GLib default GNode allocator",
+ 1024);
+ g_node_validate_allocator (allocator);
+ allocator->last = NULL;
+ current_allocator = allocator;
+ }
if (!current_allocator->free_nodes)
node = g_chunk_new (GNode, current_allocator->mem_chunk);
else
@@ -97,6 +120,7 @@ g_node_new (gpointer data)
node = current_allocator->free_nodes;
current_allocator->free_nodes = node->next;
}
+ g_unlock (current_allocator);
node->data = data;
node->next = NULL;
@@ -122,9 +146,11 @@ g_nodes_free (GNode *node)
else
break;
}
-
+
+ g_lock (current_allocator);
parent->next = current_allocator->free_nodes;
current_allocator->free_nodes = node;
+ g_unlock (current_allocator);
}
void
diff --git a/glib/gprimes.c b/glib/gprimes.c
index 3d45c1ef7..404ebd605 100644
--- a/glib/gprimes.c
+++ b/glib/gprimes.c
@@ -16,6 +16,11 @@
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
+
+/*
+ * MT safe
+ */
+
#include "glib.h"
static const guint g_primes[] =
diff --git a/glib/grel.c b/glib/grel.c
index 5fdf88098..544da6bfc 100644
--- a/glib/grel.c
+++ b/glib/grel.c
@@ -15,6 +15,11 @@
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+
+/*
+ * MT safe
+ */
+
#include "glib.h"
#include <stdarg.h>
#include <string.h>
diff --git a/glib/gscanner.c b/glib/gscanner.c
index 02985a7f7..c6fd0dd4e 100644
--- a/glib/gscanner.c
+++ b/glib/gscanner.c
@@ -19,6 +19,11 @@
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
+
+/*
+ * MT safe
+ */
+
#define __gscanner_c__
#ifdef HAVE_CONFIG_H
diff --git a/glib/gslist.c b/glib/gslist.c
index 4efe2a575..1ed517ff6 100644
--- a/glib/gslist.c
+++ b/glib/gslist.c
@@ -16,6 +16,11 @@
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
+
+/*
+ * MT safe
+ */
+
#include "glib.h"
@@ -30,10 +35,12 @@ struct _GAllocator /* from gmem.c */
GSList *free_lists; /* implementation specific */
};
+static G_LOCK_DEFINE(current_allocator);
static GAllocator *current_allocator = NULL;
-void
-g_slist_push_allocator (GAllocator *allocator)
+/* HOLDS: current_allocator_lock */
+static void
+g_slist_validate_allocator (GAllocator *allocator)
{
g_return_if_fail (allocator != NULL);
g_return_if_fail (allocator->is_unused == TRUE);
@@ -58,13 +65,22 @@ g_slist_push_allocator (GAllocator *allocator)
}
allocator->is_unused = FALSE;
+}
+
+void
+g_slist_push_allocator (GAllocator *allocator)
+{
+ g_slist_validate_allocator (allocator);
+ g_lock (current_allocator);
allocator->last = current_allocator;
current_allocator = allocator;
+ g_unlock (current_allocator);
}
void
g_slist_pop_allocator (void)
{
+ g_lock (current_allocator);
if (current_allocator)
{
GAllocator *allocator;
@@ -74,6 +90,7 @@ g_slist_pop_allocator (void)
allocator->last = NULL;
allocator->is_unused = TRUE;
}
+ g_unlock (current_allocator);
}
GSList*
@@ -81,9 +98,15 @@ g_slist_alloc (void)
{
GSList *list;
+ g_lock (current_allocator);
if (!current_allocator)
- g_slist_push_allocator (g_allocator_new ("GLib default GSList allocator", 1024));
-
+ {
+ GAllocator *allocator = g_allocator_new ("GLib default GSList allocator",
+ 1024);
+ g_slist_validate_allocator (allocator);
+ allocator->last = NULL;
+ current_allocator = allocator;
+ }
if (!current_allocator->free_lists)
{
list = g_chunk_new (GSList, current_allocator->mem_chunk);
@@ -103,6 +126,8 @@ g_slist_alloc (void)
current_allocator->free_lists = list->next;
}
}
+ g_unlock (current_allocator);
+
list->next = NULL;
return list;
@@ -114,8 +139,10 @@ g_slist_free (GSList *list)
if (list)
{
list->data = list->next;
+ g_lock (current_allocator);
list->next = current_allocator->free_lists;
current_allocator->free_lists = list;
+ g_unlock (current_allocator);
}
}
@@ -125,8 +152,10 @@ g_slist_free_1 (GSList *list)
if (list)
{
list->data = NULL;
+ g_lock (current_allocator);
list->next = current_allocator->free_lists;
current_allocator->free_lists = list;
+ g_unlock (current_allocator);
}
}
diff --git a/glib/gstrfuncs.c b/glib/gstrfuncs.c
index ad28978ee..e154c56dc 100644
--- a/glib/gstrfuncs.c
+++ b/glib/gstrfuncs.c
@@ -17,6 +17,10 @@
* Boston, MA 02111-1307, USA.
*/
+/*
+ * MT safe
+ */
+
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
@@ -208,7 +212,8 @@ g_strtod (const gchar *nptr,
gchar*
g_strerror (gint errnum)
{
- static char msg[64];
+ static GStaticPrivate msg_private = G_STATIC_PRIVATE_INIT;
+ char *msg;
#ifdef HAVE_STRERROR
return strerror (errnum);
@@ -634,7 +639,14 @@ g_strerror (gint errnum)
if ((errnum > 0) && (errnum <= sys_nerr))
return sys_errlist [errnum];
#endif /* NO_SYS_ERRLIST */
-
+
+ msg = g_static_private_get (&msg_private);
+ if( !msg )
+ {
+ msg = g_new( gchar, 64 );
+ g_static_private_set (&msg_private, msg, g_free);
+ }
+
sprintf (msg, "unknown error (%d)", errnum);
return msg;
}
@@ -642,7 +654,8 @@ g_strerror (gint errnum)
gchar*
g_strsignal (gint signum)
{
- static char msg[64];
+ static GStaticPrivate msg_private = G_STATIC_PRIVATE_INIT;
+ char *msg;
#ifdef HAVE_STRSIGNAL
extern char *strsignal (int sig);
@@ -748,6 +761,13 @@ g_strsignal (gint signum)
extern char *sys_siglist[];
return sys_siglist [signum];
#endif /* NO_SYS_SIGLIST */
+
+ msg = g_static_private_get (&msg_private);
+ if( !msg )
+ {
+ msg = g_new( gchar, 64 );
+ g_static_private_set (&msg_private, msg, g_free);
+ }
sprintf (msg, "unknown signal (%d)", signum);
return msg;
diff --git a/glib/gstring.c b/glib/gstring.c
index fa84fe7a2..312a54060 100644
--- a/glib/gstring.c
+++ b/glib/gstring.c
@@ -16,6 +16,11 @@
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
+
+/*
+ * MT safe
+ */
+
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
@@ -43,7 +48,7 @@ struct _GRealString
gint alloc;
};
-
+static G_LOCK_DEFINE(string_mem_chunk);
static GMemChunk *string_mem_chunk = NULL;
/* Hash Functions.
@@ -202,12 +207,14 @@ g_string_sized_new (guint dfl_size)
{
GRealString *string;
+ g_lock (string_mem_chunk);
if (!string_mem_chunk)
string_mem_chunk = g_mem_chunk_new ("string mem chunk",
sizeof (GRealString),
1024, G_ALLOC_AND_FREE);
string = g_chunk_new (GRealString, string_mem_chunk);
+ g_unlock (string_mem_chunk);
string->alloc = 0;
string->len = 0;
@@ -241,7 +248,9 @@ g_string_free (GString *string,
if (free_segment)
g_free (string->str);
+ g_lock (string_mem_chunk);
g_mem_chunk_free (string_mem_chunk, string);
+ g_unlock (string_mem_chunk);
}
GString*
diff --git a/glib/gtimer.c b/glib/gtimer.c
index 6e58fa0bd..0b6e86a8a 100644
--- a/glib/gtimer.c
+++ b/glib/gtimer.c
@@ -17,6 +17,10 @@
* Boston, MA 02111-1307, USA.
*/
+/*
+ * MT safe
+ */
+
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
diff --git a/glib/gtree.c b/glib/gtree.c
index 4d9e98a0b..006f15db7 100644
--- a/glib/gtree.c
+++ b/glib/gtree.c
@@ -16,6 +16,11 @@
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
+
+/*
+ * MT safe
+ */
+
#include "glib.h"
@@ -78,6 +83,7 @@ static GTreeNode* g_tree_node_rotate_right (GTreeNode *node);
static void g_tree_node_check (GTreeNode *node);
+static G_LOCK_DEFINE(g_tree_global);
static GMemChunk *node_mem_chunk = NULL;
static GTreeNode *node_free_list = NULL;
@@ -88,6 +94,7 @@ g_tree_node_new (gpointer key,
{
GTreeNode *node;
+ g_lock (g_tree_global);
if (node_free_list)
{
node = node_free_list;
@@ -102,7 +109,8 @@ g_tree_node_new (gpointer key,
G_ALLOC_ONLY);
node = g_chunk_new (GTreeNode, node_mem_chunk);
- }
+ }
+ g_unlock (g_tree_global);
node->balance = 0;
node->left = NULL;
@@ -120,9 +128,11 @@ g_tree_node_destroy (GTreeNode *node)
{
g_tree_node_destroy (node->right);
g_tree_node_destroy (node->left);
+ g_lock (g_tree_global);
node->right = node_free_list;
node_free_list = node;
- }
+ g_unlock (g_tree_global);
+ }
}
@@ -375,9 +385,11 @@ g_tree_node_remove (GTreeNode *node,
node = g_tree_node_restore_right_balance (new_root, old_balance);
}
+ g_lock (g_tree_global);
garbage->right = node_free_list;
node_free_list = garbage;
- }
+ g_unlock (g_tree_global);
+ }
else if (cmp < 0)
{
if (node->left)
diff --git a/glib/gutils.c b/glib/gutils.c
index cc6594937..9a91199b6 100644
--- a/glib/gutils.c
+++ b/glib/gutils.c
@@ -17,6 +17,10 @@
* Boston, MA 02111-1307, USA.
*/
+/*
+ * MT safe for the unix part, FIXME: make the win32 part MT safe as well.
+ */
+
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
@@ -367,11 +371,14 @@ g_getenv (const gchar *variable)
#endif
}
+static G_LOCK_DEFINE(g_utils_global);
+
static gchar *g_tmp_dir = NULL;
static gchar *g_user_name = NULL;
static gchar *g_real_name = NULL;
static gchar *g_home_dir = NULL;
+/* HOLDS: g_utils_global_lock */
static void
g_get_any_init (void)
{
@@ -442,14 +449,16 @@ g_get_any_init (void)
g_home_dir = NULL;
# endif /* !NATIVE_WIN32 */
#endif /* !HAVE_PWD_H */
- }
+ }
}
gchar*
g_get_user_name (void)
{
+ g_lock (g_utils_global);
if (!g_tmp_dir)
g_get_any_init ();
+ g_unlock (g_utils_global);
return g_user_name;
}
@@ -457,9 +466,11 @@ g_get_user_name (void)
gchar*
g_get_real_name (void)
{
+ g_lock (g_utils_global);
if (!g_tmp_dir)
g_get_any_init ();
-
+ g_unlock (g_utils_global);
+
return g_real_name;
}
@@ -472,8 +483,10 @@ g_get_real_name (void)
gchar*
g_get_home_dir (void)
{
+ g_lock (g_utils_global);
if (!g_tmp_dir)
g_get_any_init ();
+ g_unlock (g_utils_global);
return g_home_dir;
}
@@ -488,8 +501,10 @@ g_get_home_dir (void)
gchar*
g_get_tmp_dir (void)
{
+ g_lock (g_utils_global);
if (!g_tmp_dir)
g_get_any_init ();
+ g_unlock (g_utils_global);
return g_tmp_dir;
}
@@ -499,16 +514,25 @@ static gchar *g_prgname = NULL;
gchar*
g_get_prgname (void)
{
- return g_prgname;
+ gchar* retval;
+
+ g_lock (g_utils_global);
+ retval = g_prgname;
+ g_unlock (g_utils_global);
+
+ return retval;
}
void
g_set_prgname (const gchar *prgname)
{
- gchar *c = g_prgname;
-
+ gchar *c;
+
+ g_lock (g_utils_global);
+ c = g_prgname;
g_prgname = g_strdup (prgname);
g_free (c);
+ g_unlock (g_utils_global);
}
guint
diff --git a/glist.c b/glist.c
index 41a09dd18..e74dee872 100644
--- a/glist.c
+++ b/glist.c
@@ -16,6 +16,11 @@
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
+
+/*
+ * MT safe
+ */
+
#include "glib.h"
@@ -31,9 +36,11 @@ struct _GAllocator /* from gmem.c */
};
static GAllocator *current_allocator = NULL;
+static G_LOCK_DEFINE(current_allocator);
-void
-g_list_push_allocator (GAllocator *allocator)
+/* HOLDS: current_allocator_lock */
+static void
+g_list_validate_allocator (GAllocator *allocator)
{
g_return_if_fail (allocator != NULL);
g_return_if_fail (allocator->is_unused == TRUE);
@@ -58,13 +65,22 @@ g_list_push_allocator (GAllocator *allocator)
}
allocator->is_unused = FALSE;
+}
+
+void
+g_list_push_allocator(GAllocator *allocator)
+{
+ g_list_validate_allocator ( allocator );
+ g_lock (current_allocator);
allocator->last = current_allocator;
current_allocator = allocator;
+ g_unlock (current_allocator);
}
void
g_list_pop_allocator (void)
{
+ g_lock (current_allocator);
if (current_allocator)
{
GAllocator *allocator;
@@ -74,6 +90,7 @@ g_list_pop_allocator (void)
allocator->last = NULL;
allocator->is_unused = TRUE;
}
+ g_unlock (current_allocator);
}
GList*
@@ -81,9 +98,15 @@ g_list_alloc (void)
{
GList *list;
+ g_lock (current_allocator);
if (!current_allocator)
- g_list_push_allocator (g_allocator_new ("GLib default GList allocator", 1024));
-
+ {
+ GAllocator *allocator = g_allocator_new ("GLib default GList allocator",
+ 1024);
+ g_list_validate_allocator (allocator);
+ allocator->last = NULL;
+ current_allocator = allocator;
+ }
if (!current_allocator->free_lists)
{
list = g_chunk_new (GList, current_allocator->mem_chunk);
@@ -103,6 +126,7 @@ g_list_alloc (void)
current_allocator->free_lists = list->next;
}
}
+ g_unlock (current_allocator);
list->next = NULL;
list->prev = NULL;
@@ -112,23 +136,31 @@ g_list_alloc (void)
void
g_list_free (GList *list)
{
+#if 0
if (list)
{
- list->data = list->next;
+ list->data = list->next;
+ g_lock (current_allocator);
list->next = current_allocator->free_lists;
current_allocator->free_lists = list;
+ g_unlock (current_allocator);
}
+#endif
}
void
g_list_free_1 (GList *list)
{
+#if 0
if (list)
{
- list->data = NULL;
+ list->data = NULL;
+ g_lock (current_allocator);
list->next = current_allocator->free_lists;
current_allocator->free_lists = list;
+ g_unlock (current_allocator);
}
+#endif
}
GList*
diff --git a/gmain.c b/gmain.c
index 1f13e9097..5d3ae8d46 100644
--- a/gmain.c
+++ b/gmain.c
@@ -20,9 +20,14 @@
* Boston, MA 02111-1307, USA.
*/
+/*
+ * MT safe
+ */
+
#include "glib.h"
#include <sys/time.h>
#include <unistd.h>
+#include <errno.h>
#include "config.h"
/* Types */
@@ -65,9 +70,12 @@ struct _GPollRec {
/* Forward declarations */
-static void g_main_poll (gint timeout,
- gboolean use_priority,
- gint priority);
+static void g_main_poll (gint timeout,
+ gboolean use_priority,
+ gint priority);
+static void g_main_poll_add_unlocked (gint priority,
+ GPollFD *fd);
+
static gboolean g_timeout_prepare (gpointer source_data,
GTimeVal *current_time,
gint *timeout);
@@ -90,6 +98,11 @@ static gboolean g_idle_dispatch (gpointer source_data,
static GSList *pending_dispatches = NULL;
static GHookList source_list = { 0 };
+/* The following lock is used for both the list of sources
+ * and the list of poll records
+ */
+static G_LOCK_DEFINE (main_loop);
+
static GSourceFuncs timeout_funcs = {
g_timeout_prepare,
g_timeout_check,
@@ -104,6 +117,17 @@ static GSourceFuncs idle_funcs = {
(GDestroyNotify)g_free
};
+static GPollRec *poll_records = NULL;
+static GPollRec *poll_free_list = NULL;
+static GMemChunk *poll_chunk;
+static guint n_poll_records = 0;
+
+/* this pipe is used to wake up the main loop when a source is added.
+ */
+static gint wake_up_pipe[2] = { -1, -1 };
+static GPollFD wake_up_rec;
+static gboolean poll_waiting = FALSE;
+
#ifdef HAVE_POLL
static GPollFunc poll_func = (GPollFunc)poll;
#else
@@ -205,8 +229,11 @@ g_source_add (gint priority,
gpointer user_data,
GDestroyNotify notify)
{
+ guint return_val;
GSource *source;
+ g_lock (main_loop);
+
if (!source_list.is_setup)
g_hook_list_init (&source_list, sizeof(GSource));
@@ -224,31 +251,55 @@ g_source_add (gint priority,
if (can_recurse)
source->hook.flags |= G_SOURCE_CAN_RECURSE;
- return source->hook.hook_id;
+ return_val = source->hook.hook_id;
+
+ /* Now wake up the main loop if it is waiting in the poll() */
+
+ if (poll_waiting)
+ {
+ poll_waiting = FALSE;
+ write (wake_up_pipe[1], "A", 1);
+ }
+
+ g_unlock (main_loop);
+
+ return return_val;
}
void
g_source_remove (guint tag)
{
- GHook *hook = g_hook_get (&source_list, tag);
+ GHook *hook;
+
+ g_lock (main_loop);
+
+ hook = g_hook_get (&source_list, tag);
if (hook)
{
GSource *source = (GSource *)hook;
((GSourceFuncs *)source->hook.func)->destroy (source->source_data);
g_hook_destroy_link (&source_list, hook);
}
+
+ g_unlock (main_loop);
}
void
g_source_remove_by_user_data (gpointer user_data)
{
- GHook *hook = g_hook_find_data (&source_list, TRUE, user_data);
+ GHook *hook;
+
+ g_lock (main_loop);
+
+ hook = g_hook_find_data (&source_list, TRUE, user_data);
if (hook)
{
GSource *source = (GSource *)hook;
((GSourceFuncs *)source->hook.func)->destroy (source->source_data);
g_hook_destroy_link (&source_list, hook);
}
+
+ g_unlock (main_loop);
}
static gboolean
@@ -262,7 +313,11 @@ g_source_find_source_data (GHook *hook,
void
g_source_remove_by_source_data (gpointer source_data)
{
- GHook *hook = g_hook_find (&source_list, TRUE,
+ GHook *hook;
+
+ g_lock (main_loop);
+
+ hook = g_hook_find (&source_list, TRUE,
g_source_find_source_data, source_data);
if (hook)
{
@@ -270,6 +325,8 @@ g_source_remove_by_source_data (gpointer source_data)
((GSourceFuncs *)source->hook.func)->destroy (source->source_data);
g_hook_destroy_link (&source_list, hook);
}
+
+ g_unlock (main_loop);
}
void g_get_current_time (GTimeVal *result)
@@ -279,6 +336,7 @@ void g_get_current_time (GTimeVal *result)
/* Running the main loop */
+/* HOLDS: main_loop_lock */
static void
g_main_dispatch (GTimeVal *current_time)
{
@@ -294,10 +352,20 @@ g_main_dispatch (GTimeVal *current_time)
if (G_HOOK_IS_VALID (source))
{
+ gboolean (*dispatch) (gpointer, GTimeVal *, gpointer);
+ gpointer hook_data = source->hook.data;
+ gpointer source_data = source->source_data;
+
+ dispatch = ((GSourceFuncs *)source->hook.func)->dispatch;
+
source->hook.flags |= G_HOOK_FLAG_IN_CALL;
- need_destroy = !((GSourceFuncs *)source->hook.func)->dispatch (source->source_data,
- current_time,
- source->hook.data);
+
+ g_unlock (main_loop);
+ need_destroy = ! dispatch(source_data,
+ current_time,
+ hook_data);
+ g_lock (main_loop);
+
source->hook.flags &= ~G_HOOK_FLAG_IN_CALL;
if (need_destroy)
@@ -320,10 +388,13 @@ g_main_iterate (gboolean block, gboolean dispatch)
gint nready = 0;
gint current_priority = 0;
gint timeout;
+ gboolean retval = FALSE;
g_return_val_if_fail (!block || dispatch, FALSE);
g_get_current_time (&current_time);
+
+ g_lock (main_loop);
/* If recursing, finish up current dispatch, before starting over */
if (pending_dispatches)
@@ -331,6 +402,7 @@ g_main_iterate (gboolean block, gboolean dispatch)
if (dispatch)
g_main_dispatch (&current_time);
+ g_unlock (main_loop);
return TRUE;
}
@@ -362,6 +434,7 @@ g_main_iterate (gboolean block, gboolean dispatch)
if (!dispatch)
{
g_hook_unref (&source_list, hook);
+ g_unlock (main_loop);
return TRUE;
}
else
@@ -426,6 +499,7 @@ g_main_iterate (gboolean block, gboolean dispatch)
else
{
g_hook_unref (&source_list, hook);
+ g_unlock (main_loop);
return TRUE;
}
}
@@ -442,10 +516,12 @@ g_main_iterate (gboolean block, gboolean dispatch)
{
pending_dispatches = g_slist_reverse (pending_dispatches);
g_main_dispatch (&current_time);
- return TRUE;
+ retval = TRUE;
}
- else
- return FALSE;
+
+ g_unlock (main_loop);
+
+ return retval;
}
/* See if any events are pending
@@ -494,11 +570,7 @@ g_main_destroy (GMainLoop *loop)
g_free (loop);
}
-static GPollRec *poll_records = NULL;
-static GPollRec *poll_free_list = NULL;
-static GMemChunk *poll_chunk;
-static guint n_poll_records = 0;
-
+/* HOLDS: main_loop_lock */
static void
g_main_poll (gint timeout, gboolean use_priority, gint priority)
{
@@ -508,6 +580,17 @@ g_main_poll (gint timeout, gboolean use_priority, gint priority)
gint i;
gint npoll;
+ if (wake_up_pipe[0] < 0)
+ {
+ if (pipe (wake_up_pipe) < 0)
+ g_error ("Cannot create pipe main loop wake-up: %s\n",
+ g_strerror(errno));
+
+ wake_up_rec.fd = wake_up_pipe[0];
+ wake_up_rec.events = G_IO_IN;
+ g_main_poll_add_unlocked (0, &wake_up_rec);
+ }
+
pollrec = poll_records;
i = 0;
while (pollrec && (!use_priority || priority >= pollrec->priority))
@@ -520,8 +603,20 @@ g_main_poll (gint timeout, gboolean use_priority, gint priority)
i++;
}
+ poll_waiting = TRUE;
+
+ g_unlock (main_loop);
npoll = i;
(*poll_func) (fd_array, npoll, timeout);
+ g_lock (main_loop);
+
+ if (!poll_waiting)
+ {
+ gchar c;
+ read (wake_up_pipe[0], &c, 1);
+ }
+ else
+ poll_waiting = FALSE;
pollrec = poll_records;
i = 0;
@@ -539,12 +634,28 @@ void
g_main_poll_add (gint priority,
GPollFD *fd)
{
+ g_lock (main_loop);
+ g_main_poll_add_unlocked (priority, fd);
+ g_unlock (main_loop);
+}
+
+static void
+g_main_poll_add_unlocked (gint priority,
+ GPollFD *fd)
+{
GPollRec *lastrec, *pollrec, *newrec;
if (!poll_chunk)
poll_chunk = g_mem_chunk_create (GPollRec, 32, G_ALLOC_ONLY);
- newrec = g_chunk_new (GPollRec, poll_chunk);
+ if (poll_free_list)
+ {
+ newrec = poll_free_list;
+ poll_free_list = newrec->next;
+ }
+ else
+ newrec = g_chunk_new (GPollRec, poll_chunk);
+
newrec->fd = fd;
newrec->priority = priority;
@@ -564,6 +675,8 @@ g_main_poll_add (gint priority,
newrec->next = pollrec;
n_poll_records++;
+
+ g_unlock (main_loop);
}
void
@@ -571,6 +684,8 @@ g_main_poll_remove (GPollFD *fd)
{
GPollRec *pollrec, *lastrec;
+ g_lock (main_loop);
+
lastrec = NULL;
pollrec = poll_records;
@@ -585,12 +700,15 @@ g_main_poll_remove (GPollFD *fd)
pollrec->next = poll_free_list;
poll_free_list = pollrec;
+
+ n_poll_records--;
+ break;
}
lastrec = pollrec;
pollrec = pollrec->next;
}
- n_poll_records--;
+ g_unlock (main_loop);
}
void
diff --git a/gmem.c b/gmem.c
index c29ee660f..a4907ffca 100644
--- a/gmem.c
+++ b/gmem.c
@@ -17,6 +17,10 @@
* Boston, MA 02111-1307, USA.
*/
+/*
+ * MT safe
+ */
+
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
@@ -48,8 +52,12 @@
*/
#if defined(ENABLE_MEM_PROFILE) && defined(ENABLE_MEM_PROFILE_EXCLUDES_MEM_CHUNKS)
-#define ENTER_MEM_CHUNK_ROUTINE() allocating_for_mem_chunk++
-#define LEAVE_MEM_CHUNK_ROUTINE() allocating_for_mem_chunk--
+#define ENTER_MEM_CHUNK_ROUTINE() \
+ g_static_set (allocating_for_mem_chunk, \
+ g_static_get (allocating_for_mem_chunk) + 1)
+#define ENTER_MEM_CHUNK_ROUTINE() \
+ g_static_set (allocating_for_mem_chunk, \
+ g_static_get (allocating_for_mem_chunk) - 1)
#else
#define ENTER_MEM_CHUNK_ROUTINE()
#define LEAVE_MEM_CHUNK_ROUTINE()
@@ -117,13 +125,19 @@ static gint g_mem_chunk_area_search (GMemArea *a,
gchar *addr);
+/* here we can't use StaticMutexes, as they depend upon a working
+ * g_malloc, the same holds true for StaticPrivate */
+static GMutex* mem_chunks_lock = NULL;
static GRealMemChunk *mem_chunks = NULL;
#ifdef ENABLE_MEM_PROFILE
+static GMutex* mem_profile_lock;
static gulong allocations[MEM_PROFILE_TABLE_SIZE] = { 0 };
static gulong allocated_mem = 0;
static gulong freed_mem = 0;
-static gint allocating_for_mem_chunk = 0;
+static GPrivate* allocating_for_mem_chunk = NULL;
+#define IS_IN_MEM_CHUNK_ROUTINE() \
+ GPOINTER_TO_UINT (g_static_get (allocating_for_mem_chunk))
#endif /* ENABLE_MEM_PROFILE */
@@ -174,8 +188,9 @@ g_malloc (gulong size)
*t = size;
#ifdef ENABLE_MEM_PROFILE
+ g_mutex_lock (mem_profile_lock);
# ifdef ENABLE_MEM_PROFILE_EXCLUDES_MEM_CHUNKS
- if(!allocating_for_mem_chunk) {
+ if(!IS_IN_MEM_CHUNK_ROUTINE()) {
# endif
if (size <= MEM_PROFILE_TABLE_SIZE - 1)
allocations[size-1] += 1;
@@ -185,6 +200,7 @@ g_malloc (gulong size)
# ifdef ENABLE_MEM_PROFILE_EXCLUDES_MEM_CHUNKS
}
# endif
+ g_mutex_unlock (mem_profile_lock);
#endif /* ENABLE_MEM_PROFILE */
#endif /* ENABLE_MEM_PROFILE || ENABLE_MEM_CHECK */
@@ -237,8 +253,9 @@ g_malloc0 (gulong size)
*t = size;
# ifdef ENABLE_MEM_PROFILE
+ g_mutex_lock (mem_profile_lock);
# ifdef ENABLE_MEM_PROFILE_EXCLUDES_MEM_CHUNKS
- if(!allocating_for_mem_chunk) {
+ if(!IS_IN_MEM_CHUNK_ROUTINE()) {
# endif
if (size <= (MEM_PROFILE_TABLE_SIZE - 1))
allocations[size-1] += 1;
@@ -248,8 +265,9 @@ g_malloc0 (gulong size)
# ifdef ENABLE_MEM_PROFILE_EXCLUDES_MEM_CHUNKS
}
# endif
+ g_mutex_unlock (mem_profile_lock);
# endif /* ENABLE_MEM_PROFILE */
-#endif /* ENABLE_MEM_PROFILE */
+#endif /* ENABLE_MEM_PROFILE || ENABLE_MEM_CHECK */
return p;
@@ -286,7 +304,9 @@ g_realloc (gpointer mem,
#if defined(ENABLE_MEM_PROFILE) || defined(ENABLE_MEM_CHECK)
t = (gulong*) ((guchar*) mem - SIZEOF_LONG);
#ifdef ENABLE_MEM_PROFILE
+ g_mutex_lock (mem_profile);
freed_mem += *t;
+ g_mutex_unlock (mem_profile);
#endif /* ENABLE_MEM_PROFILE */
mem = t;
#endif /* ENABLE_MEM_PROFILE || ENABLE_MEM_CHECK */
@@ -321,8 +341,9 @@ g_realloc (gpointer mem,
*t = size;
#ifdef ENABLE_MEM_PROFILE
+ g_mutex_lock (mem_profile_lock);
#ifdef ENABLE_MEM_PROFILE_EXCLUDES_MEM_CHUNKS
- if(!allocating_for_mem_chunk) {
+ if(!IS_IN_MEM_CHUNK_ROUTINE()) {
#endif
if (size <= (MEM_PROFILE_TABLE_SIZE - 1))
allocations[size-1] += 1;
@@ -332,6 +353,7 @@ g_realloc (gpointer mem,
#ifdef ENABLE_MEM_PROFILE_EXCLUDES_MEM_CHUNKS
}
#endif
+ g_mutex_unlock (mem_profile_lock);
#endif /* ENABLE_MEM_PROFILE */
#endif /* ENABLE_MEM_PROFILE || ENABLE_MEM_CHECK */
@@ -352,8 +374,10 @@ g_free (gpointer mem)
#if defined(ENABLE_MEM_PROFILE) || defined(ENABLE_MEM_CHECK)
t = (gulong*) ((guchar*) mem - SIZEOF_LONG);
size = *t;
-#ifdef ENABLE_MEM_PROFILE
+#ifdef ENABLE_MEM_PROFILE
+ g_mutex_lock (mem_profile);
freed_mem += size;
+ g_mutex_unlock (mem_profile);
#endif /* ENABLE_MEM_PROFILE */
mem = t;
#endif /* ENABLE_MEM_PROFILE || ENABLE_MEM_CHECK */
@@ -380,19 +404,29 @@ g_mem_profile (void)
{
#ifdef ENABLE_MEM_PROFILE
gint i;
-
+ gulong local_allocations[MEM_PROFILE_TABLE_SIZE];
+ gulong local_allocated_mem;
+ gulong local_freed_mem;
+
+ g_mutex_lock (mem_profile);
+ for (i = 0; i < (MEM_PROFILE_TABLE_SIZE - 1); i++)
+ local_allocations[i] = allocations[i];
+ local_allocated_mem = allocated_mem;
+ local_freed_mem = freed_mem;
+ g_mutex_unlock (mem_profile);
+
for (i = 0; i < (MEM_PROFILE_TABLE_SIZE - 1); i++)
- if (allocations[i] > 0)
+ if (local_allocations[i] > 0)
g_log (g_log_domain_glib, G_LOG_LEVEL_INFO,
- "%lu allocations of %d bytes\n", allocations[i], i + 1);
+ "%lu allocations of %d bytes\n", local_allocations[i], i + 1);
- if (allocations[MEM_PROFILE_TABLE_SIZE - 1] > 0)
+ if (local_allocations[MEM_PROFILE_TABLE_SIZE - 1] > 0)
g_log (g_log_domain_glib, G_LOG_LEVEL_INFO,
"%lu allocations of greater than %d bytes\n",
- allocations[MEM_PROFILE_TABLE_SIZE - 1], MEM_PROFILE_TABLE_SIZE - 1);
- g_log (g_log_domain_glib, G_LOG_LEVEL_INFO, "%lu bytes allocated\n", allocated_mem);
- g_log (g_log_domain_glib, G_LOG_LEVEL_INFO, "%lu bytes freed\n", freed_mem);
- g_log (g_log_domain_glib, G_LOG_LEVEL_INFO, "%lu bytes in use\n", allocated_mem - freed_mem);
+ local_allocations[MEM_PROFILE_TABLE_SIZE - 1], MEM_PROFILE_TABLE_SIZE - 1);
+ g_log (g_log_domain_glib, G_LOG_LEVEL_INFO, "%lu bytes allocated\n", local_allocated_mem);
+ g_log (g_log_domain_glib, G_LOG_LEVEL_INFO, "%lu bytes freed\n", local_freed_mem);
+ g_log (g_log_domain_glib, G_LOG_LEVEL_INFO, "%lu bytes in use\n", local_allocated_mem - local_freed_mem);
#endif /* ENABLE_MEM_PROFILE */
}
@@ -460,11 +494,13 @@ g_mem_chunk_new (gchar *name,
mem_chunk->area_size += mem_chunk->atom_size - (mem_chunk->area_size % mem_chunk->atom_size);
*/
+ g_mutex_lock (mem_chunks_lock);
mem_chunk->next = mem_chunks;
mem_chunk->prev = NULL;
if (mem_chunks)
mem_chunks->prev = mem_chunk;
mem_chunks = mem_chunk;
+ g_mutex_unlock (mem_chunks_lock);
LEAVE_MEM_CHUNK_ROUTINE();
@@ -497,8 +533,10 @@ g_mem_chunk_destroy (GMemChunk *mem_chunk)
if (rmem_chunk->prev)
rmem_chunk->prev->next = rmem_chunk->next;
+ g_mutex_lock (mem_chunks_lock);
if (rmem_chunk == mem_chunks)
mem_chunks = mem_chunks->next;
+ g_mutex_unlock (mem_chunks_lock);
if (rmem_chunk->type == G_ALLOC_AND_FREE)
g_tree_destroy (rmem_chunk->mem_tree);
@@ -826,21 +864,26 @@ g_mem_chunk_info (void)
gint count;
count = 0;
+ g_mutex_lock (mem_chunks_lock);
mem_chunk = mem_chunks;
while (mem_chunk)
{
count += 1;
mem_chunk = mem_chunk->next;
}
+ g_mutex_unlock (mem_chunks_lock);
g_log (g_log_domain_glib, G_LOG_LEVEL_INFO, "%d mem chunks\n", count);
+ g_mutex_lock (mem_chunks_lock);
mem_chunk = mem_chunks;
+ g_mutex_unlock (mem_chunks_lock);
+
while (mem_chunk)
{
g_mem_chunk_print ((GMemChunk*) mem_chunk);
mem_chunk = mem_chunk->next;
- }
+ }
}
void
@@ -848,7 +891,9 @@ g_blow_chunks (void)
{
GRealMemChunk *mem_chunk;
+ g_mutex_lock (mem_chunks_lock);
mem_chunk = mem_chunks;
+ g_mutex_unlock (mem_chunks_lock);
while (mem_chunk)
{
g_mem_chunk_clean ((GMemChunk*) mem_chunk);
@@ -940,3 +985,13 @@ g_allocator_free (GAllocator *allocator)
g_free (allocator);
}
+
+void
+g_mem_init (void)
+{
+ mem_chunks_lock = g_mutex_new();
+#ifdef ENABLE_MEM_PROFILE
+ mem_profile_lock = g_mutex_new();
+ allocating_for_mem_chunk = g_private_new(NULL);
+#endif
+}
diff --git a/gmessages.c b/gmessages.c
index e0c6eacb1..eb8aed7a8 100644
--- a/gmessages.c
+++ b/gmessages.c
@@ -17,6 +17,10 @@
* Boston, MA 02111-1307, USA.
*/
+/*
+ * MT safe
+ */
+
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
@@ -31,7 +35,7 @@
#endif
#ifdef NATIVE_WIN32
-/* Just use stdio. If we're out of memroy, we're hosed anyway. */
+/* Just use stdio. If we're out of memory, we're hosed anyway. */
#undef write
static inline int
@@ -67,6 +71,9 @@ struct _GLogHandler
/* --- variables --- */
+
+static GMutex* g_messages_lock = NULL;
+
const gchar *g_log_domain_glib = "GLib";
static GLogDomain *g_log_domains = NULL;
static GLogLevelFlags g_log_always_fatal = G_LOG_FATAL_MASK;
@@ -76,20 +83,27 @@ static GErrorFunc glib_error_func = NULL;
static GWarningFunc glib_warning_func = NULL;
static GPrintFunc glib_message_func = NULL;
+static GPrivate* g_log_depth = NULL;
+
/* --- functions --- */
static inline GLogDomain*
g_log_find_domain (const gchar *log_domain)
{
register GLogDomain *domain;
-
+
+ g_mutex_lock (g_messages_lock);
domain = g_log_domains;
while (domain)
{
if (strcmp (domain->log_domain, log_domain) == 0)
- return domain;
+ {
+ g_mutex_unlock (g_messages_lock);
+ return domain;
+ }
domain = domain->next;
}
+ g_mutex_unlock (g_messages_lock);
return NULL;
}
@@ -102,8 +116,11 @@ g_log_domain_new (const gchar *log_domain)
domain->log_domain = g_strdup (log_domain);
domain->fatal_mask = G_LOG_FATAL_MASK;
domain->handlers = NULL;
+
+ g_mutex_lock (g_messages_lock);
domain->next = g_log_domains;
g_log_domains = domain;
+ g_mutex_unlock (g_messages_lock);
return domain;
}
@@ -116,7 +133,9 @@ g_log_domain_check_free (GLogDomain *domain)
{
register GLogDomain *last, *work;
- last = NULL;
+ last = NULL;
+
+ g_mutex_lock (g_messages_lock);
work = g_log_domains;
while (work)
{
@@ -131,7 +150,8 @@ g_log_domain_check_free (GLogDomain *domain)
break;
}
work = work->next;
- }
+ }
+ g_mutex_unlock (g_messages_lock);
}
}
@@ -170,8 +190,10 @@ g_log_set_always_fatal (GLogLevelFlags fatal_mask)
/* remove bogus flag */
fatal_mask &= ~G_LOG_FLAG_FATAL;
+ g_mutex_lock (g_messages_lock);
old_mask = g_log_always_fatal;
g_log_always_fatal = fatal_mask;
+ g_mutex_unlock (g_messages_lock);
return old_mask;
}
@@ -223,7 +245,9 @@ g_log_set_handler (const gchar *log_domain,
domain = g_log_domain_new (log_domain);
handler = g_new (GLogHandler, 1);
+ g_mutex_lock (g_messages_lock);
handler->id = ++handler_id;
+ g_mutex_unlock (g_messages_lock);
handler->log_level = log_levels;
handler->log_func = log_func;
handler->data = user_data;
@@ -311,19 +335,25 @@ g_logv (const gchar *log_domain,
test_level = 1 << i;
if (log_level & test_level)
{
- static guint g_log_depth = 0;
+ guint depth = GPOINTER_TO_UINT (g_private_get (g_log_depth));
GLogDomain *domain;
GLogFunc log_func;
gpointer data = NULL;
domain = g_log_find_domain (log_domain ? log_domain : "");
- if (g_log_depth++)
+ if (depth)
test_level |= G_LOG_FLAG_RECURSION;
- if ((((domain ? domain->fatal_mask : G_LOG_FATAL_MASK) | g_log_always_fatal) &
- test_level) != 0)
- test_level |= G_LOG_FLAG_FATAL;
+ depth++;
+ g_private_set (g_log_depth, GUINT_TO_POINTER (depth));
+
+ g_mutex_lock (g_messages_lock);
+ if ((((domain ? domain->fatal_mask : G_LOG_FATAL_MASK) |
+ g_log_always_fatal) & test_level) != 0)
+ test_level |= G_LOG_FLAG_FATAL;
+ g_mutex_unlock (g_messages_lock);
+
log_func = g_log_domain_get_handler (domain, test_level, &data);
log_func (log_domain, test_level, buffer, data);
@@ -332,7 +362,8 @@ g_logv (const gchar *log_domain,
if (test_level & G_LOG_FLAG_FATAL)
abort ();
- g_log_depth--;
+ depth--;
+ g_private_set (g_log_depth, GUINT_TO_POINTER (depth));
}
}
}
@@ -362,8 +393,11 @@ g_log_default_handler (const gchar *log_domain,
gint fd;
#endif
gboolean in_recursion;
- gboolean is_fatal;
-
+ gboolean is_fatal;
+ GErrorFunc local_glib_error_func;
+ GWarningFunc local_glib_warning_func;
+ GPrintFunc local_glib_message_func;
+
in_recursion = (log_level & G_LOG_FLAG_RECURSION) != 0;
is_fatal = (log_level & G_LOG_FLAG_FATAL) != 0;
log_level &= G_LOG_LEVEL_MASK;
@@ -380,13 +414,19 @@ g_log_default_handler (const gchar *log_domain,
fd = (log_level >= G_LOG_LEVEL_MESSAGE) ? 1 : 2;
#endif
+ g_mutex_lock (g_messages_lock);
+ local_glib_error_func = glib_error_func;
+ local_glib_warning_func = glib_warning_func;
+ local_glib_message_func = glib_message_func;
+ g_mutex_unlock (g_messages_lock);
+
switch (log_level)
{
case G_LOG_LEVEL_ERROR:
- if (!log_domain && glib_error_func)
+ if (!log_domain && local_glib_error_func)
{
/* compatibility code */
- glib_error_func (message);
+ local_glib_error_func (message);
return;
}
/* use write(2) for output, in case we are out of memeory */
@@ -428,10 +468,10 @@ g_log_default_handler (const gchar *log_domain,
write (fd, "\n", 1);
break;
case G_LOG_LEVEL_WARNING:
- if (!log_domain && glib_warning_func)
+ if (!log_domain && local_glib_warning_func)
{
/* compatibility code */
- glib_warning_func (message);
+ local_glib_warning_func (message);
return;
}
if (log_domain)
@@ -453,10 +493,10 @@ g_log_default_handler (const gchar *log_domain,
write (fd, "\n", 1);
break;
case G_LOG_LEVEL_MESSAGE:
- if (!log_domain && glib_message_func)
+ if (!log_domain && local_glib_message_func)
{
/* compatibility code */
- glib_message_func (message);
+ local_glib_message_func (message);
return;
}
if (log_domain)
@@ -553,8 +593,10 @@ g_set_print_handler (GPrintFunc func)
{
GPrintFunc old_print_func;
+ g_mutex_lock (g_messages_lock);
old_print_func = glib_print_func;
glib_print_func = func;
+ g_mutex_unlock (g_messages_lock);
return old_print_func;
}
@@ -565,6 +607,7 @@ g_print (const gchar *format,
{
va_list args;
gchar *string;
+ GPrintFunc local_glib_print_func;
g_return_if_fail (format != NULL);
@@ -572,8 +615,12 @@ g_print (const gchar *format,
string = g_strdup_vprintf (format, args);
va_end (args);
- if (glib_print_func)
- glib_print_func (string);
+ g_mutex_lock (g_messages_lock);
+ local_glib_print_func = glib_print_func;
+ g_mutex_unlock (g_messages_lock);
+
+ if (local_glib_print_func)
+ local_glib_print_func (string);
else
{
fputs (string, stdout);
@@ -587,8 +634,10 @@ g_set_printerr_handler (GPrintFunc func)
{
GPrintFunc old_printerr_func;
+ g_mutex_lock (g_messages_lock);
old_printerr_func = glib_printerr_func;
glib_printerr_func = func;
+ g_mutex_unlock (g_messages_lock);
return old_printerr_func;
}
@@ -599,6 +648,7 @@ g_printerr (const gchar *format,
{
va_list args;
gchar *string;
+ GPrintFunc local_glib_printerr_func;
g_return_if_fail (format != NULL);
@@ -606,8 +656,12 @@ g_printerr (const gchar *format,
string = g_strdup_vprintf (format, args);
va_end (args);
- if (glib_printerr_func)
- glib_printerr_func (string);
+ g_mutex_lock (g_messages_lock);
+ local_glib_printerr_func = glib_printerr_func;
+ g_mutex_unlock (g_messages_lock);
+
+ if (local_glib_printerr_func)
+ local_glib_printerr_func (string);
else
{
fputs (string, stderr);
@@ -622,9 +676,11 @@ g_set_error_handler (GErrorFunc func)
{
GErrorFunc old_error_func;
+ g_mutex_lock (g_messages_lock);
old_error_func = glib_error_func;
glib_error_func = func;
-
+ g_mutex_unlock (g_messages_lock);
+
return old_error_func;
}
@@ -634,8 +690,10 @@ g_set_warning_handler (GWarningFunc func)
{
GWarningFunc old_warning_func;
+ g_mutex_lock (g_messages_lock);
old_warning_func = glib_warning_func;
glib_warning_func = func;
+ g_mutex_unlock (g_messages_lock);
return old_warning_func;
}
@@ -646,8 +704,17 @@ g_set_message_handler (GPrintFunc func)
{
GPrintFunc old_message_func;
+ g_mutex_lock (g_messages_lock);
old_message_func = glib_message_func;
glib_message_func = func;
+ g_mutex_unlock (g_messages_lock);
return old_message_func;
}
+
+void
+g_messages_init (void)
+{
+ g_messages_lock = g_mutex_new();
+ g_log_depth = g_private_new(NULL);
+}
diff --git a/gmodule/ChangeLog b/gmodule/ChangeLog
index 4de434321..86dd222ae 100644
--- a/gmodule/ChangeLog
+++ b/gmodule/ChangeLog
@@ -1,3 +1,8 @@
+1998-12-10 Sebastian Wilhelmi <wilhelmi@ira.uka.de>
+
+ * gmodule.c: Made it MT safe, the g_module_error() is now thread
+ specific.
+
Fri Nov 20 14:43:44 1998 Tim Janik <timj@gtk.org>
* gmodule.c (_g_module_build_path): added empty default imlementation
diff --git a/gmodule/gmodule-dl.c b/gmodule/gmodule-dl.c
index 034e94bf0..4a5686616 100644
--- a/gmodule/gmodule-dl.c
+++ b/gmodule/gmodule-dl.c
@@ -16,6 +16,11 @@
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
+
+/*
+ * MT safe
+ */
+
#include <dlfcn.h>
/* Perl includes <nlist.h> and <link.h> instead of <dlfcn.h> on some systmes? */
diff --git a/gmodule/gmodule-dld.c b/gmodule/gmodule-dld.c
index b1d68d7d3..53b269b48 100644
--- a/gmodule/gmodule-dld.c
+++ b/gmodule/gmodule-dld.c
@@ -16,6 +16,11 @@
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
+
+/*
+ * MT safe
+ */
+
#include <dl.h>
diff --git a/gmodule/gmodule-win32.c b/gmodule/gmodule-win32.c
index 0cc1bacc3..98643ad23 100644
--- a/gmodule/gmodule-win32.c
+++ b/gmodule/gmodule-win32.c
@@ -17,6 +17,11 @@
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
+
+/*
+ * MT safe
+ */
+
#include <stdio.h>
#include <windows.h>
diff --git a/gmodule/gmodule.c b/gmodule/gmodule.c
index 9efa3f51b..71f614570 100644
--- a/gmodule/gmodule.c
+++ b/gmodule/gmodule.c
@@ -16,6 +16,11 @@
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
+
+/*
+ * MT safe
+ */
+
#include "gmodule.h"
#include "gmoduleconf.h"
#include <errno.h>
@@ -59,10 +64,11 @@ static inline GModule* g_module_find_by_name (const gchar *name);
/* --- variables --- */
-const char *g_log_domain_gmodule = "GModule";
-static GModule *modules = NULL;
-static GModule *main_module = NULL;
-static gchar *module_error = NULL;
+static G_LOCK_DEFINE (g_module_global);
+const char *g_log_domain_gmodule = "GModule";
+static GModule *modules = NULL;
+static GModule *main_module = NULL;
+static GStaticPrivate module_error_private = G_STATIC_PRIVATE_INIT;
/* --- inline functions --- */
@@ -70,30 +76,45 @@ static inline GModule*
g_module_find_by_handle (gpointer handle)
{
GModule *module;
+ GModule *retval = NULL;
+ g_lock (g_module_global);
if (main_module && main_module->handle == handle)
- return main_module;
-
- for (module = modules; module; module = module->next)
- if (handle == module->handle)
- return module;
- return NULL;
+ retval = main_module;
+ else
+ for (module = modules; module; module = module->next)
+ if (handle == module->handle)
+ {
+ retval = module;
+ break;
+ }
+ g_unlock (g_module_global);
+
+ return retval;
}
static inline GModule*
g_module_find_by_name (const gchar *name)
{
GModule *module;
+ GModule *retval = NULL;
+ g_lock (g_module_global);
for (module = modules; module; module = module->next)
if (strcmp (name, module->file_name) == 0)
- return module;
- return NULL;
+ {
+ retval = module;
+ break;
+ }
+ g_unlock (g_module_global);
+
+ return retval;
}
static inline void
g_module_set_error (const gchar *error)
{
+ gchar* module_error = g_static_private_get (&module_error_private);
if (module_error)
g_free (module_error);
if (error)
@@ -101,6 +122,7 @@ g_module_set_error (const gchar *error)
else
module_error = NULL;
errno = 0;
+ g_static_private_set (&module_error_private, module_error, g_free);
}
@@ -175,7 +197,8 @@ g_module_open (const gchar *file_name,
CHECK_ERROR (NULL);
if (!file_name)
- {
+ {
+ g_lock (g_module_global);
if (!main_module)
{
handle = _g_module_self ();
@@ -190,7 +213,8 @@ g_module_open (const gchar *file_name,
main_module->next = NULL;
}
}
-
+ g_unlock (g_module_global);
+
return main_module;
}
@@ -222,8 +246,8 @@ g_module_open (const gchar *file_name,
return module;
}
- saved_error = module_error;
- module_error = NULL;
+ saved_error = g_module_error();
+ g_static_private_set (&module_error_private, NULL, NULL);
g_module_set_error (NULL);
module = g_new (GModule, 1);
@@ -232,8 +256,10 @@ g_module_open (const gchar *file_name,
module->ref_count = 1;
module->is_resident = FALSE;
module->unload = NULL;
+ g_lock (g_module_global);
module->next = modules;
modules = module;
+ g_unlock (g_module_global);
/* check initialization */
if (g_module_symbol (module, "g_module_check_init", (gpointer) &check_init))
@@ -286,6 +312,8 @@ g_module_close (GModule *module)
GModule *node;
last = NULL;
+
+ g_lock (g_module_global);
node = modules;
while (node)
{
@@ -301,6 +329,7 @@ g_module_close (GModule *module)
node = last->next;
}
module->next = NULL;
+ g_unlock (g_module_global);
_g_module_close (module->handle, FALSE);
g_free (module->file_name);
@@ -308,7 +337,7 @@ g_module_close (GModule *module)
g_free (module);
}
- return module_error == NULL;
+ return g_module_error() == NULL;
}
void
@@ -322,7 +351,7 @@ g_module_make_resident (GModule *module)
gchar*
g_module_error (void)
{
- return module_error;
+ return g_static_private_get (&module_error_private);
}
gboolean
@@ -330,6 +359,7 @@ g_module_symbol (GModule *module,
const gchar *symbol_name,
gpointer *symbol)
{
+ gchar *module_error;
if (symbol)
*symbol = NULL;
CHECK_ERROR (FALSE);
@@ -350,7 +380,7 @@ g_module_symbol (GModule *module,
*symbol = _g_module_symbol (module->handle, symbol_name);
#endif /* !G_MODULE_NEED_USCORE */
- if (module_error)
+ if ((module_error = g_module_error()))
{
gchar *error;
diff --git a/gmutex.c b/gmutex.c
new file mode 100644
index 000000000..b1d894799
--- /dev/null
+++ b/gmutex.c
@@ -0,0 +1,176 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * gmutex.c: MT safety related functions
+ * Copyright 1998 Sebastian Wilhelmi; University of Karlsruhe
+ * Owen Taylor
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * MT safe
+ */
+
+#include "glib.h"
+
+typedef struct _GStaticPrivateNode GStaticPrivateNode;
+
+struct _GStaticPrivateNode {
+ gpointer data;
+ GDestroyNotify destroy;
+};
+
+static void g_static_private_free_data (gpointer data);
+static void g_thread_fail (void);
+
+/* Global variables */
+
+gboolean g_thread_use_default_impl = TRUE;
+gboolean g_thread_supported = FALSE;
+
+GThreadFunctions g_thread_functions_for_glib_use = {
+ (GMutex*(*)())g_thread_fail, /* mutex_new */
+ NULL, /* mutex_lock */
+ NULL, /* mutex_trylock */
+ NULL, /* mutex_unlock */
+ NULL, /* mutex_free */
+ (GCond*(*)())g_thread_fail, /* cond_new */
+ NULL, /* cond_signal */
+ NULL, /* cond_broadcast */
+ NULL, /* cond_wait */
+ NULL, /* cond_timed_wait */
+ NULL, /* cond_free */
+ (GPrivate*(*)(GDestroyNotify))g_thread_fail, /* private_new */
+ NULL, /* private_get */
+ NULL, /* private_set */
+};
+
+/* Local data */
+
+static GMutex *g_mutex_protect_static_mutex_allocation = NULL;
+static GMutex *g_thread_specific_mutex = NULL;
+static GPrivate *g_thread_specific_private = NULL;
+
+/* This must be called only once, before any threads are created.
+ * It will only be called from g_thread_init() in -lgthread.
+ */
+void
+g_mutex_init (void)
+{
+ /* We let the main thread (the one that calls g_thread_init) inherit
+ the data, that it set before calling g_thread_init */
+ gpointer private_old = g_thread_specific_private;
+ g_thread_specific_private = g_private_new (g_static_private_free_data);
+
+ /* we can not use g_private_set here, as g_thread_supported is not
+ yet set TRUE, whereas the private_set function is already set. */
+ g_thread_functions_for_glib_use.private_set (g_thread_specific_private,
+ private_old);
+
+ g_mutex_protect_static_mutex_allocation = g_mutex_new();
+ g_thread_specific_mutex = g_mutex_new();
+}
+
+GMutex *
+g_static_mutex_get_mutex_impl (GMutex** mutex)
+{
+ if (!g_thread_supported)
+ return NULL;
+
+ g_assert (g_mutex_protect_static_mutex_allocation);
+
+ g_mutex_lock (g_mutex_protect_static_mutex_allocation);
+
+ if (!(*mutex))
+ *mutex = g_mutex_new();
+
+ g_mutex_unlock (g_mutex_protect_static_mutex_allocation);
+
+ return *mutex;
+}
+
+gpointer
+g_static_private_get (GStaticPrivate *private)
+{
+ GArray *array;
+
+ array = g_private_get (g_thread_specific_private);
+ if (!array)
+ return NULL;
+
+ if (!private->index)
+ return NULL;
+ else if (private->index <= array->len)
+ return g_array_index (array, GStaticPrivateNode, (private->index - 1)).data;
+ else
+ return NULL;
+}
+
+void
+g_static_private_set (GStaticPrivate *private,
+ gpointer data,
+ GDestroyNotify notify)
+{
+ GArray *array;
+ static guint next_index = 0;
+
+ array = g_private_get (g_thread_specific_private);
+ if (!array)
+ {
+ array = g_array_new (FALSE, FALSE, sizeof(GStaticPrivateNode));
+ g_private_set (g_thread_specific_private, array);
+ }
+
+ if (!private->index)
+ {
+ g_mutex_lock (g_thread_specific_mutex);
+
+ if (!private->index)
+ private->index = ++next_index;
+
+ g_mutex_unlock (g_thread_specific_mutex);
+ }
+
+ if (private->index > array->len)
+ g_array_set_size (array, private->index);
+
+ g_array_index (array, GStaticPrivateNode, (private->index - 1)).data = data;
+ g_array_index (array, GStaticPrivateNode, (private->index - 1)).destroy = notify;
+}
+
+static void
+g_static_private_free_data (gpointer data)
+{
+ if (data)
+ {
+ GArray* array = data;
+ guint i;
+
+ for (i = 0; i < array->len; i++ )
+ {
+ GStaticPrivateNode *node = &g_array_index (array, GStaticPrivateNode, i);
+ if (node->data && node->destroy)
+ node->destroy (node->data);
+ }
+ }
+}
+
+static void
+g_thread_fail (void)
+{
+ g_error ("The thread system is not yet initialized.");
+}
diff --git a/gnode.c b/gnode.c
index 9f6e544ba..089a4996d 100644
--- a/gnode.c
+++ b/gnode.c
@@ -19,6 +19,11 @@
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
+
+/*
+ * MT safe
+ */
+
#include "glib.h"
/* node allocation
@@ -34,10 +39,12 @@ struct _GAllocator /* from gmem.c */
GNode *free_nodes; /* implementation specific */
};
+static G_LOCK_DEFINE(current_allocator);
static GAllocator *current_allocator = NULL;
-void
-g_node_push_allocator (GAllocator *allocator)
+/* HOLDS: current_allocator_lock */
+static void
+g_node_validate_allocator (GAllocator *allocator)
{
g_return_if_fail (allocator != NULL);
g_return_if_fail (allocator->is_unused == TRUE);
@@ -62,13 +69,22 @@ g_node_push_allocator (GAllocator *allocator)
}
allocator->is_unused = FALSE;
+}
+
+void
+g_node_push_allocator (GAllocator *allocator)
+{
+ g_node_validate_allocator ( allocator );
+ g_lock (current_allocator);
allocator->last = current_allocator;
current_allocator = allocator;
+ g_unlock (current_allocator);
}
void
g_node_pop_allocator (void)
{
+ g_lock (current_allocator);
if (current_allocator)
{
GAllocator *allocator;
@@ -78,6 +94,7 @@ g_node_pop_allocator (void)
allocator->last = NULL;
allocator->is_unused = TRUE;
}
+ g_unlock (current_allocator);
}
@@ -87,9 +104,15 @@ g_node_new (gpointer data)
{
GNode *node;
+ g_lock (current_allocator);
if (!current_allocator)
- g_node_push_allocator (g_allocator_new ("GLib default GNode allocator", 1024));
-
+ {
+ GAllocator *allocator = g_allocator_new ("GLib default GNode allocator",
+ 1024);
+ g_node_validate_allocator (allocator);
+ allocator->last = NULL;
+ current_allocator = allocator;
+ }
if (!current_allocator->free_nodes)
node = g_chunk_new (GNode, current_allocator->mem_chunk);
else
@@ -97,6 +120,7 @@ g_node_new (gpointer data)
node = current_allocator->free_nodes;
current_allocator->free_nodes = node->next;
}
+ g_unlock (current_allocator);
node->data = data;
node->next = NULL;
@@ -122,9 +146,11 @@ g_nodes_free (GNode *node)
else
break;
}
-
+
+ g_lock (current_allocator);
parent->next = current_allocator->free_nodes;
current_allocator->free_nodes = node;
+ g_unlock (current_allocator);
}
void
diff --git a/gprimes.c b/gprimes.c
index 3d45c1ef7..404ebd605 100644
--- a/gprimes.c
+++ b/gprimes.c
@@ -16,6 +16,11 @@
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
+
+/*
+ * MT safe
+ */
+
#include "glib.h"
static const guint g_primes[] =
diff --git a/grel.c b/grel.c
index 5fdf88098..544da6bfc 100644
--- a/grel.c
+++ b/grel.c
@@ -15,6 +15,11 @@
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+
+/*
+ * MT safe
+ */
+
#include "glib.h"
#include <stdarg.h>
#include <string.h>
diff --git a/gscanner.c b/gscanner.c
index 02985a7f7..c6fd0dd4e 100644
--- a/gscanner.c
+++ b/gscanner.c
@@ -19,6 +19,11 @@
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
+
+/*
+ * MT safe
+ */
+
#define __gscanner_c__
#ifdef HAVE_CONFIG_H
diff --git a/gslist.c b/gslist.c
index 4efe2a575..1ed517ff6 100644
--- a/gslist.c
+++ b/gslist.c
@@ -16,6 +16,11 @@
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
+
+/*
+ * MT safe
+ */
+
#include "glib.h"
@@ -30,10 +35,12 @@ struct _GAllocator /* from gmem.c */
GSList *free_lists; /* implementation specific */
};
+static G_LOCK_DEFINE(current_allocator);
static GAllocator *current_allocator = NULL;
-void
-g_slist_push_allocator (GAllocator *allocator)
+/* HOLDS: current_allocator_lock */
+static void
+g_slist_validate_allocator (GAllocator *allocator)
{
g_return_if_fail (allocator != NULL);
g_return_if_fail (allocator->is_unused == TRUE);
@@ -58,13 +65,22 @@ g_slist_push_allocator (GAllocator *allocator)
}
allocator->is_unused = FALSE;
+}
+
+void
+g_slist_push_allocator (GAllocator *allocator)
+{
+ g_slist_validate_allocator (allocator);
+ g_lock (current_allocator);
allocator->last = current_allocator;
current_allocator = allocator;
+ g_unlock (current_allocator);
}
void
g_slist_pop_allocator (void)
{
+ g_lock (current_allocator);
if (current_allocator)
{
GAllocator *allocator;
@@ -74,6 +90,7 @@ g_slist_pop_allocator (void)
allocator->last = NULL;
allocator->is_unused = TRUE;
}
+ g_unlock (current_allocator);
}
GSList*
@@ -81,9 +98,15 @@ g_slist_alloc (void)
{
GSList *list;
+ g_lock (current_allocator);
if (!current_allocator)
- g_slist_push_allocator (g_allocator_new ("GLib default GSList allocator", 1024));
-
+ {
+ GAllocator *allocator = g_allocator_new ("GLib default GSList allocator",
+ 1024);
+ g_slist_validate_allocator (allocator);
+ allocator->last = NULL;
+ current_allocator = allocator;
+ }
if (!current_allocator->free_lists)
{
list = g_chunk_new (GSList, current_allocator->mem_chunk);
@@ -103,6 +126,8 @@ g_slist_alloc (void)
current_allocator->free_lists = list->next;
}
}
+ g_unlock (current_allocator);
+
list->next = NULL;
return list;
@@ -114,8 +139,10 @@ g_slist_free (GSList *list)
if (list)
{
list->data = list->next;
+ g_lock (current_allocator);
list->next = current_allocator->free_lists;
current_allocator->free_lists = list;
+ g_unlock (current_allocator);
}
}
@@ -125,8 +152,10 @@ g_slist_free_1 (GSList *list)
if (list)
{
list->data = NULL;
+ g_lock (current_allocator);
list->next = current_allocator->free_lists;
current_allocator->free_lists = list;
+ g_unlock (current_allocator);
}
}
diff --git a/gstrfuncs.c b/gstrfuncs.c
index ad28978ee..e154c56dc 100644
--- a/gstrfuncs.c
+++ b/gstrfuncs.c
@@ -17,6 +17,10 @@
* Boston, MA 02111-1307, USA.
*/
+/*
+ * MT safe
+ */
+
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
@@ -208,7 +212,8 @@ g_strtod (const gchar *nptr,
gchar*
g_strerror (gint errnum)
{
- static char msg[64];
+ static GStaticPrivate msg_private = G_STATIC_PRIVATE_INIT;
+ char *msg;
#ifdef HAVE_STRERROR
return strerror (errnum);
@@ -634,7 +639,14 @@ g_strerror (gint errnum)
if ((errnum > 0) && (errnum <= sys_nerr))
return sys_errlist [errnum];
#endif /* NO_SYS_ERRLIST */
-
+
+ msg = g_static_private_get (&msg_private);
+ if( !msg )
+ {
+ msg = g_new( gchar, 64 );
+ g_static_private_set (&msg_private, msg, g_free);
+ }
+
sprintf (msg, "unknown error (%d)", errnum);
return msg;
}
@@ -642,7 +654,8 @@ g_strerror (gint errnum)
gchar*
g_strsignal (gint signum)
{
- static char msg[64];
+ static GStaticPrivate msg_private = G_STATIC_PRIVATE_INIT;
+ char *msg;
#ifdef HAVE_STRSIGNAL
extern char *strsignal (int sig);
@@ -748,6 +761,13 @@ g_strsignal (gint signum)
extern char *sys_siglist[];
return sys_siglist [signum];
#endif /* NO_SYS_SIGLIST */
+
+ msg = g_static_private_get (&msg_private);
+ if( !msg )
+ {
+ msg = g_new( gchar, 64 );
+ g_static_private_set (&msg_private, msg, g_free);
+ }
sprintf (msg, "unknown signal (%d)", signum);
return msg;
diff --git a/gstring.c b/gstring.c
index fa84fe7a2..312a54060 100644
--- a/gstring.c
+++ b/gstring.c
@@ -16,6 +16,11 @@
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
+
+/*
+ * MT safe
+ */
+
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
@@ -43,7 +48,7 @@ struct _GRealString
gint alloc;
};
-
+static G_LOCK_DEFINE(string_mem_chunk);
static GMemChunk *string_mem_chunk = NULL;
/* Hash Functions.
@@ -202,12 +207,14 @@ g_string_sized_new (guint dfl_size)
{
GRealString *string;
+ g_lock (string_mem_chunk);
if (!string_mem_chunk)
string_mem_chunk = g_mem_chunk_new ("string mem chunk",
sizeof (GRealString),
1024, G_ALLOC_AND_FREE);
string = g_chunk_new (GRealString, string_mem_chunk);
+ g_unlock (string_mem_chunk);
string->alloc = 0;
string->len = 0;
@@ -241,7 +248,9 @@ g_string_free (GString *string,
if (free_segment)
g_free (string->str);
+ g_lock (string_mem_chunk);
g_mem_chunk_free (string_mem_chunk, string);
+ g_unlock (string_mem_chunk);
}
GString*
diff --git a/gthread/.cvsignore b/gthread/.cvsignore
new file mode 100644
index 000000000..ba4d80249
--- /dev/null
+++ b/gthread/.cvsignore
@@ -0,0 +1,8 @@
+Makefile.in
+Makefile
+.deps
+*.lo
+*.o
+.libs
+*.la
+testgthread
diff --git a/gthread/Makefile.am b/gthread/Makefile.am
new file mode 100644
index 000000000..3b7bc9748
--- /dev/null
+++ b/gthread/Makefile.am
@@ -0,0 +1,21 @@
+## Process this file with automake to produce Makefile.in
+
+INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/gthread -DG_LOG_DOMAIN=g_log_domain_gthread
+
+EXTRA_DIST = \
+ gthread-posix.c
+
+libglib = $(top_builddir)/libglib.la # -lglib
+
+lib_LTLIBRARIES = libgthread.la
+
+libgthread_la_SOURCES = gthread.c
+libgthread_la_LDFLAGS = \
+ -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) \
+ -release $(LT_RELEASE)
+
+libgthread_la_LIBADD = \
+ @G_THREAD_LIBS@
+
+noinst_PROGRAMS = testgthread
+testgthread_LDADD = ../libglib.la libgthread.la
diff --git a/gthread/gthread-none.c b/gthread/gthread-none.c
new file mode 100644
index 000000000..1240fd580
--- /dev/null
+++ b/gthread/gthread-none.c
@@ -0,0 +1,28 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * gthread.c: fallback thread system implementation
+ * Copyright 1998 Sebastian Wilhelmi; University of Karlsruhe
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * MT safe
+ */
+
+static GThreadFunctions
+g_mutex_functions_for_glib_use_default; /* is NULLified */
diff --git a/gthread/gthread-nspr.c b/gthread/gthread-nspr.c
new file mode 100644
index 000000000..77672e5f0
--- /dev/null
+++ b/gthread/gthread-nspr.c
@@ -0,0 +1,218 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * gthread.c: nspr thread system implementation
+ * Copyright 1998 Sebastian Wilhelmi; University of Karlsruhe
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * MT safe
+ */
+
+#include <prpdce.h>
+#include <prthread.h>
+#include <stdlib.h>
+
+#ifdef G_DISABLE_ASSERT
+
+#define STDERR_ASSERT(expr)
+
+#else /* G_DISABLE_ASSERT */
+
+#define STDERR_ASSERT(expr) G_STMT_START{ \
+ if (!(expr)) \
+ g_log (G_LOG_DOMAIN, \
+ G_LOG_LEVEL_ERROR, \
+ "file %s: line %d: assertion failed: (%s)", \
+ __FILE__, \
+ __LINE__, \
+ #expr); }G_STMT_END
+
+#endif /* G_DISABLE_ASSERT */
+
+/* NOTE: the functions g_mutex_lock and g_mutex_unlock may not use
+ functions from gmem.c and gmessages.c; */
+
+static gboolean
+g_mutex_trylock_nspr_impl (GMutex * mutex)
+{
+ PRStatus status = PRP_TryLock ((PRLock *) mutex);
+ if (status == PR_SUCCESS)
+ {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static void
+g_cond_wait_nspr_impl (GCond * cond,
+ GMutex * entered_mutex)
+{
+ PRStatus status = PRP_NakedWait ((PRCondVar *) cond,
+ (PRLock *) entered_mutex,
+ PR_INTERVAL_NO_TIMEOUT);
+ g_assert (status == PR_SUCCESS);
+}
+
+#define G_MICROSEC 1000000
+
+static gboolean
+g_cond_timed_wait_nspr_impl (GCond * cond,
+ GMutex * entered_mutex,
+ GTimeVal * abs_time)
+{
+ PRStatus status;
+ PRIntervalTime interval;
+ GTimeVal current_time;
+ glong microsecs;
+
+ g_return_val_if_fail (cond != NULL, FALSE);
+ g_return_val_if_fail (entered_mutex != NULL, FALSE);
+
+ g_get_current_time (&current_time);
+
+ if (abs_time->tv_sec < current_time.tv_sec ||
+ (abs_time->tv_sec == current_time.tv_sec &&
+ abs_time->tv_usec < current_time.tv_usec))
+ return FALSE;
+
+ interval = PR_SecondsToInterval (abs_time->tv_sec - current_time.tv_sec);
+ microsecs = abs_time->tv_usec - current_time.tv_usec;
+ if (microsecs < 0)
+ interval -= PR_MicrosecondsToInterval (-microsecs);
+ else
+ interval += PR_MicrosecondsToInterval (microsecs);
+
+ status = PRP_NakedWait ((PRCondVar *) cond, (PRLock *) entered_mutex,
+ interval);
+
+ g_assert (status == PR_SUCCESS);
+
+ g_get_current_time (&current_time);
+
+ if (abs_time->tv_sec < current_time.tv_sec ||
+ (abs_time->tv_sec == current_time.tv_sec &&
+ abs_time->tv_usec < current_time.tv_usec))
+ return FALSE;
+ return TRUE;
+}
+
+typedef struct _GPrivateNSPRData GPrivateNSPRData;
+struct _GPrivateNSPRData
+ {
+ gpointer data;
+ GDestroyNotify destructor;
+ };
+
+typedef struct _GPrivateNSPR GPrivateNSPR;
+struct _GPrivateNSPR
+ {
+ PRUintn private;
+ GDestroyNotify destructor;
+ };
+
+static GPrivateNSPRData *
+g_private_nspr_data_constructor (GDestroyNotify destructor, gpointer data)
+{
+ /* we can not use g_new and friends, as they might use private data by
+ themself */
+ GPrivateNSPRData *private = malloc (sizeof (GPrivateNSPRData));
+ g_assert (private);
+ private->data = data;
+ private->destructor = destructor;
+
+ return private;
+}
+
+static void
+g_private_nspr_data_destructor (gpointer data)
+{
+ GPrivateNSPRData *private = data;
+ if (private->destructor && private->data)
+ (*private->destructor) (private->data);
+ free (private);
+}
+
+static GPrivate *
+g_private_new_nspr_impl (GDestroyNotify destructor)
+{
+ GPrivateNSPR *result = g_new (GPrivateNSPR, 1);
+ PRStatus status = PR_NewThreadPrivateIndex (&result->private,
+ g_private_nspr_data_destructor);
+ g_assert (status == PR_SUCCESS);
+
+ result->destructor = destructor;
+ return (GPrivate *) result;
+}
+
+/* NOTE: the functions g_private_get and g_private_set may not use
+ functions from gmem.c and gmessages.c */
+
+static GPrivateNSPRData *
+g_private_nspr_data_get (GPrivateNSPR * private)
+{
+ GPrivateNSPRData *data;
+
+ STDERR_ASSERT (private);
+
+ data = PR_GetThreadPrivate (private->private);
+ if (!data)
+ {
+ data = g_private_nspr_data_constructor (private->destructor, NULL);
+ STDERR_ASSERT (PR_SetThreadPrivate (private->private, data)
+ == PR_SUCCESS);
+ }
+
+ return data;
+}
+
+static void
+g_private_set_nspr_impl (GPrivate * private, gpointer value)
+{
+ if (!private)
+ return;
+
+ g_private_nspr_data_get ((GPrivateNSPR *) private)->data = value;
+}
+
+static gpointer
+g_private_get_nspr_impl (GPrivate * private)
+{
+ if (!private)
+ return NULL;
+
+ return g_private_nspr_data_get ((GPrivateNSPR *) private)->data;
+}
+
+static GThreadFunctions g_thread_functions_for_glib_use_default =
+{
+ (GMutex * (*)())PR_NewLock,
+ (void (*)(GMutex *)) PR_Lock,
+ g_mutex_trylock_nspr_impl,
+ (void (*)(GMutex *)) PR_Unlock,
+ (void (*)(GMutex *)) PR_DestroyLock,
+ (GCond * (*)())PRP_NewNakedCondVar,
+ (void (*)(GCond *)) PRP_NakedNotify,
+ (void (*)(GCond *)) PRP_NakedBroadcast,
+ g_cond_wait_nspr_impl,
+ g_cond_timed_wait_nspr_impl,
+ (void (*)(GCond *)) PRP_DestroyNakedCondVar,
+ g_private_new_nspr_impl,
+ g_private_get_nspr_impl,
+ g_private_set_nspr_impl
+};
diff --git a/gthread/gthread-posix.c b/gthread/gthread-posix.c
new file mode 100644
index 000000000..5b59672fe
--- /dev/null
+++ b/gthread/gthread-posix.c
@@ -0,0 +1,176 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * gthread.c: posix thread system implementation
+ * Copyright 1998 Sebastian Wilhelmi; University of Karlsruhe
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * MT safe
+ */
+
+#include <pthread.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <sys/time.h>
+
+#define posix_print_error( name, num ) \
+ g_error( "file %s: line %d (%s): error %s during %s", \
+ __FILE__, __LINE__, G_GNUC_PRETTY_FUNCTION, \
+ g_strerror((num)), #name )
+
+#define posix_check_for_error( what ) G_STMT_START{ \
+ int error = (what); \
+ if( error ) { posix_print_error( what, error ); } \
+ }G_STMT_END
+
+static GMutex *
+g_mutex_new_posix_impl (void)
+{
+ GMutex *result = (GMutex *) g_new (pthread_mutex_t, 1);
+ posix_check_for_error (pthread_mutex_init ((pthread_mutex_t *) result, NULL));
+ return result;
+}
+
+static void
+g_mutex_free_posix_impl (GMutex * mutex)
+{
+ posix_check_for_error (pthread_mutex_destroy ((pthread_mutex_t *) mutex));
+ free (mutex);
+}
+
+/* NOTE: the functions g_mutex_lock and g_mutex_unlock may not use
+ functions from gmem.c and gmessages.c; */
+
+/* pthread_mutex_lock, pthread_mutex_unlock can be taken directly, as
+ signature and semantic are right, but without error check then!!!!,
+ we might want to change this therefore. */
+
+static gboolean
+g_mutex_trylock_posix_impl (GMutex * mutex)
+{
+ int result;
+
+ result = pthread_mutex_trylock ((pthread_mutex_t *) mutex);
+ if (result != EBUSY)
+ return FALSE;
+
+ posix_check_for_error (result);
+ return TRUE;
+}
+
+static GCond *
+g_cond_new_posix_impl (void)
+{
+ GCond *result = (GCond *) g_new (pthread_cond_t, 1);
+ posix_check_for_error (pthread_cond_init ((pthread_cond_t *) result, NULL));
+ return result;
+}
+
+/* pthread_cond_signal, pthread_cond_broadcast and pthread_cond_wait
+ can be taken directly, as signature and semantic are right, but
+ without error check then!!!!, we might want to change this
+ therfore. */
+
+#define G_MICROSEC 1000000
+#define G_NANOSEC 1000000000
+
+static gboolean
+g_cond_timed_wait_posix_impl (GCond * cond,
+ GMutex * entered_mutex,
+ GTimeVal * abs_time)
+{
+ int result;
+ struct timespec end_time;
+ gboolean timed_out;
+
+ g_return_val_if_fail (cond != NULL, FALSE);
+ g_return_val_if_fail (entered_mutex != NULL, FALSE);
+
+ if (!abs_time)
+ {
+ g_cond_wait (cond, entered_mutex);
+ return TRUE;
+ }
+
+ end_time.tv_sec = abs_time->tv_sec;
+ end_time.tv_nsec = abs_time->tv_usec * (G_NANOSEC / G_MICROSEC);
+ g_assert (end_time.tv_nsec < G_NANOSEC);
+ result = pthread_cond_timedwait ((pthread_cond_t *) cond,
+ (pthread_mutex_t *) entered_mutex,
+ &end_time);
+ timed_out = (result == ETIMEDOUT);
+ if (!timed_out)
+ posix_check_for_error (result);
+ return !timed_out;
+}
+
+static void
+g_cond_free_posix_impl (GCond * cond)
+{
+ posix_check_for_error (pthread_cond_destroy ((pthread_cond_t *) cond));
+ g_free (cond);
+}
+
+static GPrivate *
+g_private_new_posix_impl (GDestroyNotify destructor)
+{
+ GPrivate *result = (GPrivate *) g_new (pthread_key_t, 1);
+ posix_check_for_error (pthread_key_create ((pthread_key_t *) result,
+ destructor));
+ return result;
+}
+
+/* NOTE: the functions g_private_get and g_private_set may not use
+ functions from gmem.c and gmessages.c */
+
+static void
+g_private_set_posix_impl (GPrivate * private, gpointer value)
+{
+ if (!private)
+ return;
+
+ pthread_setspecific (*(pthread_key_t *) private, value);
+}
+
+static gpointer
+g_private_get_posix_impl (GPrivate * private)
+{
+ if (!private)
+ return NULL;
+
+ return pthread_getspecific (*(pthread_key_t *) private);
+}
+
+static GThreadFunctions g_thread_functions_for_glib_use_default =
+{
+ g_mutex_new_posix_impl,
+ (void (*)(GMutex *)) pthread_mutex_lock,
+ g_mutex_trylock_posix_impl,
+ (void (*)(GMutex *)) pthread_mutex_unlock,
+ g_mutex_free_posix_impl,
+ g_cond_new_posix_impl,
+ (void (*)(GCond *)) pthread_cond_signal,
+ (void (*)(GCond *)) pthread_cond_broadcast,
+ (void (*)(GCond *, GMutex *)) pthread_cond_wait,
+ g_cond_timed_wait_posix_impl,
+ g_cond_free_posix_impl,
+ g_private_new_posix_impl,
+ g_private_get_posix_impl,
+ g_private_set_posix_impl
+};
diff --git a/gthread/gthread-solaris.c b/gthread/gthread-solaris.c
new file mode 100644
index 000000000..52d4c5552
--- /dev/null
+++ b/gthread/gthread-solaris.c
@@ -0,0 +1,177 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * gthread.c: solaris thread system implementation
+ * Copyright 1998 Sebastian Wilhelmi; University of Karlsruhe
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * MT safe
+ */
+
+#include <thread.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#define solaris_print_error( name, num ) \
+ g_error( "file %s: line %d (%s): error %s during %s", \
+ __FILE__, __LINE__, G_GNUC_PRETTY_FUNCTION, \
+ g_strerror((num)), #name )
+
+#define solaris_check_for_error( what ) G_STMT_START{ \
+ int error = (what); \
+ if( error ) { solaris_print_error( what, error ); } \
+ }G_STMT_END
+
+static GMutex *
+g_mutex_new_solaris_impl (void)
+{
+ GMutex *result = (GMutex *) g_new (mutex_t, 1);
+ solaris_check_for_error (mutex_init ((mutex_t *) result, USYNC_PROCESS, 0));
+ return result;
+}
+
+static void
+g_mutex_free_solaris_impl (GMutex * mutex)
+{
+ solaris_check_for_error (mutex_destroy ((mutex_t *) mutex));
+ free (mutex);
+}
+
+/* NOTE: the functions g_mutex_lock and g_mutex_unlock may not use
+ functions from gmem.c and gmessages.c; */
+
+/* mutex_lock, mutex_unlock can be taken directly, as
+ signature and semantic are right, but without error check then!!!!,
+ we might want to change this therefore. */
+
+static gboolean
+g_mutex_trylock_solaris_impl (GMutex * mutex)
+{
+ int result;
+ result = mutex_trylock ((mutex_t *) mutex);
+ if (result == EBUSY)
+ return FALSE;
+ solaris_check_for_error (result);
+ return TRUE;
+}
+
+static GCond *
+g_cond_new_solaris_impl ()
+{
+ GCond *result = (GCond *) g_new (cond_t, 1);
+ solaris_check_for_error (cond_init ((cond_t *) result, USYNC_THREAD, 0));
+ return result;
+}
+
+/* cond_signal, cond_broadcast and cond_wait
+ can be taken directly, as signature and semantic are right, but
+ without error check then!!!!, we might want to change this
+ therfore. */
+
+#define G_MICROSEC 1000000
+#define G_NANOSEC 1000000000
+
+static gboolean
+g_cond_timed_wait_solaris_impl (GCond * cond,
+ GMutex * entered_mutex,
+ GTimeVal * abs_time)
+{
+ int result;
+ timestruc_t end_time;
+ gboolean timed_out;
+
+ g_return_val_if_fail (cond != NULL, FALSE);
+ g_return_val_if_fail (entered_mutex != NULL, FALSE);
+
+ if (!abs_time)
+ {
+ g_cond_wait (cond, entered_mutex);
+ return TRUE;
+ }
+
+ end_time.tv_sec = abs_time->tv_sec;
+ end_time.tv_nsec = abs_time->tv_usec * (G_NANOSEC / G_MICROSEC);
+ g_assert (end_time.tv_nsec < G_NANOSEC);
+ result = cond_timedwait ((cond_t *) cond, (mutex_t *) entered_mutex,
+ &end_time);
+ timed_out = (result == ETIME);
+ if (!timed_out)
+ solaris_check_for_error (result);
+ return !timed_out;
+}
+
+static void
+g_cond_free_solaris_impl (GCond * cond)
+{
+ solaris_check_for_error (cond_destroy ((cond_t *) cond));
+ g_free (cond);
+}
+
+static GPrivate *
+g_private_new_solaris_impl (GDestroyNotify destructor)
+{
+ GPrivate *result = (GPrivate *) g_new (thread_key_t,1);
+ solaris_check_for_error (thr_keycreate ((thread_key_t *) result,
+ destructor));
+ return result;
+}
+
+/* NOTE: the functions g_private_get and g_private_set may not use
+ functions from gmem.c and gmessages.c */
+
+static void
+g_private_set_solaris_impl (GPrivate * private, gpointer value)
+{
+ if (!private)
+ return;
+
+ thr_setspecific (*(thread_key_t *) private, value);
+}
+
+static gpointer
+g_private_get_solaris_impl (GPrivate * private)
+{
+ gpointer result;
+
+ if (!private)
+ return NULL;
+
+ thr_getspecific (*(thread_key_t *) private, &result);
+
+ return result;
+}
+
+static GThreadFunctions g_thread_functions_for_glib_use_default =
+{
+ g_mutex_new_solaris_impl,
+ (void (*)(GMutex *)) mutex_lock,
+ g_mutex_trylock_solaris_impl,
+ (void (*)(GMutex *)) mutex_unlock,
+ g_mutex_free_solaris_impl,
+ g_cond_new_solaris_impl,
+ (void (*)(GCond *)) cond_signal,
+ (void (*)(GCond *)) cond_broadcast,
+ (void (*)(GCond *, GMutex *)) cond_wait,
+ g_cond_timed_wait_solaris_impl,
+ g_cond_free_solaris_impl,
+ g_private_new_solaris_impl,
+ g_private_get_solaris_impl,
+ g_private_set_solaris_impl
+};
diff --git a/gthread/gthread.c b/gthread/gthread.c
new file mode 100644
index 000000000..8ada7f89d
--- /dev/null
+++ b/gthread/gthread.c
@@ -0,0 +1,101 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * gthread.c: thread related functions
+ * Copyright 1998 Sebastian Wilhelmi; University of Karlsruhe
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * MT safe
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib.h>
+
+static const char *g_log_domain_gthread = "GThread";
+static gboolean thread_system_already_initialized = FALSE;
+
+#include G_THREAD_SOURCE
+
+void g_mutex_init (void);
+void g_mem_init (void);
+void g_messages_init (void);
+
+void
+g_thread_init(GThreadFunctions* init)
+{
+ gboolean supported;
+
+ if (thread_system_already_initialized)
+ g_error ("the glib thread system may only be initialized once.");
+
+ thread_system_already_initialized = TRUE;
+
+ if (init == NULL)
+ init = &g_thread_functions_for_glib_use_default;
+ else
+ g_thread_use_default_impl = FALSE;
+
+ g_thread_functions_for_glib_use = *init;
+
+ /* It is important, that g_thread_supported is not set before the
+ thread initialization functions of the different modules are
+ called */
+
+ supported =
+ init->mutex_new &&
+ init->mutex_lock &&
+ init->mutex_trylock &&
+ init->mutex_unlock &&
+ init->mutex_free &&
+ init->cond_new &&
+ init->cond_signal &&
+ init->cond_broadcast &&
+ init->cond_wait &&
+ init->cond_timed_wait &&
+ init->cond_free &&
+ init->private_new &&
+ init->private_get &&
+ init->private_get;
+
+ /* if somebody is calling g_thread_init (), it means that he wants to
+ have thread support, so check this */
+
+ if (!supported)
+ {
+ if (g_thread_use_default_impl)
+ g_error ("Threads are not supported on this platform.");
+ else
+ g_error ("The supplied thread function vector is invalid.");
+ }
+
+ /* now call the thread initialization functions of the different
+ glib modules. BTW: order does matter, g_mutex_init MUST be first */
+
+ g_mutex_init ();
+ g_mem_init ();
+ g_messages_init ();
+
+ /* now we can set g_thread_supported and thus enable all the thread
+ functions */
+
+ g_thread_supported = TRUE;
+}
diff --git a/gthread/testgthread.c b/gthread/testgthread.c
new file mode 100644
index 000000000..be81f0490
--- /dev/null
+++ b/gthread/testgthread.c
@@ -0,0 +1,200 @@
+#include <stdlib.h>
+
+#define main testglib_main
+#include <testglib.c>
+#undef main
+
+#define TEST_PRIVATE_THREADS 9
+#define TEST_PRIVATE_ROUNDS 5
+
+void
+test_mutexes ()
+{
+ GMutex *mutex = NULL;
+ GCond *cond = NULL;
+ GStaticMutex static_mutex = G_STATIC_MUTEX_INIT;
+ G_LOCK_DEFINE (test_me);
+
+ if (g_thread_supported)
+ {
+ mutex = g_mutex_new ();
+ cond = g_cond_new ();
+ }
+
+ g_mutex_lock (mutex);
+ g_mutex_unlock (mutex);
+
+ g_static_mutex_lock (static_mutex);
+ g_static_mutex_unlock (static_mutex);
+
+ g_cond_signal (cond);
+ g_cond_broadcast (cond);
+
+ g_lock (test_me);
+ g_unlock (test_me);
+
+ if (g_thread_supported)
+ {
+ g_cond_free (cond);
+ g_mutex_free (mutex);
+ }
+}
+
+#if defined(NSPR) /* we are using nspr threads */
+/* this option must be specified by hand during compile of
+ testgthread. also note, that you have to link with whatever library
+ nspr is building upon, it might otherwise (as on solaris) lead to
+ run time failure, as the mutex functions are defined in libc, but
+ as noops, that will make some nspr assertions fail. */
+#include <prthread.h>
+
+gpointer
+new_thread (GHookFunc func, gpointer data)
+{
+ PRThread *thread = PR_CreateThread (PR_SYSTEM_THREAD, func, data,
+ PR_PRIORITY_NORMAL, PR_LOCAL_THREAD,
+ PR_JOINABLE_THREAD, 0);
+ return thread;
+}
+#define join_thread(thread) PR_JoinThread (thread)
+#define self_thread() PR_GetCurrentThread ()
+
+#elif defined(DEFAULTMUTEX) /* we are using solaris threads */
+
+gpointer
+new_thread (GHookFunc func, gpointer data)
+{
+ thread_t thread;
+ thr_create (NULL, 0, (void *(*)(void *)) func, data, THR_BOUND, &thread);
+ return GUINT_TO_POINTER (thread);
+}
+#define join_thread(thread) \
+ thr_join ((thread_t)GPOINTER_TO_UINT (thread), NULL, NULL)
+#define self_thread() GUINT_TO_POINTER (thr_self ())
+
+#elif defined(PTHREAD_MUTEX_INITIALIZER) /* we are using posix threads */
+gpointer
+new_thread(GHookFunc func, gpointer data)
+{
+ pthread_t thread;
+ pthread_attr_t pthread_attr;
+ pthread_attr_init (&pthread_attr);
+ pthread_attr_setdetachstate (&pthread_attr, PTHREAD_CREATE_JOINABLE);
+ pthread_create (&thread, &pthread_attr, (void *(*)(void *)) func, data);
+ return GUINT_TO_POINTER (thread);
+}
+#define join_thread(thread) \
+ pthread_join ((pthread_t)GPOINTER_TO_UINT (thread), NULL)
+#define self_thread() GUINT_TO_POINTER (pthread_self ())
+
+#else /* we are not having a thread implementation, do nothing */
+
+#define new_thread(func,data) (NULL)
+#define join_thread(thread) ((void)0)
+#define self_thread() NULL
+
+#endif
+
+#define G_MICROSEC 1000000
+
+void
+wait_thread (double seconds)
+{
+ GMutex *mutex;
+ GCond *cond;
+ GTimeVal current_time;
+
+ g_get_current_time (&current_time);
+ mutex = g_mutex_new ();
+ cond = g_cond_new ();
+
+ current_time.tv_sec += (guint) seconds;
+ seconds -= (guint) seconds;
+ current_time.tv_usec += (guint) (seconds * G_MICROSEC);
+ while (current_time.tv_usec >= G_MICROSEC)
+ {
+ current_time.tv_usec -= G_MICROSEC;
+ current_time.tv_sec++;
+ }
+
+ g_mutex_lock (mutex);
+ g_cond_timed_wait (cond, mutex, &current_time);
+ g_mutex_unlock (mutex);
+
+ g_mutex_free (mutex);
+ g_cond_free (cond);
+}
+
+gpointer
+private_constructor ()
+{
+ gpointer *result = g_new (gpointer, 2);
+ result[0] = 0;
+ result[1] = self_thread ();
+ g_print ("allocating data for the thread %p.\n", result[1]);
+ return result;
+}
+
+void
+private_destructor (gpointer data)
+{
+ gpointer *real = data;
+ g_print ("freeing data for the thread %p.\n", real[1]);
+ g_free (real);
+}
+
+GStaticPrivate private;
+
+void
+test_private_func (void *data)
+{
+ guint i = 0;
+ wait_thread (1);
+ while (i < TEST_PRIVATE_ROUNDS)
+ {
+ guint random_value = rand () % 10000;
+ guint *data = g_static_private_get (&private);
+ if (!data)
+ {
+ data = private_constructor ();
+ g_static_private_set (&private, data, private_destructor);
+ }
+ *data = random_value;
+ wait_thread (.2);
+ g_assert (*(guint *) g_static_private_get (&private) == random_value);
+ i++;
+ }
+}
+
+void
+test_private ()
+{
+ int i;
+ gpointer threads[TEST_PRIVATE_THREADS];
+ for (i = 0; i < TEST_PRIVATE_THREADS; i++)
+ {
+ threads[i] = new_thread (test_private_func, (gpointer) i);
+ }
+ for (i = 0; i < TEST_PRIVATE_THREADS; i++)
+ {
+ join_thread (threads[i]);
+ }
+ g_print ("\n");
+}
+
+int
+main ()
+{
+ test_mutexes ();
+
+ g_thread_init (NULL);
+
+ test_mutexes ();
+
+ test_private ();
+
+ /* later we might want to start n copies of that */
+ testglib_main (0, NULL);
+
+ return 0;
+}
diff --git a/gtimer.c b/gtimer.c
index 6e58fa0bd..0b6e86a8a 100644
--- a/gtimer.c
+++ b/gtimer.c
@@ -17,6 +17,10 @@
* Boston, MA 02111-1307, USA.
*/
+/*
+ * MT safe
+ */
+
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
diff --git a/gtree.c b/gtree.c
index 4d9e98a0b..006f15db7 100644
--- a/gtree.c
+++ b/gtree.c
@@ -16,6 +16,11 @@
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
+
+/*
+ * MT safe
+ */
+
#include "glib.h"
@@ -78,6 +83,7 @@ static GTreeNode* g_tree_node_rotate_right (GTreeNode *node);
static void g_tree_node_check (GTreeNode *node);
+static G_LOCK_DEFINE(g_tree_global);
static GMemChunk *node_mem_chunk = NULL;
static GTreeNode *node_free_list = NULL;
@@ -88,6 +94,7 @@ g_tree_node_new (gpointer key,
{
GTreeNode *node;
+ g_lock (g_tree_global);
if (node_free_list)
{
node = node_free_list;
@@ -102,7 +109,8 @@ g_tree_node_new (gpointer key,
G_ALLOC_ONLY);
node = g_chunk_new (GTreeNode, node_mem_chunk);
- }
+ }
+ g_unlock (g_tree_global);
node->balance = 0;
node->left = NULL;
@@ -120,9 +128,11 @@ g_tree_node_destroy (GTreeNode *node)
{
g_tree_node_destroy (node->right);
g_tree_node_destroy (node->left);
+ g_lock (g_tree_global);
node->right = node_free_list;
node_free_list = node;
- }
+ g_unlock (g_tree_global);
+ }
}
@@ -375,9 +385,11 @@ g_tree_node_remove (GTreeNode *node,
node = g_tree_node_restore_right_balance (new_root, old_balance);
}
+ g_lock (g_tree_global);
garbage->right = node_free_list;
node_free_list = garbage;
- }
+ g_unlock (g_tree_global);
+ }
else if (cmp < 0)
{
if (node->left)
diff --git a/gutils.c b/gutils.c
index cc6594937..9a91199b6 100644
--- a/gutils.c
+++ b/gutils.c
@@ -17,6 +17,10 @@
* Boston, MA 02111-1307, USA.
*/
+/*
+ * MT safe for the unix part, FIXME: make the win32 part MT safe as well.
+ */
+
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
@@ -367,11 +371,14 @@ g_getenv (const gchar *variable)
#endif
}
+static G_LOCK_DEFINE(g_utils_global);
+
static gchar *g_tmp_dir = NULL;
static gchar *g_user_name = NULL;
static gchar *g_real_name = NULL;
static gchar *g_home_dir = NULL;
+/* HOLDS: g_utils_global_lock */
static void
g_get_any_init (void)
{
@@ -442,14 +449,16 @@ g_get_any_init (void)
g_home_dir = NULL;
# endif /* !NATIVE_WIN32 */
#endif /* !HAVE_PWD_H */
- }
+ }
}
gchar*
g_get_user_name (void)
{
+ g_lock (g_utils_global);
if (!g_tmp_dir)
g_get_any_init ();
+ g_unlock (g_utils_global);
return g_user_name;
}
@@ -457,9 +466,11 @@ g_get_user_name (void)
gchar*
g_get_real_name (void)
{
+ g_lock (g_utils_global);
if (!g_tmp_dir)
g_get_any_init ();
-
+ g_unlock (g_utils_global);
+
return g_real_name;
}
@@ -472,8 +483,10 @@ g_get_real_name (void)
gchar*
g_get_home_dir (void)
{
+ g_lock (g_utils_global);
if (!g_tmp_dir)
g_get_any_init ();
+ g_unlock (g_utils_global);
return g_home_dir;
}
@@ -488,8 +501,10 @@ g_get_home_dir (void)
gchar*
g_get_tmp_dir (void)
{
+ g_lock (g_utils_global);
if (!g_tmp_dir)
g_get_any_init ();
+ g_unlock (g_utils_global);
return g_tmp_dir;
}
@@ -499,16 +514,25 @@ static gchar *g_prgname = NULL;
gchar*
g_get_prgname (void)
{
- return g_prgname;
+ gchar* retval;
+
+ g_lock (g_utils_global);
+ retval = g_prgname;
+ g_unlock (g_utils_global);
+
+ return retval;
}
void
g_set_prgname (const gchar *prgname)
{
- gchar *c = g_prgname;
-
+ gchar *c;
+
+ g_lock (g_utils_global);
+ c = g_prgname;
g_prgname = g_strdup (prgname);
g_free (c);
+ g_unlock (g_utils_global);
}
guint