This commit merges the glib-threads branch into the main
authorOwen Taylor <otaylor@src.gnome.org>
Tue, 15 Dec 1998 05:28:02 +0000 (05:28 +0000)
committerOwen Taylor <otaylor@src.gnome.org>
Tue, 15 Dec 1998 05:28:02 +0000 (05:28 +0000)
branch. See the ChangeLog for details of the changes.

In brief overview:

 - The set of threading functions can be set
 - A default implementation is provided in -lgthread
 - All static data structures are locked using these
   functions if g_thread_init() is called.

79 files changed:
ChangeLog
ChangeLog.pre-2-0
ChangeLog.pre-2-10
ChangeLog.pre-2-12
ChangeLog.pre-2-2
ChangeLog.pre-2-4
ChangeLog.pre-2-6
ChangeLog.pre-2-8
Makefile.am
acconfig.h
configure.in
garray.c
gbacktrace.c
gcache.c
gcompletion.c
gdataset.c
gdate.c
gerror.c
ghash.c
ghook.c
giochannel.c
giounix.c
glib-config.in
glib.h
glib/Makefile.am
glib/garray.c
glib/gbacktrace.c
glib/gcache.c
glib/gcompletion.c
glib/gdataset.c
glib/gdate.c
glib/gerror.c
glib/ghash.c
glib/ghook.c
glib/giochannel.c
glib/giounix.c
glib/glib.h
glib/glist.c
glib/gmain.c
glib/gmem.c
glib/gmessages.c
glib/gnode.c
glib/gprimes.c
glib/grel.c
glib/gscanner.c
glib/gslist.c
glib/gstrfuncs.c
glib/gstring.c
glib/gtimer.c
glib/gtree.c
glib/gutils.c
glist.c
gmain.c
gmem.c
gmessages.c
gmodule/ChangeLog
gmodule/gmodule-dl.c
gmodule/gmodule-dld.c
gmodule/gmodule-win32.c
gmodule/gmodule.c
gmutex.c [new file with mode: 0644]
gnode.c
gprimes.c
grel.c
gscanner.c
gslist.c
gstrfuncs.c
gstring.c
gthread/.cvsignore [new file with mode: 0644]
gthread/Makefile.am [new file with mode: 0644]
gthread/gthread-none.c [new file with mode: 0644]
gthread/gthread-nspr.c [new file with mode: 0644]
gthread/gthread-posix.c [new file with mode: 0644]
gthread/gthread-solaris.c [new file with mode: 0644]
gthread/gthread.c [new file with mode: 0644]
gthread/testgthread.c [new file with mode: 0644]
gtimer.c
gtree.c
gutils.c

index 7d1d075..dc3ecad 100644 (file)
--- 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
index 7d1d075..dc3ecad 100644 (file)
@@ -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
index 7d1d075..dc3ecad 100644 (file)
@@ -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
index 7d1d075..dc3ecad 100644 (file)
@@ -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
index 7d1d075..dc3ecad 100644 (file)
@@ -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
index 7d1d075..dc3ecad 100644 (file)
@@ -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
index 7d1d075..dc3ecad 100644 (file)
@@ -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
index 7d1d075..dc3ecad 100644 (file)
@@ -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
index d2a10f5..a06082f 100644 (file)
@@ -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
index 93ecd55..4396f7b 100644 (file)
@@ -84,6 +84,8 @@
 #undef WIN32
 #undef NATIVE_WIN32
 
+#undef G_THREAD_SOURCE
+
 /* #undef PACKAGE */
 /* #undef VERSION */
 
index 2a91d11..6b7fc2a 100644 (file)
@@ -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;;
index 0247972..7f0803e 100644 (file)
--- a/garray.c
+++ b/garray.c
  * 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
index 6aeb8b5..2615ce2 100644 (file)
  * 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
index b2fe779..800bb2b 100644 (file)
--- a/gcache.c
+++ b/gcache.c
  * 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);
 }
index 62ec244..cba2a86 100644 (file)
  * Boston, MA 02111-1307, USA.
  */
 
+/* 
+ * MT safe
+ */
+
 #include "glib.h"
 #include <string.h>
 
index 7dafc21..f22b21d 100644 (file)
  * 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 69c337d..7c60e23 100644 (file)
--- a/gdate.c
+++ b/gdate.c
  * 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         
index 6aeb8b5..2615ce2 100644 (file)
--- a/gerror.c
+++ b/gerror.c
  * 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 4ab82b3..7240363 100644 (file)
--- a/ghash.c
+++ b/ghash.c
  * 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 47a2874..b683b7c 100644 (file)
--- a/ghook.c
+++ b/ghook.c
  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  * Boston, MA 02111-1307, USA.
  */
+
+/* 
+ * MT safe
+ */
+
 #include       "glib.h"
 
 
index fa42626..0693a08 100644 (file)
  * Boston, MA 02111-1307, USA.
  */
 
+/* 
+ * MT safe
+ */
+
 #include "glib.h"
 #include <unistd.h>
 
index 5e605a4..82944be 100644 (file)
--- a/giounix.c
+++ b/giounix.c
  * Boston, MA 02111-1307, USA.
  */
 
+/* 
+ * MT safe
+ */
+
 #include "glib.h"
 #include <sys/types.h>
 #include <unistd.h>
index a3b264c..36192c9 100644 (file)
@@ -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 33fa042..d4d1aaa 100644 (file)
--- 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
 }
index d2a10f5..a06082f 100644 (file)
@@ -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
index 0247972..7f0803e 100644 (file)
  * 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
index 6aeb8b5..2615ce2 100644 (file)
  * 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
index b2fe779..800bb2b 100644 (file)
  * 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);
 }
index 62ec244..cba2a86 100644 (file)
  * Boston, MA 02111-1307, USA.
  */
 
+/* 
+ * MT safe
+ */
+
 #include "glib.h"
 #include <string.h>
 
index 7dafc21..f22b21d 100644 (file)
  * 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)
 {
index 69c337d..7c60e23 100644 (file)
  * 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         
index 6aeb8b5..2615ce2 100644 (file)
  * 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
index 4ab82b3..7240363 100644 (file)
  * 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);
 }
index 47a2874..b683b7c 100644 (file)
  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  * Boston, MA 02111-1307, USA.
  */
+
+/* 
+ * MT safe
+ */
+
 #include       "glib.h"
 
 
index fa42626..0693a08 100644 (file)
  * Boston, MA 02111-1307, USA.
  */
 
+/* 
+ * MT safe
+ */
+
 #include "glib.h"
 #include <unistd.h>
 
index 5e605a4..82944be 100644 (file)
  * Boston, MA 02111-1307, USA.
  */
 
+/* 
+ * MT safe
+ */
+
 #include "glib.h"
 #include <sys/types.h>
 #include <unistd.h>
index 33fa042..d4d1aaa 100644 (file)
@@ -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
 }
index 41a09dd..e74dee8 100644 (file)
  * 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*
index 1f13e90..5d3ae8d 100644 (file)
  * 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 
index c29ee66..a4907ff 100644 (file)
  * Boston, MA 02111-1307, USA.
  */
 
+/* 
+ * MT safe
+ */
+
 #ifdef HAVE_CONFIG_H
 #include <config.h>
 #endif
  */
 
 #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
+}
index e0c6eac..eb8aed7 100644 (file)
  * 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);
+}
index 9f6e544..089a499 100644 (file)
  * 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
index 3d45c1e..404ebd6 100644 (file)
  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  * Boston, MA 02111-1307, USA.
  */
+
+/* 
+ * MT safe
+ */
+
 #include "glib.h"
 
 static const guint g_primes[] =
index 5fdf880..544da6b 100644 (file)
  * 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>
index 02985a7..c6fd0dd 100644 (file)
  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  * Boston, MA 02111-1307, USA.
  */
+
+/* 
+ * MT safe
+ */
+
 #define                __gscanner_c__
 
 #ifdef HAVE_CONFIG_H
index 4efe2a5..1ed517f 100644 (file)
  * 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);
     }
 }
 
index ad28978..e154c56 100644 (file)
  * 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;
index fa84fe7..312a540 100644 (file)
  * 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*
index 6e58fa0..0b6e86a 100644 (file)
  * Boston, MA 02111-1307, USA.
  */
 
+/* 
+ * MT safe
+ */
+
 #ifdef HAVE_CONFIG_H
 #include <config.h>
 #endif
index 4d9e98a..006f15d 100644 (file)
  * 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)
index cc65949..9a91199 100644 (file)
  * 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 41a09dd..e74dee8 100644 (file)
--- a/glist.c
+++ b/glist.c
  * 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 1f13e90..5d3ae8d 100644 (file)
--- a/gmain.c
+++ b/gmain.c
  * 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 c29ee66..a4907ff 100644 (file)
--- a/gmem.c
+++ b/gmem.c
  * Boston, MA 02111-1307, USA.
  */
 
+/* 
+ * MT safe
+ */
+
 #ifdef HAVE_CONFIG_H
 #include <config.h>
 #endif
  */
 
 #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
+}
index e0c6eac..eb8aed7 100644 (file)
  * 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);
+}
index 4de4343..86dd222 100644 (file)
@@ -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
index 034e94b..4a56866 100644 (file)
  * 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? */
index b1d68d7..53b269b 100644 (file)
  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  * Boston, MA 02111-1307, USA.
  */
+
+/* 
+ * MT safe
+ */
+
 #include <dl.h>
 
 
index 0cc1bac..98643ad 100644 (file)
  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  * Boston, MA 02111-1307, USA.
  */
+
+/* 
+ * MT safe
+ */
+
 #include <stdio.h>
 #include <windows.h>
 
index 9efa3f5..71f6145 100644 (file)
  * 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 (file)
index 0000000..b1d8947
--- /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 9f6e544..089a499 100644 (file)
--- a/gnode.c
+++ b/gnode.c
  * 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
index 3d45c1e..404ebd6 100644 (file)
--- a/gprimes.c
+++ b/gprimes.c
  * 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 5fdf880..544da6b 100644 (file)
--- a/grel.c
+++ b/grel.c
  * 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>
index 02985a7..c6fd0dd 100644 (file)
  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  * Boston, MA 02111-1307, USA.
  */
+
+/* 
+ * MT safe
+ */
+
 #define                __gscanner_c__
 
 #ifdef HAVE_CONFIG_H
index 4efe2a5..1ed517f 100644 (file)
--- a/gslist.c
+++ b/gslist.c
  * 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);
     }
 }
 
index ad28978..e154c56 100644 (file)
  * 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;
index fa84fe7..312a540 100644 (file)
--- a/gstring.c
+++ b/gstring.c
  * 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 (file)
index 0000000..ba4d802
--- /dev/null
@@ -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 (file)
index 0000000..3b7bc97
--- /dev/null
@@ -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 (file)
index 0000000..1240fd5
--- /dev/null
@@ -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 (file)
index 0000000..77672e5
--- /dev/null
@@ -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 (file)
index 0000000..5b59672
--- /dev/null
@@ -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 (file)
index 0000000..52d4c55
--- /dev/null
@@ -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 (file)
index 0000000..8ada7f8
--- /dev/null
@@ -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 (file)
index 0000000..be81f04
--- /dev/null
@@ -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;
+}
index 6e58fa0..0b6e86a 100644 (file)
--- a/gtimer.c
+++ b/gtimer.c
  * Boston, MA 02111-1307, USA.
  */
 
+/* 
+ * MT safe
+ */
+
 #ifdef HAVE_CONFIG_H
 #include <config.h>
 #endif
diff --git a/gtree.c b/gtree.c
index 4d9e98a..006f15d 100644 (file)
--- a/gtree.c
+++ b/gtree.c
  * 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)
index cc65949..9a91199 100644 (file)
--- a/gutils.c
+++ b/gutils.c
  * 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