From 931ea952650b013b834041b91b0c37a748ffd449 Mon Sep 17 00:00:00 2001 From: Owen Taylor Date: Tue, 15 Dec 1998 05:28:02 +0000 Subject: [PATCH] This commit merges the glib-threads branch into the main 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. --- ChangeLog | 84 +++++++++++++++ ChangeLog.pre-2-0 | 84 +++++++++++++++ ChangeLog.pre-2-10 | 84 +++++++++++++++ ChangeLog.pre-2-12 | 84 +++++++++++++++ ChangeLog.pre-2-2 | 84 +++++++++++++++ ChangeLog.pre-2-4 | 84 +++++++++++++++ ChangeLog.pre-2-6 | 84 +++++++++++++++ ChangeLog.pre-2-8 | 84 +++++++++++++++ Makefile.am | 5 +- acconfig.h | 2 + configure.in | 206 +++++++++++++++++++++++++++++++++++ garray.c | 19 +++- gbacktrace.c | 5 + gcache.c | 11 +- gcompletion.c | 4 + gdataset.c | 76 ++++++++++--- gdate.c | 24 ++++- gerror.c | 5 + ghash.c | 13 +++ ghook.c | 5 + giochannel.c | 4 + giounix.c | 4 + glib-config.in | 15 ++- glib.h | 134 +++++++++++++++++++++++ glib/Makefile.am | 5 +- glib/garray.c | 19 +++- glib/gbacktrace.c | 5 + glib/gcache.c | 11 +- glib/gcompletion.c | 4 + glib/gdataset.c | 76 ++++++++++--- glib/gdate.c | 24 ++++- glib/gerror.c | 5 + glib/ghash.c | 13 +++ glib/ghook.c | 5 + glib/giochannel.c | 4 + glib/giounix.c | 4 + glib/glib.h | 134 +++++++++++++++++++++++ glib/glist.c | 44 ++++++-- glib/gmain.c | 158 +++++++++++++++++++++++---- glib/gmem.c | 89 +++++++++++++--- glib/gmessages.c | 115 +++++++++++++++----- glib/gnode.c | 36 ++++++- glib/gprimes.c | 5 + glib/grel.c | 5 + glib/gscanner.c | 5 + glib/gslist.c | 37 ++++++- glib/gstrfuncs.c | 26 ++++- glib/gstring.c | 11 +- glib/gtimer.c | 4 + glib/gtree.c | 18 +++- glib/gutils.c | 34 +++++- glist.c | 44 ++++++-- gmain.c | 158 +++++++++++++++++++++++---- gmem.c | 89 +++++++++++++--- gmessages.c | 115 +++++++++++++++----- gmodule/ChangeLog | 5 + gmodule/gmodule-dl.c | 5 + gmodule/gmodule-dld.c | 5 + gmodule/gmodule-win32.c | 5 + gmodule/gmodule.c | 68 ++++++++---- gmutex.c | 176 ++++++++++++++++++++++++++++++ gnode.c | 36 ++++++- gprimes.c | 5 + grel.c | 5 + gscanner.c | 5 + gslist.c | 37 ++++++- gstrfuncs.c | 26 ++++- gstring.c | 11 +- gthread/.cvsignore | 8 ++ gthread/Makefile.am | 21 ++++ gthread/gthread-none.c | 28 +++++ gthread/gthread-nspr.c | 218 ++++++++++++++++++++++++++++++++++++++ gthread/gthread-posix.c | 176 ++++++++++++++++++++++++++++++ gthread/gthread-solaris.c | 177 +++++++++++++++++++++++++++++++ gthread/gthread.c | 101 ++++++++++++++++++ gthread/testgthread.c | 200 ++++++++++++++++++++++++++++++++++ gtimer.c | 4 + gtree.c | 18 +++- gutils.c | 34 +++++- 79 files changed, 3635 insertions(+), 245 deletions(-) create mode 100644 gmutex.c create mode 100644 gthread/.cvsignore create mode 100644 gthread/Makefile.am create mode 100644 gthread/gthread-none.c create mode 100644 gthread/gthread-nspr.c create mode 100644 gthread/gthread-posix.c create mode 100644 gthread/gthread-solaris.c create mode 100644 gthread/gthread.c create mode 100644 gthread/testgthread.c diff --git a/ChangeLog b/ChangeLog index 7d1d0758f..dc3ecadc7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,87 @@ +1998-12-11 Sebastian Wilhelmi + + * 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 + + * 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 + + * 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 + + * Start at adding thread-safety. (mostly work + of Sebastian Wilhelmi ) + + - 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 * configure.in: always define G_HAVE_INLINE if __cplusplus is diff --git a/ChangeLog.pre-2-0 b/ChangeLog.pre-2-0 index 7d1d0758f..dc3ecadc7 100644 --- a/ChangeLog.pre-2-0 +++ b/ChangeLog.pre-2-0 @@ -1,3 +1,87 @@ +1998-12-11 Sebastian Wilhelmi + + * 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 + + * 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 + + * 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 + + * Start at adding thread-safety. (mostly work + of Sebastian Wilhelmi ) + + - 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 * configure.in: always define G_HAVE_INLINE if __cplusplus is diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10 index 7d1d0758f..dc3ecadc7 100644 --- a/ChangeLog.pre-2-10 +++ b/ChangeLog.pre-2-10 @@ -1,3 +1,87 @@ +1998-12-11 Sebastian Wilhelmi + + * 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 + + * 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 + + * 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 + + * Start at adding thread-safety. (mostly work + of Sebastian Wilhelmi ) + + - 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 * configure.in: always define G_HAVE_INLINE if __cplusplus is diff --git a/ChangeLog.pre-2-12 b/ChangeLog.pre-2-12 index 7d1d0758f..dc3ecadc7 100644 --- a/ChangeLog.pre-2-12 +++ b/ChangeLog.pre-2-12 @@ -1,3 +1,87 @@ +1998-12-11 Sebastian Wilhelmi + + * 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 + + * 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 + + * 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 + + * Start at adding thread-safety. (mostly work + of Sebastian Wilhelmi ) + + - 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 * configure.in: always define G_HAVE_INLINE if __cplusplus is diff --git a/ChangeLog.pre-2-2 b/ChangeLog.pre-2-2 index 7d1d0758f..dc3ecadc7 100644 --- a/ChangeLog.pre-2-2 +++ b/ChangeLog.pre-2-2 @@ -1,3 +1,87 @@ +1998-12-11 Sebastian Wilhelmi + + * 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 + + * 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 + + * 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 + + * Start at adding thread-safety. (mostly work + of Sebastian Wilhelmi ) + + - 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 * configure.in: always define G_HAVE_INLINE if __cplusplus is diff --git a/ChangeLog.pre-2-4 b/ChangeLog.pre-2-4 index 7d1d0758f..dc3ecadc7 100644 --- a/ChangeLog.pre-2-4 +++ b/ChangeLog.pre-2-4 @@ -1,3 +1,87 @@ +1998-12-11 Sebastian Wilhelmi + + * 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 + + * 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 + + * 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 + + * Start at adding thread-safety. (mostly work + of Sebastian Wilhelmi ) + + - 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 * configure.in: always define G_HAVE_INLINE if __cplusplus is diff --git a/ChangeLog.pre-2-6 b/ChangeLog.pre-2-6 index 7d1d0758f..dc3ecadc7 100644 --- a/ChangeLog.pre-2-6 +++ b/ChangeLog.pre-2-6 @@ -1,3 +1,87 @@ +1998-12-11 Sebastian Wilhelmi + + * 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 + + * 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 + + * 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 + + * Start at adding thread-safety. (mostly work + of Sebastian Wilhelmi ) + + - 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 * configure.in: always define G_HAVE_INLINE if __cplusplus is diff --git a/ChangeLog.pre-2-8 b/ChangeLog.pre-2-8 index 7d1d0758f..dc3ecadc7 100644 --- a/ChangeLog.pre-2-8 +++ b/ChangeLog.pre-2-8 @@ -1,3 +1,87 @@ +1998-12-11 Sebastian Wilhelmi + + * 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 + + * 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 + + * 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 + + * Start at adding thread-safety. (mostly work + of Sebastian Wilhelmi ) + + - 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 * configure.in: always define G_HAVE_INLINE if __cplusplus is diff --git a/Makefile.am b/Makefile.am index d2a10f588..a06082fa3 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,7 +1,7 @@ ## Process this file with automake to produce Makefile.in # build . first, then SUBDIRS -SUBDIRS = gmodule docs +SUBDIRS = gmodule gthread docs all-recursive-am: all-am # alpha `automake' supports this better #SUBDIRS = . gmodule docs @@ -50,7 +50,8 @@ libglib_la_SOURCES = \ gstring.c \ gstrfuncs.c \ gscanner.c \ - gutils.c + gutils.c \ + gmutex.c include_HEADERS = \ glib.h diff --git a/acconfig.h b/acconfig.h index 93ecd556d..4396f7be4 100644 --- a/acconfig.h +++ b/acconfig.h @@ -84,6 +84,8 @@ #undef WIN32 #undef NATIVE_WIN32 +#undef G_THREAD_SOURCE + /* #undef PACKAGE */ /* #undef VERSION */ diff --git a/configure.in b/configure.in index 2a91d1117..6b7fc2a19 100644 --- a/configure.in +++ b/configure.in @@ -508,6 +508,155 @@ AC_SUBST(G_MODULE_HAVE_DLERROR) AC_SUBST(G_MODULE_NEED_USCORE) AC_SUBST(GLIB_DEBUG_FLAGS) + +dnl *********************** +dnl *** g_thread checks *** +dnl *********************** + +AC_ARG_WITH(threads, [ --with-threads=[none/posix/solaris/nspr] specify a thread implementation to use.],,) + +dnl error and warning message +dnl ************************* + +THREAD_NO_IMPLEMENTATION="You do not have any known thread system on your + computer. glib will not be thread safe on your computer." + +THREAD_UNKNOWN_COMPILER="Your compiler is not known, so I cannot + determine the necessary compiler options to compile programs + which are using threads. Please provide such information." + +FLAG_DOES_NOT_WORK="I can't find the MACRO, that enables thread safety on your + platform (normaly it's "_REENTRANT"). I'll not use any flag on + compilation now, but then your programs might not work. + Please provide information on how it is done on your system." + +LIBS_NOT_FOUND_1="I can't find the libraries for the thread implementation + " + +LIBS_NOT_FOUND_2=". Please choose another thread implementation or + provide informationon your thread implementation." + +dnl determination of thread implementation +dnl *************************************** + +if test x"$with_threads" = x; then + case $host in + *-*-solaris*) + AC_CHECK_LIB(thread,cond_init,with_threads=solaris) + ;; + esac + if test x"$with_threads" = x; then + AC_CHECK_LIB(pthread,pthread_cond_init,with_threads=posix) + AC_CHECK_LIB(pthreads,pthread_attr_init,with_threads=posix) + AC_CHECK_LIB(nspr21,PRP_NewNakedCondVar,with_threads=nspr) + fi +fi + +AC_MSG_CHECKING(for thread implementation) + +if test x"$with_threads" = x; then + with_threads=none + AC_MSG_WARN($THREAD_NO_IMPLEMENTATION) +fi + +AC_MSG_RESULT($with_threads) + +dnl determination of G_THREAD_LIBS +dnl ****************************** + +G_THREAD_LIBS= + +case $with_threads in + posix) + G_THREAD_LIBS=error + AC_CHECK_LIB(pthreads,pthread_cond_init, + G_THREAD_LIBS="-lpthreads") + AC_CHECK_LIB(pthread,pthread_cond_init, + G_THREAD_LIBS="-lpthread") + ;; + solaris) + G_THREAD_LIBS=error + AC_CHECK_LIB(thread,cond_init,G_THREAD_LIBS="-lthread") + # solaris has a broken initializer for mutexes, if we find it, + # we will replace it. + AC_MSG_CHECKING(for broken solaris mutex initialization) + AC_EGREP_CPP([ *begin *{ *0 *, *0 *, *0 *, *0 *, *0 *, *0 *, *0 *, *0 *, *0 *, *0 *, *0 *, *0 *, *0 *, *0 *} *end *], + [#include + 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 ' >> $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 ' >> $outfile echo '#include ' >> $outfile @@ -628,6 +780,34 @@ $glib_inline #define G_BYTE_ORDER $g_byte_order outfile_EOF +cat >>$outfile <>$outfile <>$outfile < #include "glib.h" @@ -40,9 +45,8 @@ static gint g_nearest_pow (gint num); static void g_array_maybe_expand (GRealArray *array, gint len); - static GMemChunk *array_mem_chunk = NULL; - +static G_LOCK_DEFINE(array_mem_chunk); GArray* g_array_new (gboolean zero_terminated, @@ -51,12 +55,14 @@ g_array_new (gboolean zero_terminated, { GRealArray *array; + g_lock (array_mem_chunk); if (!array_mem_chunk) array_mem_chunk = g_mem_chunk_new ("array mem chunk", sizeof (GRealArray), 1024, G_ALLOC_AND_FREE); array = g_chunk_new (GRealArray, array_mem_chunk); + g_unlock (array_mem_chunk); array->data = NULL; array->len = 0; @@ -75,7 +81,9 @@ g_array_free (GArray *array, if (free_segment) g_free (array->data); + g_lock (array_mem_chunk); g_mem_chunk_free (array_mem_chunk, array); + g_unlock (array_mem_chunk); } GArray* @@ -241,9 +249,8 @@ struct _GRealPtrArray static void g_ptr_array_maybe_expand (GRealPtrArray *array, gint len); - static GMemChunk *ptr_array_mem_chunk = NULL; - +static G_LOCK_DEFINE(ptr_array_mem_chunk); GPtrArray* @@ -251,12 +258,14 @@ g_ptr_array_new (void) { GRealPtrArray *array; + g_lock (ptr_array_mem_chunk); if (!ptr_array_mem_chunk) ptr_array_mem_chunk = g_mem_chunk_new ("array mem chunk", sizeof (GRealPtrArray), 1024, G_ALLOC_AND_FREE); array = g_chunk_new (GRealPtrArray, ptr_array_mem_chunk); + g_unlock (ptr_array_mem_chunk); array->pdata = NULL; array->len = 0; @@ -274,7 +283,9 @@ g_ptr_array_free (GPtrArray *array, if (free_segment) g_free (array->pdata); + g_lock (ptr_array_mem_chunk); g_mem_chunk_free (ptr_array_mem_chunk, array); + g_unlock (ptr_array_mem_chunk); } static void diff --git a/gbacktrace.c b/gbacktrace.c index 6aeb8b517..2615ce2b4 100644 --- a/gbacktrace.c +++ b/gbacktrace.c @@ -17,6 +17,11 @@ * Boston, MA 02111-1307, USA. */ +/* + * MT safe ; except for g_on_error_stack_trace, but who wants thread safety + * then + */ + #ifdef HAVE_CONFIG_H #include #endif diff --git a/gcache.c b/gcache.c index b2fe77910..800bb2b13 100644 --- a/gcache.c +++ b/gcache.c @@ -16,6 +16,11 @@ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ + +/* + * MT safe + */ + #include "glib.h" @@ -56,7 +61,7 @@ static void g_cache_node_destroy (GCacheNode *node); static GMemChunk *node_mem_chunk = NULL; - +static G_LOCK_DEFINE(node_mem_chunk); GCache* g_cache_new (GCacheNewFunc value_new_func, @@ -193,11 +198,13 @@ g_cache_node_new (gpointer value) { GCacheNode *node; + g_lock (node_mem_chunk); if (!node_mem_chunk) node_mem_chunk = g_mem_chunk_new ("cache node mem chunk", sizeof (GCacheNode), 1024, G_ALLOC_AND_FREE); node = g_chunk_new (GCacheNode, node_mem_chunk); + g_unlock (node_mem_chunk); node->value = value; node->ref_count = 1; @@ -208,5 +215,7 @@ g_cache_node_new (gpointer value) static void g_cache_node_destroy (GCacheNode *node) { + g_lock (node_mem_chunk); g_mem_chunk_free (node_mem_chunk, node); + g_unlock (node_mem_chunk); } diff --git a/gcompletion.c b/gcompletion.c index 62ec244bc..cba2a86cb 100644 --- a/gcompletion.c +++ b/gcompletion.c @@ -17,6 +17,10 @@ * Boston, MA 02111-1307, USA. */ +/* + * MT safe + */ + #include "glib.h" #include diff --git a/gdataset.c b/gdataset.c index 7dafc2191..f22b21d59 100644 --- a/gdataset.c +++ b/gdataset.c @@ -18,6 +18,12 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. */ + +/* + * MT safe ; FIXME: might still freeze, watch out, not thoroughly + * looked at yet. + */ + #include #include "glib.h" @@ -61,18 +67,24 @@ static inline GQuark g_quark_new (gchar *string); /* --- variables --- */ +static G_LOCK_DEFINE(g_dataset_global); static GHashTable *g_dataset_location_ht = NULL; -static GDataset *g_dataset_cached = NULL; +static GDataset *g_dataset_cached = NULL; /* should this be + threadspecific? */ static GMemChunk *g_dataset_mem_chunk = NULL; static GMemChunk *g_data_mem_chunk = NULL; static GData *g_data_cache = NULL; static guint g_data_cache_length = 0; + +static G_LOCK_DEFINE(g_quark_global); static GHashTable *g_quark_ht = NULL; static gchar **g_quarks = NULL; static GQuark g_quark_seq_id = 0; /* --- functions --- */ + +/* HOLDS: g_dataset_global_lock */ static inline void g_datalist_clear_i (GData **datalist) { @@ -109,13 +121,16 @@ g_datalist_clear (GData **datalist) { g_return_if_fail (datalist != NULL); + g_lock (g_dataset_global); if (!g_dataset_location_ht) g_data_initialize (); while (*datalist) g_datalist_clear_i (datalist); + g_unlock (g_dataset_global); } +/* HOLDS: g_dataset_global_lock */ static inline GDataset* g_dataset_lookup (gconstpointer dataset_location) { @@ -131,6 +146,7 @@ g_dataset_lookup (gconstpointer dataset_location) return dataset; } +/* HOLDS: g_dataset_global_lock */ static void g_dataset_destroy_internal (GDataset *dataset) { @@ -158,6 +174,7 @@ g_dataset_destroy (gconstpointer dataset_location) { g_return_if_fail (dataset_location != NULL); + g_lock (g_dataset_global); if (g_dataset_location_ht) { register GDataset *dataset; @@ -166,8 +183,10 @@ g_dataset_destroy (gconstpointer dataset_location) if (dataset) g_dataset_destroy_internal (dataset); } + g_unlock (g_dataset_global); } +/* HOLDS: g_dataset_global_lock */ static inline void g_data_set_internal (GData **datalist, GQuark key_id, @@ -293,9 +312,10 @@ g_dataset_id_set_data_full (gconstpointer dataset_location, return; } + g_lock (g_dataset_global); if (!g_dataset_location_ht) g_data_initialize (); - + dataset = g_dataset_lookup (dataset_location); if (!dataset) { @@ -308,6 +328,7 @@ g_dataset_id_set_data_full (gconstpointer dataset_location, } g_data_set_internal (&dataset->datalist, key_id, data, destroy_func, dataset); + g_unlock (g_dataset_global); } void @@ -327,10 +348,12 @@ g_datalist_id_set_data_full (GData **datalist, return; } + g_lock (g_dataset_global); if (!g_dataset_location_ht) g_data_initialize (); g_data_set_internal (datalist, key_id, data, destroy_func, NULL); + g_unlock (g_dataset_global); } void @@ -339,6 +362,7 @@ g_dataset_id_remove_no_notify (gconstpointer dataset_location, { g_return_if_fail (dataset_location != NULL); + g_lock (g_dataset_global); if (key_id && g_dataset_location_ht) { GDataset *dataset; @@ -346,7 +370,8 @@ g_dataset_id_remove_no_notify (gconstpointer dataset_location, dataset = g_dataset_lookup (dataset_location); if (dataset) g_data_set_internal (&dataset->datalist, key_id, NULL, (GDestroyNotify) 42, dataset); - } + } + g_unlock (g_dataset_global); } void @@ -355,8 +380,10 @@ g_datalist_id_remove_no_notify (GData **datalist, { g_return_if_fail (datalist != NULL); + g_lock (g_dataset_global); if (key_id && g_dataset_location_ht) g_data_set_internal (datalist, key_id, NULL, (GDestroyNotify) 42, NULL); + g_unlock (g_dataset_global); } gpointer @@ -365,6 +392,7 @@ g_dataset_id_get_data (gconstpointer dataset_location, { g_return_val_if_fail (dataset_location != NULL, NULL); + g_lock (g_dataset_global); if (key_id && g_dataset_location_ht) { register GDataset *dataset; @@ -376,10 +404,14 @@ g_dataset_id_get_data (gconstpointer dataset_location, for (list = dataset->datalist; list; list = list->next) if (list->id == key_id) - return list->data; + { + g_unlock (g_dataset_global); + return list->data; + } } } - + g_unlock (g_dataset_global); + return NULL; } @@ -411,17 +443,23 @@ g_dataset_foreach (gconstpointer dataset_location, g_return_if_fail (dataset_location != NULL); g_return_if_fail (func != NULL); + g_lock (g_dataset_global); if (g_dataset_location_ht) { dataset = g_dataset_lookup (dataset_location); + g_unlock (g_dataset_global); if (dataset) { register GData *list; for (list = dataset->datalist; list; list = list->next) - func (list->id, list->data, user_data); + func (list->id, list->data, user_data); } } + else + { + g_unlock (g_dataset_global); + } } void @@ -446,6 +484,7 @@ g_datalist_init (GData **datalist) *datalist = NULL; } +/* HOLDS: g_dataset_global_lock */ static void g_data_initialize (void) { @@ -468,12 +507,15 @@ g_data_initialize (void) GQuark g_quark_try_string (const gchar *string) { + GQuark quark = 0; g_return_val_if_fail (string != NULL, 0); + g_lock (g_quark_global); if (g_quark_ht) - return (gulong) g_hash_table_lookup (g_quark_ht, string); - else - return 0; + quark = GPOINTER_TO_UINT (g_hash_table_lookup (g_quark_ht, string)); + g_unlock (g_quark_global); + + return quark; } GQuark @@ -483,6 +525,7 @@ g_quark_from_string (const gchar *string) g_return_val_if_fail (string != NULL, 0); + g_lock (g_quark_global); if (g_quark_ht) quark = (gulong) g_hash_table_lookup (g_quark_ht, string); else @@ -493,6 +536,7 @@ g_quark_from_string (const gchar *string) if (!quark) quark = g_quark_new (g_strdup (string)); + g_unlock (g_quark_global); return quark; } @@ -504,6 +548,7 @@ g_quark_from_static_string (const gchar *string) g_return_val_if_fail (string != NULL, 0); + g_lock (g_quark_global); if (g_quark_ht) quark = (gulong) g_hash_table_lookup (g_quark_ht, string); else @@ -514,19 +559,24 @@ g_quark_from_static_string (const gchar *string) if (!quark) quark = g_quark_new ((gchar*) string); - + g_unlock (g_quark_global); + return quark; } gchar* g_quark_to_string (GQuark quark) { + gchar* result = NULL; + g_lock (g_quark_global); if (quark > 0 && quark <= g_quark_seq_id) - return g_quarks[quark - 1]; - else - return NULL; + result = g_quarks[quark - 1]; + g_unlock (g_quark_global); + + return result; } +/* HOLDS: g_quark_global_lock */ static inline GQuark g_quark_new (gchar *string) { diff --git a/gdate.c b/gdate.c index 69c337def..7c60e23d9 100644 --- a/gdate.c +++ b/gdate.c @@ -16,6 +16,11 @@ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ + +/* + * MT safe + */ + #include "glib.h" #include @@ -383,6 +388,8 @@ g_date_clear (GDate *d, guint ndates) memset (d, 0x0, ndates*sizeof (GDate)); } +static G_LOCK_DEFINE(g_date_global); + /* These are for the parser, output to the user should use * * g_date_strftime () - this creates more never-freed memory to annoy * all those memory debugger users. :-) @@ -429,6 +436,7 @@ typedef struct _GDateParseTokens GDateParseTokens; #define NUM_LEN 10 +/* HOLDS: g_date_global_lock */ static void g_date_fill_parse_tokens (const gchar *str, GDateParseTokens *pt) { @@ -488,7 +496,7 @@ g_date_fill_parse_tokens (const gchar *str, GDateParseTokens *pt) if (found != NULL) { pt->month = i; - return; + return; } } @@ -502,12 +510,13 @@ g_date_fill_parse_tokens (const gchar *str, GDateParseTokens *pt) return; } } - + ++i; - } + } } } +/* HOLDS: g_date_global_lock */ static void g_date_prepare_to_parse (const gchar *str, GDateParseTokens *pt) { @@ -641,6 +650,8 @@ g_date_set_parse (GDate *d, /* set invalid */ g_date_clear (d, 1); + g_lock (g_date_global); + g_date_prepare_to_parse (str, &pt); #ifdef G_ENABLE_DEBUG @@ -649,7 +660,11 @@ g_date_set_parse (GDate *d, #endif - if (pt.num_ints == 4) return; /* presumably a typo; bail out. */ + if (pt.num_ints == 4) + { + g_unlock (g_date_global); + return; /* presumably a typo; bail out. */ + } if (pt.num_ints > 1) { @@ -765,6 +780,7 @@ g_date_set_parse (GDate *d, else g_message ("Rejected DMY %u %u %u", day, m, y); #endif + g_unlock (g_date_global); } void diff --git a/gerror.c b/gerror.c index 6aeb8b517..2615ce2b4 100644 --- a/gerror.c +++ b/gerror.c @@ -17,6 +17,11 @@ * Boston, MA 02111-1307, USA. */ +/* + * MT safe ; except for g_on_error_stack_trace, but who wants thread safety + * then + */ + #ifdef HAVE_CONFIG_H #include #endif diff --git a/ghash.c b/ghash.c index 4ab82b3fa..724036388 100644 --- a/ghash.c +++ b/ghash.c @@ -16,6 +16,11 @@ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ + +/* + * MT safe + */ + #include "glib.h" @@ -52,6 +57,8 @@ static void g_hash_node_destroy (GHashNode *hash_node); static void g_hash_nodes_destroy (GHashNode *hash_node); +static G_LOCK_DEFINE(g_hash_global); + static GMemChunk *node_mem_chunk = NULL; static GHashNode *node_free_list = NULL; @@ -338,6 +345,7 @@ g_hash_node_new (gpointer key, { GHashNode *hash_node; + g_lock (g_hash_global); if (node_free_list) { hash_node = node_free_list; @@ -352,6 +360,7 @@ g_hash_node_new (gpointer key, hash_node = g_chunk_new (GHashNode, node_mem_chunk); } + g_unlock (g_hash_global); hash_node->key = key; hash_node->value = value; @@ -363,8 +372,10 @@ g_hash_node_new (gpointer key, static void g_hash_node_destroy (GHashNode *hash_node) { + g_lock (g_hash_global); hash_node->next = node_free_list; node_free_list = hash_node; + g_unlock (g_hash_global); } static void @@ -380,6 +391,8 @@ g_hash_nodes_destroy (GHashNode *hash_node) while (node->next) node = node->next; + g_lock (g_hash_global); node->next = node_free_list; node_free_list = hash_node; + g_unlock (g_hash_global); } diff --git a/ghook.c b/ghook.c index 47a2874a4..b683b7c31 100644 --- a/ghook.c +++ b/ghook.c @@ -19,6 +19,11 @@ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ + +/* + * MT safe + */ + #include "glib.h" diff --git a/giochannel.c b/giochannel.c index fa4262602..0693a084b 100644 --- a/giochannel.c +++ b/giochannel.c @@ -20,6 +20,10 @@ * Boston, MA 02111-1307, USA. */ +/* + * MT safe + */ + #include "glib.h" #include diff --git a/giounix.c b/giounix.c index 5e605a478..82944be89 100644 --- a/giounix.c +++ b/giounix.c @@ -20,6 +20,10 @@ * Boston, MA 02111-1307, USA. */ +/* + * MT safe + */ + #include "glib.h" #include #include diff --git a/glib-config.in b/glib-config.in index a3b264c13..36192c9c9 100644 --- a/glib-config.in +++ b/glib-config.in @@ -17,6 +17,7 @@ Options: Libraries: glib gmodule + gthread EOF exit $1 } @@ -69,6 +70,9 @@ while test $# -gt 0; do gmodule) lib_gmodule=yes ;; + gthread) + lib_gthread=yes + ;; *) usage 1 1>&2 ;; @@ -83,7 +87,11 @@ if test "$echo_exec_prefix" = "yes"; then echo $exec_prefix fi if test "$echo_cflags" = "yes"; then - echo -I@libdir@/glib/include $includes + cflags="" + if test "$lib_gthread" = "yes"; then + cflags="$cflags @G_THREAD_CFLAGS@" + fi + echo -I@libdir@/glib/include $includes $cflags fi if test "$echo_libs" = "yes"; then libs="" @@ -93,5 +101,8 @@ if test "$echo_libs" = "yes"; then if test "$lib_gmodule" = "yes"; then libs="@G_MODULE_LDFLAGS@ -lgmodule $libs @G_MODULE_LIBS@" fi - echo "-L@libdir@ $libs" + if test "$lib_gthread" = "yes"; then + libs="-lgthread $libs @G_THREAD_LIBS@" + fi + echo -L@libdir@ $libs fi diff --git a/glib.h b/glib.h index 33fa042e9..d4d1aaa77 100644 --- a/glib.h +++ b/glib.h @@ -2597,6 +2597,140 @@ gint gwin_closedir (DIR *dir); #endif /* NATIVE_WIN32 */ +/* functions for thread support for glib. */ + +typedef struct _GMutex GMutex; +typedef struct _GCond GCond; +typedef struct _GPrivate GPrivate; +typedef struct _GStaticPrivate GStaticPrivate; + +typedef struct _GThreadFunctions GThreadFunctions; +struct _GThreadFunctions +{ + GMutex* (*mutex_new) (void); + void (*mutex_lock) (GMutex* mutex); + gboolean (*mutex_trylock) (GMutex* mutex); + void (*mutex_unlock) (GMutex* mutex); + void (*mutex_free) (GMutex* mutex); + GCond* (*cond_new) (void); + void (*cond_signal) (GCond* cond); + void (*cond_broadcast) (GCond* cond); + void (*cond_wait) (GCond* cond, GMutex* mutex); + gboolean (*cond_timed_wait) (GCond* cond, GMutex* mutex, + GTimeVal *end_time); + void (*cond_free) (GCond* cond); + GPrivate* (*private_new) (GDestroyNotify destructor); + gpointer (*private_get) (GPrivate* private); + void (*private_set) (GPrivate* private, gpointer value); +}; + +GUTILS_C_VAR GThreadFunctions g_thread_functions_for_glib_use; +GUTILS_C_VAR gboolean g_thread_use_default_impl; +GUTILS_C_VAR gboolean g_thread_supported; + +/* initializes the mutex/cond/private implementation for glib, might + * only be called once, and must not be called directly or indirectly + * from another glib-function, e.g. as a callback. */ +void g_thread_init(GThreadFunctions* init); + +/* Internal functions for fallback static mutex implementation + * Please don't use it directly + */ +GMutex* g_static_mutex_get_mutex_impl(GMutex** mutex); + +#define G_USE_THREAD_FUNC_UNCOND(name,arg) \ + (*g_thread_functions_for_glib_use.name)arg +#define G_USE_THREAD_FUNC(name,fail,arg) \ + (g_thread_supported ? G_USE_THREAD_FUNC_UNCOND(name,arg) : (fail)) + +/* keep in mind, all those mutexes and static mutexes are not + * recursive in general, don't rely on that */ +#define g_mutex_new() G_USE_THREAD_FUNC_UNCOND(mutex_new,()) +#define g_mutex_lock(mutex) G_USE_THREAD_FUNC(mutex_lock,(void)0,(mutex)) +#define g_mutex_trylock(mutex) G_USE_THREAD_FUNC(mutex_trylock,TRUE,(mutex)) +#define g_mutex_unlock(mutex) G_USE_THREAD_FUNC(mutex_unlock,(void)0,(mutex)) +#define g_mutex_free(mutex) G_USE_THREAD_FUNC(mutex_free,(void)0,(mutex)) +#define g_cond_new() G_USE_THREAD_FUNC_UNCOND(cond_new,()) +#define g_cond_signal(cond) G_USE_THREAD_FUNC(cond_signal,(void)0,(cond)) +#define g_cond_broadcast(cond) G_USE_THREAD_FUNC(cond_broadcast,(void)0,(cond)) +#define g_cond_wait(cond,mutex) G_USE_THREAD_FUNC(cond_wait,(void)0,(cond,mutex)) +#define g_cond_timed_wait(cond,mutex,abs_time) \ + G_USE_THREAD_FUNC(cond_timed_wait,TRUE,(cond,mutex,abs_time)) +#define g_cond_free(cond) G_USE_THREAD_FUNC(cond_free,(void)0,(cond)) + +#define g_private_new(destructor) \ + G_USE_THREAD_FUNC_UNCOND(private_new,(destructor)) +#define g_private_get(private) \ + G_USE_THREAD_FUNC(private_get,((gpointer)private),(private)) +#define g_private_set(private,value) \ + G_USE_THREAD_FUNC(private_set,(void)(private=(GPrivate *)(value)), \ + (private,value)) + +/* GStaticMutex'es can be statically initialized with the value + * G_STATIC_MUTEX_INIT, and then they can directly be used, that is + * much easier, than having to explicitly allocate the mutex before + * use */ +#define g_static_mutex_lock(mutex) \ + g_mutex_lock( g_static_mutex_get_mutex(mutex) ) +#define g_static_mutex_trylock(mutex) \ + g_mutex_trylock( g_static_mutex_get_mutex(mutex) ) +#define g_static_mutex_unlock(mutex) \ + g_mutex_unlock( g_static_mutex_get_mutex(mutex) ) + +struct _GStaticPrivate +{ + guint index; +}; + +#define G_STATIC_PRIVATE_INIT { 0 } + +gpointer g_static_private_get (GStaticPrivate* private); +void g_static_private_set (GStaticPrivate *private, + gpointer data, + GDestroyNotify notify); + +/* these are some convenience macros, for using StaticMutex'es, you + * define them by G_LOCK_DEFINE(name), where name could for example be the + * name of the protected varibale, and you (un)lock them with + * g_(un)lock(name) */ +#define g_lock_name(name) (name ## _lock) +#define G_LOCK_DEFINE(name) GStaticMutex g_lock_name(name)=G_STATIC_MUTEX_INIT + +#ifdef G_DEBUG_LOCKS +#define g_lock(name) G_STMT_START{ \ + g_log (G_LOG_DOMAIN, \ + G_LOG_LEVEL_MESSAGE, \ + "file %s: line %d (%s): locking: %s ", \ + __FILE__, \ + __LINE__, \ + __PRETTY_FUNCTION__, \ + #name); \ + g_static_mutex_lock(g_lock_name(name)); \ + }G_STMT_END +#define g_unlock(name) G_STMT_START{ \ + g_log (G_LOG_DOMAIN, \ + G_LOG_LEVEL_MESSAGE, \ + "file %s: line %d (%s): unlocking: %s ", \ + __FILE__, \ + __LINE__, \ + __PRETTY_FUNCTION__, \ + #name); \ + g_static_mutex_unlock(g_lock_name(name)); \ + }G_STMT_END +#define g_trylock(name) G_STMT_START{ \ + g_log (G_LOG_DOMAIN, \ + G_LOG_LEVEL_MESSAGE, \ + "file %s: line %d (%s): try locking: %s ", \ + __FILE__, \ + __LINE__, \ + __PRETTY_FUNCTION__, \ + #name); \ + }G_STMT_END, g_static_mutex_trylock(g_lock_name(name)) +#else /* !G_DEBUG_LOCKS */ +#define g_lock(name) g_static_mutex_lock(g_lock_name(name)) +#define g_unlock(name) g_static_mutex_unlock(g_lock_name(name)) +#define g_trylock(name) g_static_mutex_trylock(g_lock_name(name)) +#endif #ifdef __cplusplus } diff --git a/glib/Makefile.am b/glib/Makefile.am index d2a10f588..a06082fa3 100644 --- a/glib/Makefile.am +++ b/glib/Makefile.am @@ -1,7 +1,7 @@ ## Process this file with automake to produce Makefile.in # build . first, then SUBDIRS -SUBDIRS = gmodule docs +SUBDIRS = gmodule gthread docs all-recursive-am: all-am # alpha `automake' supports this better #SUBDIRS = . gmodule docs @@ -50,7 +50,8 @@ libglib_la_SOURCES = \ gstring.c \ gstrfuncs.c \ gscanner.c \ - gutils.c + gutils.c \ + gmutex.c include_HEADERS = \ glib.h diff --git a/glib/garray.c b/glib/garray.c index 0247972ec..7f0803e3e 100644 --- a/glib/garray.c +++ b/glib/garray.c @@ -16,6 +16,11 @@ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ + +/* + * MT safe + */ + #include #include "glib.h" @@ -40,9 +45,8 @@ static gint g_nearest_pow (gint num); static void g_array_maybe_expand (GRealArray *array, gint len); - static GMemChunk *array_mem_chunk = NULL; - +static G_LOCK_DEFINE(array_mem_chunk); GArray* g_array_new (gboolean zero_terminated, @@ -51,12 +55,14 @@ g_array_new (gboolean zero_terminated, { GRealArray *array; + g_lock (array_mem_chunk); if (!array_mem_chunk) array_mem_chunk = g_mem_chunk_new ("array mem chunk", sizeof (GRealArray), 1024, G_ALLOC_AND_FREE); array = g_chunk_new (GRealArray, array_mem_chunk); + g_unlock (array_mem_chunk); array->data = NULL; array->len = 0; @@ -75,7 +81,9 @@ g_array_free (GArray *array, if (free_segment) g_free (array->data); + g_lock (array_mem_chunk); g_mem_chunk_free (array_mem_chunk, array); + g_unlock (array_mem_chunk); } GArray* @@ -241,9 +249,8 @@ struct _GRealPtrArray static void g_ptr_array_maybe_expand (GRealPtrArray *array, gint len); - static GMemChunk *ptr_array_mem_chunk = NULL; - +static G_LOCK_DEFINE(ptr_array_mem_chunk); GPtrArray* @@ -251,12 +258,14 @@ g_ptr_array_new (void) { GRealPtrArray *array; + g_lock (ptr_array_mem_chunk); if (!ptr_array_mem_chunk) ptr_array_mem_chunk = g_mem_chunk_new ("array mem chunk", sizeof (GRealPtrArray), 1024, G_ALLOC_AND_FREE); array = g_chunk_new (GRealPtrArray, ptr_array_mem_chunk); + g_unlock (ptr_array_mem_chunk); array->pdata = NULL; array->len = 0; @@ -274,7 +283,9 @@ g_ptr_array_free (GPtrArray *array, if (free_segment) g_free (array->pdata); + g_lock (ptr_array_mem_chunk); g_mem_chunk_free (ptr_array_mem_chunk, array); + g_unlock (ptr_array_mem_chunk); } static void diff --git a/glib/gbacktrace.c b/glib/gbacktrace.c index 6aeb8b517..2615ce2b4 100644 --- a/glib/gbacktrace.c +++ b/glib/gbacktrace.c @@ -17,6 +17,11 @@ * Boston, MA 02111-1307, USA. */ +/* + * MT safe ; except for g_on_error_stack_trace, but who wants thread safety + * then + */ + #ifdef HAVE_CONFIG_H #include #endif diff --git a/glib/gcache.c b/glib/gcache.c index b2fe77910..800bb2b13 100644 --- a/glib/gcache.c +++ b/glib/gcache.c @@ -16,6 +16,11 @@ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ + +/* + * MT safe + */ + #include "glib.h" @@ -56,7 +61,7 @@ static void g_cache_node_destroy (GCacheNode *node); static GMemChunk *node_mem_chunk = NULL; - +static G_LOCK_DEFINE(node_mem_chunk); GCache* g_cache_new (GCacheNewFunc value_new_func, @@ -193,11 +198,13 @@ g_cache_node_new (gpointer value) { GCacheNode *node; + g_lock (node_mem_chunk); if (!node_mem_chunk) node_mem_chunk = g_mem_chunk_new ("cache node mem chunk", sizeof (GCacheNode), 1024, G_ALLOC_AND_FREE); node = g_chunk_new (GCacheNode, node_mem_chunk); + g_unlock (node_mem_chunk); node->value = value; node->ref_count = 1; @@ -208,5 +215,7 @@ g_cache_node_new (gpointer value) static void g_cache_node_destroy (GCacheNode *node) { + g_lock (node_mem_chunk); g_mem_chunk_free (node_mem_chunk, node); + g_unlock (node_mem_chunk); } diff --git a/glib/gcompletion.c b/glib/gcompletion.c index 62ec244bc..cba2a86cb 100644 --- a/glib/gcompletion.c +++ b/glib/gcompletion.c @@ -17,6 +17,10 @@ * Boston, MA 02111-1307, USA. */ +/* + * MT safe + */ + #include "glib.h" #include diff --git a/glib/gdataset.c b/glib/gdataset.c index 7dafc2191..f22b21d59 100644 --- a/glib/gdataset.c +++ b/glib/gdataset.c @@ -18,6 +18,12 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. */ + +/* + * MT safe ; FIXME: might still freeze, watch out, not thoroughly + * looked at yet. + */ + #include #include "glib.h" @@ -61,18 +67,24 @@ static inline GQuark g_quark_new (gchar *string); /* --- variables --- */ +static G_LOCK_DEFINE(g_dataset_global); static GHashTable *g_dataset_location_ht = NULL; -static GDataset *g_dataset_cached = NULL; +static GDataset *g_dataset_cached = NULL; /* should this be + threadspecific? */ static GMemChunk *g_dataset_mem_chunk = NULL; static GMemChunk *g_data_mem_chunk = NULL; static GData *g_data_cache = NULL; static guint g_data_cache_length = 0; + +static G_LOCK_DEFINE(g_quark_global); static GHashTable *g_quark_ht = NULL; static gchar **g_quarks = NULL; static GQuark g_quark_seq_id = 0; /* --- functions --- */ + +/* HOLDS: g_dataset_global_lock */ static inline void g_datalist_clear_i (GData **datalist) { @@ -109,13 +121,16 @@ g_datalist_clear (GData **datalist) { g_return_if_fail (datalist != NULL); + g_lock (g_dataset_global); if (!g_dataset_location_ht) g_data_initialize (); while (*datalist) g_datalist_clear_i (datalist); + g_unlock (g_dataset_global); } +/* HOLDS: g_dataset_global_lock */ static inline GDataset* g_dataset_lookup (gconstpointer dataset_location) { @@ -131,6 +146,7 @@ g_dataset_lookup (gconstpointer dataset_location) return dataset; } +/* HOLDS: g_dataset_global_lock */ static void g_dataset_destroy_internal (GDataset *dataset) { @@ -158,6 +174,7 @@ g_dataset_destroy (gconstpointer dataset_location) { g_return_if_fail (dataset_location != NULL); + g_lock (g_dataset_global); if (g_dataset_location_ht) { register GDataset *dataset; @@ -166,8 +183,10 @@ g_dataset_destroy (gconstpointer dataset_location) if (dataset) g_dataset_destroy_internal (dataset); } + g_unlock (g_dataset_global); } +/* HOLDS: g_dataset_global_lock */ static inline void g_data_set_internal (GData **datalist, GQuark key_id, @@ -293,9 +312,10 @@ g_dataset_id_set_data_full (gconstpointer dataset_location, return; } + g_lock (g_dataset_global); if (!g_dataset_location_ht) g_data_initialize (); - + dataset = g_dataset_lookup (dataset_location); if (!dataset) { @@ -308,6 +328,7 @@ g_dataset_id_set_data_full (gconstpointer dataset_location, } g_data_set_internal (&dataset->datalist, key_id, data, destroy_func, dataset); + g_unlock (g_dataset_global); } void @@ -327,10 +348,12 @@ g_datalist_id_set_data_full (GData **datalist, return; } + g_lock (g_dataset_global); if (!g_dataset_location_ht) g_data_initialize (); g_data_set_internal (datalist, key_id, data, destroy_func, NULL); + g_unlock (g_dataset_global); } void @@ -339,6 +362,7 @@ g_dataset_id_remove_no_notify (gconstpointer dataset_location, { g_return_if_fail (dataset_location != NULL); + g_lock (g_dataset_global); if (key_id && g_dataset_location_ht) { GDataset *dataset; @@ -346,7 +370,8 @@ g_dataset_id_remove_no_notify (gconstpointer dataset_location, dataset = g_dataset_lookup (dataset_location); if (dataset) g_data_set_internal (&dataset->datalist, key_id, NULL, (GDestroyNotify) 42, dataset); - } + } + g_unlock (g_dataset_global); } void @@ -355,8 +380,10 @@ g_datalist_id_remove_no_notify (GData **datalist, { g_return_if_fail (datalist != NULL); + g_lock (g_dataset_global); if (key_id && g_dataset_location_ht) g_data_set_internal (datalist, key_id, NULL, (GDestroyNotify) 42, NULL); + g_unlock (g_dataset_global); } gpointer @@ -365,6 +392,7 @@ g_dataset_id_get_data (gconstpointer dataset_location, { g_return_val_if_fail (dataset_location != NULL, NULL); + g_lock (g_dataset_global); if (key_id && g_dataset_location_ht) { register GDataset *dataset; @@ -376,10 +404,14 @@ g_dataset_id_get_data (gconstpointer dataset_location, for (list = dataset->datalist; list; list = list->next) if (list->id == key_id) - return list->data; + { + g_unlock (g_dataset_global); + return list->data; + } } } - + g_unlock (g_dataset_global); + return NULL; } @@ -411,17 +443,23 @@ g_dataset_foreach (gconstpointer dataset_location, g_return_if_fail (dataset_location != NULL); g_return_if_fail (func != NULL); + g_lock (g_dataset_global); if (g_dataset_location_ht) { dataset = g_dataset_lookup (dataset_location); + g_unlock (g_dataset_global); if (dataset) { register GData *list; for (list = dataset->datalist; list; list = list->next) - func (list->id, list->data, user_data); + func (list->id, list->data, user_data); } } + else + { + g_unlock (g_dataset_global); + } } void @@ -446,6 +484,7 @@ g_datalist_init (GData **datalist) *datalist = NULL; } +/* HOLDS: g_dataset_global_lock */ static void g_data_initialize (void) { @@ -468,12 +507,15 @@ g_data_initialize (void) GQuark g_quark_try_string (const gchar *string) { + GQuark quark = 0; g_return_val_if_fail (string != NULL, 0); + g_lock (g_quark_global); if (g_quark_ht) - return (gulong) g_hash_table_lookup (g_quark_ht, string); - else - return 0; + quark = GPOINTER_TO_UINT (g_hash_table_lookup (g_quark_ht, string)); + g_unlock (g_quark_global); + + return quark; } GQuark @@ -483,6 +525,7 @@ g_quark_from_string (const gchar *string) g_return_val_if_fail (string != NULL, 0); + g_lock (g_quark_global); if (g_quark_ht) quark = (gulong) g_hash_table_lookup (g_quark_ht, string); else @@ -493,6 +536,7 @@ g_quark_from_string (const gchar *string) if (!quark) quark = g_quark_new (g_strdup (string)); + g_unlock (g_quark_global); return quark; } @@ -504,6 +548,7 @@ g_quark_from_static_string (const gchar *string) g_return_val_if_fail (string != NULL, 0); + g_lock (g_quark_global); if (g_quark_ht) quark = (gulong) g_hash_table_lookup (g_quark_ht, string); else @@ -514,19 +559,24 @@ g_quark_from_static_string (const gchar *string) if (!quark) quark = g_quark_new ((gchar*) string); - + g_unlock (g_quark_global); + return quark; } gchar* g_quark_to_string (GQuark quark) { + gchar* result = NULL; + g_lock (g_quark_global); if (quark > 0 && quark <= g_quark_seq_id) - return g_quarks[quark - 1]; - else - return NULL; + result = g_quarks[quark - 1]; + g_unlock (g_quark_global); + + return result; } +/* HOLDS: g_quark_global_lock */ static inline GQuark g_quark_new (gchar *string) { diff --git a/glib/gdate.c b/glib/gdate.c index 69c337def..7c60e23d9 100644 --- a/glib/gdate.c +++ b/glib/gdate.c @@ -16,6 +16,11 @@ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ + +/* + * MT safe + */ + #include "glib.h" #include @@ -383,6 +388,8 @@ g_date_clear (GDate *d, guint ndates) memset (d, 0x0, ndates*sizeof (GDate)); } +static G_LOCK_DEFINE(g_date_global); + /* These are for the parser, output to the user should use * * g_date_strftime () - this creates more never-freed memory to annoy * all those memory debugger users. :-) @@ -429,6 +436,7 @@ typedef struct _GDateParseTokens GDateParseTokens; #define NUM_LEN 10 +/* HOLDS: g_date_global_lock */ static void g_date_fill_parse_tokens (const gchar *str, GDateParseTokens *pt) { @@ -488,7 +496,7 @@ g_date_fill_parse_tokens (const gchar *str, GDateParseTokens *pt) if (found != NULL) { pt->month = i; - return; + return; } } @@ -502,12 +510,13 @@ g_date_fill_parse_tokens (const gchar *str, GDateParseTokens *pt) return; } } - + ++i; - } + } } } +/* HOLDS: g_date_global_lock */ static void g_date_prepare_to_parse (const gchar *str, GDateParseTokens *pt) { @@ -641,6 +650,8 @@ g_date_set_parse (GDate *d, /* set invalid */ g_date_clear (d, 1); + g_lock (g_date_global); + g_date_prepare_to_parse (str, &pt); #ifdef G_ENABLE_DEBUG @@ -649,7 +660,11 @@ g_date_set_parse (GDate *d, #endif - if (pt.num_ints == 4) return; /* presumably a typo; bail out. */ + if (pt.num_ints == 4) + { + g_unlock (g_date_global); + return; /* presumably a typo; bail out. */ + } if (pt.num_ints > 1) { @@ -765,6 +780,7 @@ g_date_set_parse (GDate *d, else g_message ("Rejected DMY %u %u %u", day, m, y); #endif + g_unlock (g_date_global); } void diff --git a/glib/gerror.c b/glib/gerror.c index 6aeb8b517..2615ce2b4 100644 --- a/glib/gerror.c +++ b/glib/gerror.c @@ -17,6 +17,11 @@ * Boston, MA 02111-1307, USA. */ +/* + * MT safe ; except for g_on_error_stack_trace, but who wants thread safety + * then + */ + #ifdef HAVE_CONFIG_H #include #endif diff --git a/glib/ghash.c b/glib/ghash.c index 4ab82b3fa..724036388 100644 --- a/glib/ghash.c +++ b/glib/ghash.c @@ -16,6 +16,11 @@ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ + +/* + * MT safe + */ + #include "glib.h" @@ -52,6 +57,8 @@ static void g_hash_node_destroy (GHashNode *hash_node); static void g_hash_nodes_destroy (GHashNode *hash_node); +static G_LOCK_DEFINE(g_hash_global); + static GMemChunk *node_mem_chunk = NULL; static GHashNode *node_free_list = NULL; @@ -338,6 +345,7 @@ g_hash_node_new (gpointer key, { GHashNode *hash_node; + g_lock (g_hash_global); if (node_free_list) { hash_node = node_free_list; @@ -352,6 +360,7 @@ g_hash_node_new (gpointer key, hash_node = g_chunk_new (GHashNode, node_mem_chunk); } + g_unlock (g_hash_global); hash_node->key = key; hash_node->value = value; @@ -363,8 +372,10 @@ g_hash_node_new (gpointer key, static void g_hash_node_destroy (GHashNode *hash_node) { + g_lock (g_hash_global); hash_node->next = node_free_list; node_free_list = hash_node; + g_unlock (g_hash_global); } static void @@ -380,6 +391,8 @@ g_hash_nodes_destroy (GHashNode *hash_node) while (node->next) node = node->next; + g_lock (g_hash_global); node->next = node_free_list; node_free_list = hash_node; + g_unlock (g_hash_global); } diff --git a/glib/ghook.c b/glib/ghook.c index 47a2874a4..b683b7c31 100644 --- a/glib/ghook.c +++ b/glib/ghook.c @@ -19,6 +19,11 @@ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ + +/* + * MT safe + */ + #include "glib.h" diff --git a/glib/giochannel.c b/glib/giochannel.c index fa4262602..0693a084b 100644 --- a/glib/giochannel.c +++ b/glib/giochannel.c @@ -20,6 +20,10 @@ * Boston, MA 02111-1307, USA. */ +/* + * MT safe + */ + #include "glib.h" #include diff --git a/glib/giounix.c b/glib/giounix.c index 5e605a478..82944be89 100644 --- a/glib/giounix.c +++ b/glib/giounix.c @@ -20,6 +20,10 @@ * Boston, MA 02111-1307, USA. */ +/* + * MT safe + */ + #include "glib.h" #include #include diff --git a/glib/glib.h b/glib/glib.h index 33fa042e9..d4d1aaa77 100644 --- a/glib/glib.h +++ b/glib/glib.h @@ -2597,6 +2597,140 @@ gint gwin_closedir (DIR *dir); #endif /* NATIVE_WIN32 */ +/* functions for thread support for glib. */ + +typedef struct _GMutex GMutex; +typedef struct _GCond GCond; +typedef struct _GPrivate GPrivate; +typedef struct _GStaticPrivate GStaticPrivate; + +typedef struct _GThreadFunctions GThreadFunctions; +struct _GThreadFunctions +{ + GMutex* (*mutex_new) (void); + void (*mutex_lock) (GMutex* mutex); + gboolean (*mutex_trylock) (GMutex* mutex); + void (*mutex_unlock) (GMutex* mutex); + void (*mutex_free) (GMutex* mutex); + GCond* (*cond_new) (void); + void (*cond_signal) (GCond* cond); + void (*cond_broadcast) (GCond* cond); + void (*cond_wait) (GCond* cond, GMutex* mutex); + gboolean (*cond_timed_wait) (GCond* cond, GMutex* mutex, + GTimeVal *end_time); + void (*cond_free) (GCond* cond); + GPrivate* (*private_new) (GDestroyNotify destructor); + gpointer (*private_get) (GPrivate* private); + void (*private_set) (GPrivate* private, gpointer value); +}; + +GUTILS_C_VAR GThreadFunctions g_thread_functions_for_glib_use; +GUTILS_C_VAR gboolean g_thread_use_default_impl; +GUTILS_C_VAR gboolean g_thread_supported; + +/* initializes the mutex/cond/private implementation for glib, might + * only be called once, and must not be called directly or indirectly + * from another glib-function, e.g. as a callback. */ +void g_thread_init(GThreadFunctions* init); + +/* Internal functions for fallback static mutex implementation + * Please don't use it directly + */ +GMutex* g_static_mutex_get_mutex_impl(GMutex** mutex); + +#define G_USE_THREAD_FUNC_UNCOND(name,arg) \ + (*g_thread_functions_for_glib_use.name)arg +#define G_USE_THREAD_FUNC(name,fail,arg) \ + (g_thread_supported ? G_USE_THREAD_FUNC_UNCOND(name,arg) : (fail)) + +/* keep in mind, all those mutexes and static mutexes are not + * recursive in general, don't rely on that */ +#define g_mutex_new() G_USE_THREAD_FUNC_UNCOND(mutex_new,()) +#define g_mutex_lock(mutex) G_USE_THREAD_FUNC(mutex_lock,(void)0,(mutex)) +#define g_mutex_trylock(mutex) G_USE_THREAD_FUNC(mutex_trylock,TRUE,(mutex)) +#define g_mutex_unlock(mutex) G_USE_THREAD_FUNC(mutex_unlock,(void)0,(mutex)) +#define g_mutex_free(mutex) G_USE_THREAD_FUNC(mutex_free,(void)0,(mutex)) +#define g_cond_new() G_USE_THREAD_FUNC_UNCOND(cond_new,()) +#define g_cond_signal(cond) G_USE_THREAD_FUNC(cond_signal,(void)0,(cond)) +#define g_cond_broadcast(cond) G_USE_THREAD_FUNC(cond_broadcast,(void)0,(cond)) +#define g_cond_wait(cond,mutex) G_USE_THREAD_FUNC(cond_wait,(void)0,(cond,mutex)) +#define g_cond_timed_wait(cond,mutex,abs_time) \ + G_USE_THREAD_FUNC(cond_timed_wait,TRUE,(cond,mutex,abs_time)) +#define g_cond_free(cond) G_USE_THREAD_FUNC(cond_free,(void)0,(cond)) + +#define g_private_new(destructor) \ + G_USE_THREAD_FUNC_UNCOND(private_new,(destructor)) +#define g_private_get(private) \ + G_USE_THREAD_FUNC(private_get,((gpointer)private),(private)) +#define g_private_set(private,value) \ + G_USE_THREAD_FUNC(private_set,(void)(private=(GPrivate *)(value)), \ + (private,value)) + +/* GStaticMutex'es can be statically initialized with the value + * G_STATIC_MUTEX_INIT, and then they can directly be used, that is + * much easier, than having to explicitly allocate the mutex before + * use */ +#define g_static_mutex_lock(mutex) \ + g_mutex_lock( g_static_mutex_get_mutex(mutex) ) +#define g_static_mutex_trylock(mutex) \ + g_mutex_trylock( g_static_mutex_get_mutex(mutex) ) +#define g_static_mutex_unlock(mutex) \ + g_mutex_unlock( g_static_mutex_get_mutex(mutex) ) + +struct _GStaticPrivate +{ + guint index; +}; + +#define G_STATIC_PRIVATE_INIT { 0 } + +gpointer g_static_private_get (GStaticPrivate* private); +void g_static_private_set (GStaticPrivate *private, + gpointer data, + GDestroyNotify notify); + +/* these are some convenience macros, for using StaticMutex'es, you + * define them by G_LOCK_DEFINE(name), where name could for example be the + * name of the protected varibale, and you (un)lock them with + * g_(un)lock(name) */ +#define g_lock_name(name) (name ## _lock) +#define G_LOCK_DEFINE(name) GStaticMutex g_lock_name(name)=G_STATIC_MUTEX_INIT + +#ifdef G_DEBUG_LOCKS +#define g_lock(name) G_STMT_START{ \ + g_log (G_LOG_DOMAIN, \ + G_LOG_LEVEL_MESSAGE, \ + "file %s: line %d (%s): locking: %s ", \ + __FILE__, \ + __LINE__, \ + __PRETTY_FUNCTION__, \ + #name); \ + g_static_mutex_lock(g_lock_name(name)); \ + }G_STMT_END +#define g_unlock(name) G_STMT_START{ \ + g_log (G_LOG_DOMAIN, \ + G_LOG_LEVEL_MESSAGE, \ + "file %s: line %d (%s): unlocking: %s ", \ + __FILE__, \ + __LINE__, \ + __PRETTY_FUNCTION__, \ + #name); \ + g_static_mutex_unlock(g_lock_name(name)); \ + }G_STMT_END +#define g_trylock(name) G_STMT_START{ \ + g_log (G_LOG_DOMAIN, \ + G_LOG_LEVEL_MESSAGE, \ + "file %s: line %d (%s): try locking: %s ", \ + __FILE__, \ + __LINE__, \ + __PRETTY_FUNCTION__, \ + #name); \ + }G_STMT_END, g_static_mutex_trylock(g_lock_name(name)) +#else /* !G_DEBUG_LOCKS */ +#define g_lock(name) g_static_mutex_lock(g_lock_name(name)) +#define g_unlock(name) g_static_mutex_unlock(g_lock_name(name)) +#define g_trylock(name) g_static_mutex_trylock(g_lock_name(name)) +#endif #ifdef __cplusplus } diff --git a/glib/glist.c b/glib/glist.c index 41a09dd18..e74dee872 100644 --- a/glib/glist.c +++ b/glib/glist.c @@ -16,6 +16,11 @@ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ + +/* + * MT safe + */ + #include "glib.h" @@ -31,9 +36,11 @@ struct _GAllocator /* from gmem.c */ }; static GAllocator *current_allocator = NULL; +static G_LOCK_DEFINE(current_allocator); -void -g_list_push_allocator (GAllocator *allocator) +/* HOLDS: current_allocator_lock */ +static void +g_list_validate_allocator (GAllocator *allocator) { g_return_if_fail (allocator != NULL); g_return_if_fail (allocator->is_unused == TRUE); @@ -58,13 +65,22 @@ g_list_push_allocator (GAllocator *allocator) } allocator->is_unused = FALSE; +} + +void +g_list_push_allocator(GAllocator *allocator) +{ + g_list_validate_allocator ( allocator ); + g_lock (current_allocator); allocator->last = current_allocator; current_allocator = allocator; + g_unlock (current_allocator); } void g_list_pop_allocator (void) { + g_lock (current_allocator); if (current_allocator) { GAllocator *allocator; @@ -74,6 +90,7 @@ g_list_pop_allocator (void) allocator->last = NULL; allocator->is_unused = TRUE; } + g_unlock (current_allocator); } GList* @@ -81,9 +98,15 @@ g_list_alloc (void) { GList *list; + g_lock (current_allocator); if (!current_allocator) - g_list_push_allocator (g_allocator_new ("GLib default GList allocator", 1024)); - + { + GAllocator *allocator = g_allocator_new ("GLib default GList allocator", + 1024); + g_list_validate_allocator (allocator); + allocator->last = NULL; + current_allocator = allocator; + } if (!current_allocator->free_lists) { list = g_chunk_new (GList, current_allocator->mem_chunk); @@ -103,6 +126,7 @@ g_list_alloc (void) current_allocator->free_lists = list->next; } } + g_unlock (current_allocator); list->next = NULL; list->prev = NULL; @@ -112,23 +136,31 @@ g_list_alloc (void) void g_list_free (GList *list) { +#if 0 if (list) { - list->data = list->next; + list->data = list->next; + g_lock (current_allocator); list->next = current_allocator->free_lists; current_allocator->free_lists = list; + g_unlock (current_allocator); } +#endif } void g_list_free_1 (GList *list) { +#if 0 if (list) { - list->data = NULL; + list->data = NULL; + g_lock (current_allocator); list->next = current_allocator->free_lists; current_allocator->free_lists = list; + g_unlock (current_allocator); } +#endif } GList* diff --git a/glib/gmain.c b/glib/gmain.c index 1f13e9097..5d3ae8d46 100644 --- a/glib/gmain.c +++ b/glib/gmain.c @@ -20,9 +20,14 @@ * Boston, MA 02111-1307, USA. */ +/* + * MT safe + */ + #include "glib.h" #include #include +#include #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 (¤t_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 (¤t_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 (¤t_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; @@ -538,13 +633,29 @@ g_main_poll (gint timeout, gboolean use_priority, gint priority) void g_main_poll_add (gint priority, GPollFD *fd) +{ + g_lock (main_loop); + g_main_poll_add_unlocked (priority, fd); + g_unlock (main_loop); +} + +static void +g_main_poll_add_unlocked (gint priority, + GPollFD *fd) { GPollRec *lastrec, *pollrec, *newrec; if (!poll_chunk) poll_chunk = g_mem_chunk_create (GPollRec, 32, G_ALLOC_ONLY); - newrec = g_chunk_new (GPollRec, poll_chunk); + if (poll_free_list) + { + newrec = poll_free_list; + poll_free_list = newrec->next; + } + else + newrec = g_chunk_new (GPollRec, poll_chunk); + newrec->fd = fd; newrec->priority = priority; @@ -564,6 +675,8 @@ g_main_poll_add (gint priority, newrec->next = pollrec; n_poll_records++; + + g_unlock (main_loop); } void @@ -571,6 +684,8 @@ g_main_poll_remove (GPollFD *fd) { GPollRec *pollrec, *lastrec; + g_lock (main_loop); + lastrec = NULL; pollrec = poll_records; @@ -585,12 +700,15 @@ g_main_poll_remove (GPollFD *fd) pollrec->next = poll_free_list; poll_free_list = pollrec; + + n_poll_records--; + break; } lastrec = pollrec; pollrec = pollrec->next; } - n_poll_records--; + g_unlock (main_loop); } void diff --git a/glib/gmem.c b/glib/gmem.c index c29ee660f..a4907ffca 100644 --- a/glib/gmem.c +++ b/glib/gmem.c @@ -17,6 +17,10 @@ * Boston, MA 02111-1307, USA. */ +/* + * MT safe + */ + #ifdef HAVE_CONFIG_H #include #endif @@ -48,8 +52,12 @@ */ #if defined(ENABLE_MEM_PROFILE) && defined(ENABLE_MEM_PROFILE_EXCLUDES_MEM_CHUNKS) -#define ENTER_MEM_CHUNK_ROUTINE() allocating_for_mem_chunk++ -#define LEAVE_MEM_CHUNK_ROUTINE() allocating_for_mem_chunk-- +#define ENTER_MEM_CHUNK_ROUTINE() \ + g_static_set (allocating_for_mem_chunk, \ + g_static_get (allocating_for_mem_chunk) + 1) +#define ENTER_MEM_CHUNK_ROUTINE() \ + g_static_set (allocating_for_mem_chunk, \ + g_static_get (allocating_for_mem_chunk) - 1) #else #define ENTER_MEM_CHUNK_ROUTINE() #define LEAVE_MEM_CHUNK_ROUTINE() @@ -117,13 +125,19 @@ static gint g_mem_chunk_area_search (GMemArea *a, gchar *addr); +/* here we can't use StaticMutexes, as they depend upon a working + * g_malloc, the same holds true for StaticPrivate */ +static GMutex* mem_chunks_lock = NULL; static GRealMemChunk *mem_chunks = NULL; #ifdef ENABLE_MEM_PROFILE +static GMutex* mem_profile_lock; static gulong allocations[MEM_PROFILE_TABLE_SIZE] = { 0 }; static gulong allocated_mem = 0; static gulong freed_mem = 0; -static gint allocating_for_mem_chunk = 0; +static GPrivate* allocating_for_mem_chunk = NULL; +#define IS_IN_MEM_CHUNK_ROUTINE() \ + GPOINTER_TO_UINT (g_static_get (allocating_for_mem_chunk)) #endif /* ENABLE_MEM_PROFILE */ @@ -174,8 +188,9 @@ g_malloc (gulong size) *t = size; #ifdef ENABLE_MEM_PROFILE + g_mutex_lock (mem_profile_lock); # ifdef ENABLE_MEM_PROFILE_EXCLUDES_MEM_CHUNKS - if(!allocating_for_mem_chunk) { + if(!IS_IN_MEM_CHUNK_ROUTINE()) { # endif if (size <= MEM_PROFILE_TABLE_SIZE - 1) allocations[size-1] += 1; @@ -185,6 +200,7 @@ g_malloc (gulong size) # ifdef ENABLE_MEM_PROFILE_EXCLUDES_MEM_CHUNKS } # endif + g_mutex_unlock (mem_profile_lock); #endif /* ENABLE_MEM_PROFILE */ #endif /* ENABLE_MEM_PROFILE || ENABLE_MEM_CHECK */ @@ -237,8 +253,9 @@ g_malloc0 (gulong size) *t = size; # ifdef ENABLE_MEM_PROFILE + g_mutex_lock (mem_profile_lock); # ifdef ENABLE_MEM_PROFILE_EXCLUDES_MEM_CHUNKS - if(!allocating_for_mem_chunk) { + if(!IS_IN_MEM_CHUNK_ROUTINE()) { # endif if (size <= (MEM_PROFILE_TABLE_SIZE - 1)) allocations[size-1] += 1; @@ -248,8 +265,9 @@ g_malloc0 (gulong size) # ifdef ENABLE_MEM_PROFILE_EXCLUDES_MEM_CHUNKS } # endif + g_mutex_unlock (mem_profile_lock); # endif /* ENABLE_MEM_PROFILE */ -#endif /* ENABLE_MEM_PROFILE */ +#endif /* ENABLE_MEM_PROFILE || ENABLE_MEM_CHECK */ return p; @@ -286,7 +304,9 @@ g_realloc (gpointer mem, #if defined(ENABLE_MEM_PROFILE) || defined(ENABLE_MEM_CHECK) t = (gulong*) ((guchar*) mem - SIZEOF_LONG); #ifdef ENABLE_MEM_PROFILE + g_mutex_lock (mem_profile); freed_mem += *t; + g_mutex_unlock (mem_profile); #endif /* ENABLE_MEM_PROFILE */ mem = t; #endif /* ENABLE_MEM_PROFILE || ENABLE_MEM_CHECK */ @@ -321,8 +341,9 @@ g_realloc (gpointer mem, *t = size; #ifdef ENABLE_MEM_PROFILE + g_mutex_lock (mem_profile_lock); #ifdef ENABLE_MEM_PROFILE_EXCLUDES_MEM_CHUNKS - if(!allocating_for_mem_chunk) { + if(!IS_IN_MEM_CHUNK_ROUTINE()) { #endif if (size <= (MEM_PROFILE_TABLE_SIZE - 1)) allocations[size-1] += 1; @@ -332,6 +353,7 @@ g_realloc (gpointer mem, #ifdef ENABLE_MEM_PROFILE_EXCLUDES_MEM_CHUNKS } #endif + g_mutex_unlock (mem_profile_lock); #endif /* ENABLE_MEM_PROFILE */ #endif /* ENABLE_MEM_PROFILE || ENABLE_MEM_CHECK */ @@ -352,8 +374,10 @@ g_free (gpointer mem) #if defined(ENABLE_MEM_PROFILE) || defined(ENABLE_MEM_CHECK) t = (gulong*) ((guchar*) mem - SIZEOF_LONG); size = *t; -#ifdef ENABLE_MEM_PROFILE +#ifdef ENABLE_MEM_PROFILE + g_mutex_lock (mem_profile); freed_mem += size; + g_mutex_unlock (mem_profile); #endif /* ENABLE_MEM_PROFILE */ mem = t; #endif /* ENABLE_MEM_PROFILE || ENABLE_MEM_CHECK */ @@ -380,19 +404,29 @@ g_mem_profile (void) { #ifdef ENABLE_MEM_PROFILE gint i; - + gulong local_allocations[MEM_PROFILE_TABLE_SIZE]; + gulong local_allocated_mem; + gulong local_freed_mem; + + g_mutex_lock (mem_profile); for (i = 0; i < (MEM_PROFILE_TABLE_SIZE - 1); i++) - if (allocations[i] > 0) + 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 (local_allocations[i] > 0) g_log (g_log_domain_glib, G_LOG_LEVEL_INFO, - "%lu allocations of %d bytes\n", allocations[i], i + 1); + "%lu allocations of %d bytes\n", local_allocations[i], i + 1); - if (allocations[MEM_PROFILE_TABLE_SIZE - 1] > 0) + if (local_allocations[MEM_PROFILE_TABLE_SIZE - 1] > 0) g_log (g_log_domain_glib, G_LOG_LEVEL_INFO, "%lu allocations of greater than %d bytes\n", - allocations[MEM_PROFILE_TABLE_SIZE - 1], MEM_PROFILE_TABLE_SIZE - 1); - g_log (g_log_domain_glib, G_LOG_LEVEL_INFO, "%lu bytes allocated\n", allocated_mem); - g_log (g_log_domain_glib, G_LOG_LEVEL_INFO, "%lu bytes freed\n", freed_mem); - g_log (g_log_domain_glib, G_LOG_LEVEL_INFO, "%lu bytes in use\n", allocated_mem - freed_mem); + local_allocations[MEM_PROFILE_TABLE_SIZE - 1], MEM_PROFILE_TABLE_SIZE - 1); + g_log (g_log_domain_glib, G_LOG_LEVEL_INFO, "%lu bytes allocated\n", local_allocated_mem); + g_log (g_log_domain_glib, G_LOG_LEVEL_INFO, "%lu bytes freed\n", local_freed_mem); + g_log (g_log_domain_glib, G_LOG_LEVEL_INFO, "%lu bytes in use\n", local_allocated_mem - local_freed_mem); #endif /* ENABLE_MEM_PROFILE */ } @@ -460,11 +494,13 @@ g_mem_chunk_new (gchar *name, mem_chunk->area_size += mem_chunk->atom_size - (mem_chunk->area_size % mem_chunk->atom_size); */ + g_mutex_lock (mem_chunks_lock); mem_chunk->next = mem_chunks; mem_chunk->prev = NULL; if (mem_chunks) mem_chunks->prev = mem_chunk; mem_chunks = mem_chunk; + g_mutex_unlock (mem_chunks_lock); LEAVE_MEM_CHUNK_ROUTINE(); @@ -497,8 +533,10 @@ g_mem_chunk_destroy (GMemChunk *mem_chunk) if (rmem_chunk->prev) rmem_chunk->prev->next = rmem_chunk->next; + g_mutex_lock (mem_chunks_lock); if (rmem_chunk == mem_chunks) mem_chunks = mem_chunks->next; + g_mutex_unlock (mem_chunks_lock); if (rmem_chunk->type == G_ALLOC_AND_FREE) g_tree_destroy (rmem_chunk->mem_tree); @@ -826,21 +864,26 @@ g_mem_chunk_info (void) gint count; count = 0; + g_mutex_lock (mem_chunks_lock); mem_chunk = mem_chunks; while (mem_chunk) { count += 1; mem_chunk = mem_chunk->next; } + g_mutex_unlock (mem_chunks_lock); g_log (g_log_domain_glib, G_LOG_LEVEL_INFO, "%d mem chunks\n", count); + g_mutex_lock (mem_chunks_lock); mem_chunk = mem_chunks; + g_mutex_unlock (mem_chunks_lock); + while (mem_chunk) { g_mem_chunk_print ((GMemChunk*) mem_chunk); mem_chunk = mem_chunk->next; - } + } } void @@ -848,7 +891,9 @@ g_blow_chunks (void) { GRealMemChunk *mem_chunk; + g_mutex_lock (mem_chunks_lock); mem_chunk = mem_chunks; + g_mutex_unlock (mem_chunks_lock); while (mem_chunk) { g_mem_chunk_clean ((GMemChunk*) mem_chunk); @@ -940,3 +985,13 @@ g_allocator_free (GAllocator *allocator) g_free (allocator); } + +void +g_mem_init (void) +{ + mem_chunks_lock = g_mutex_new(); +#ifdef ENABLE_MEM_PROFILE + mem_profile_lock = g_mutex_new(); + allocating_for_mem_chunk = g_private_new(NULL); +#endif +} diff --git a/glib/gmessages.c b/glib/gmessages.c index e0c6eacb1..eb8aed7a8 100644 --- a/glib/gmessages.c +++ b/glib/gmessages.c @@ -17,6 +17,10 @@ * Boston, MA 02111-1307, USA. */ +/* + * MT safe + */ + #ifdef HAVE_CONFIG_H #include #endif @@ -31,7 +35,7 @@ #endif #ifdef NATIVE_WIN32 -/* Just use stdio. If we're out of memroy, we're hosed anyway. */ +/* Just use stdio. If we're out of memory, we're hosed anyway. */ #undef write static inline int @@ -67,6 +71,9 @@ struct _GLogHandler /* --- variables --- */ + +static GMutex* g_messages_lock = NULL; + const gchar *g_log_domain_glib = "GLib"; static GLogDomain *g_log_domains = NULL; static GLogLevelFlags g_log_always_fatal = G_LOG_FATAL_MASK; @@ -76,20 +83,27 @@ static GErrorFunc glib_error_func = NULL; static GWarningFunc glib_warning_func = NULL; static GPrintFunc glib_message_func = NULL; +static GPrivate* g_log_depth = NULL; + /* --- functions --- */ static inline GLogDomain* g_log_find_domain (const gchar *log_domain) { register GLogDomain *domain; - + + g_mutex_lock (g_messages_lock); domain = g_log_domains; while (domain) { if (strcmp (domain->log_domain, log_domain) == 0) - return domain; + { + g_mutex_unlock (g_messages_lock); + return domain; + } domain = domain->next; } + g_mutex_unlock (g_messages_lock); return NULL; } @@ -102,8 +116,11 @@ g_log_domain_new (const gchar *log_domain) domain->log_domain = g_strdup (log_domain); domain->fatal_mask = G_LOG_FATAL_MASK; domain->handlers = NULL; + + g_mutex_lock (g_messages_lock); domain->next = g_log_domains; g_log_domains = domain; + g_mutex_unlock (g_messages_lock); return domain; } @@ -116,7 +133,9 @@ g_log_domain_check_free (GLogDomain *domain) { register GLogDomain *last, *work; - last = NULL; + last = NULL; + + g_mutex_lock (g_messages_lock); work = g_log_domains; while (work) { @@ -131,7 +150,8 @@ g_log_domain_check_free (GLogDomain *domain) break; } work = work->next; - } + } + g_mutex_unlock (g_messages_lock); } } @@ -170,8 +190,10 @@ g_log_set_always_fatal (GLogLevelFlags fatal_mask) /* remove bogus flag */ fatal_mask &= ~G_LOG_FLAG_FATAL; + g_mutex_lock (g_messages_lock); old_mask = g_log_always_fatal; g_log_always_fatal = fatal_mask; + g_mutex_unlock (g_messages_lock); return old_mask; } @@ -223,7 +245,9 @@ g_log_set_handler (const gchar *log_domain, domain = g_log_domain_new (log_domain); handler = g_new (GLogHandler, 1); + g_mutex_lock (g_messages_lock); handler->id = ++handler_id; + g_mutex_unlock (g_messages_lock); handler->log_level = log_levels; handler->log_func = log_func; handler->data = user_data; @@ -311,19 +335,25 @@ g_logv (const gchar *log_domain, test_level = 1 << i; if (log_level & test_level) { - static guint g_log_depth = 0; + guint depth = GPOINTER_TO_UINT (g_private_get (g_log_depth)); GLogDomain *domain; GLogFunc log_func; gpointer data = NULL; domain = g_log_find_domain (log_domain ? log_domain : ""); - if (g_log_depth++) + if (depth) test_level |= G_LOG_FLAG_RECURSION; - if ((((domain ? domain->fatal_mask : G_LOG_FATAL_MASK) | g_log_always_fatal) & - test_level) != 0) - test_level |= G_LOG_FLAG_FATAL; + depth++; + g_private_set (g_log_depth, GUINT_TO_POINTER (depth)); + + g_mutex_lock (g_messages_lock); + if ((((domain ? domain->fatal_mask : G_LOG_FATAL_MASK) | + g_log_always_fatal) & test_level) != 0) + test_level |= G_LOG_FLAG_FATAL; + g_mutex_unlock (g_messages_lock); + log_func = g_log_domain_get_handler (domain, test_level, &data); log_func (log_domain, test_level, buffer, data); @@ -332,7 +362,8 @@ g_logv (const gchar *log_domain, if (test_level & G_LOG_FLAG_FATAL) abort (); - g_log_depth--; + depth--; + g_private_set (g_log_depth, GUINT_TO_POINTER (depth)); } } } @@ -362,8 +393,11 @@ g_log_default_handler (const gchar *log_domain, gint fd; #endif gboolean in_recursion; - gboolean is_fatal; - + gboolean is_fatal; + GErrorFunc local_glib_error_func; + GWarningFunc local_glib_warning_func; + GPrintFunc local_glib_message_func; + in_recursion = (log_level & G_LOG_FLAG_RECURSION) != 0; is_fatal = (log_level & G_LOG_FLAG_FATAL) != 0; log_level &= G_LOG_LEVEL_MASK; @@ -380,13 +414,19 @@ g_log_default_handler (const gchar *log_domain, fd = (log_level >= G_LOG_LEVEL_MESSAGE) ? 1 : 2; #endif + g_mutex_lock (g_messages_lock); + local_glib_error_func = glib_error_func; + local_glib_warning_func = glib_warning_func; + local_glib_message_func = glib_message_func; + g_mutex_unlock (g_messages_lock); + switch (log_level) { case G_LOG_LEVEL_ERROR: - if (!log_domain && glib_error_func) + if (!log_domain && local_glib_error_func) { /* compatibility code */ - glib_error_func (message); + local_glib_error_func (message); return; } /* use write(2) for output, in case we are out of memeory */ @@ -428,10 +468,10 @@ g_log_default_handler (const gchar *log_domain, write (fd, "\n", 1); break; case G_LOG_LEVEL_WARNING: - if (!log_domain && glib_warning_func) + if (!log_domain && local_glib_warning_func) { /* compatibility code */ - glib_warning_func (message); + local_glib_warning_func (message); return; } if (log_domain) @@ -453,10 +493,10 @@ g_log_default_handler (const gchar *log_domain, write (fd, "\n", 1); break; case G_LOG_LEVEL_MESSAGE: - if (!log_domain && glib_message_func) + if (!log_domain && local_glib_message_func) { /* compatibility code */ - glib_message_func (message); + local_glib_message_func (message); return; } if (log_domain) @@ -553,8 +593,10 @@ g_set_print_handler (GPrintFunc func) { GPrintFunc old_print_func; + g_mutex_lock (g_messages_lock); old_print_func = glib_print_func; glib_print_func = func; + g_mutex_unlock (g_messages_lock); return old_print_func; } @@ -565,6 +607,7 @@ g_print (const gchar *format, { va_list args; gchar *string; + GPrintFunc local_glib_print_func; g_return_if_fail (format != NULL); @@ -572,8 +615,12 @@ g_print (const gchar *format, string = g_strdup_vprintf (format, args); va_end (args); - if (glib_print_func) - glib_print_func (string); + g_mutex_lock (g_messages_lock); + local_glib_print_func = glib_print_func; + g_mutex_unlock (g_messages_lock); + + if (local_glib_print_func) + local_glib_print_func (string); else { fputs (string, stdout); @@ -587,8 +634,10 @@ g_set_printerr_handler (GPrintFunc func) { GPrintFunc old_printerr_func; + g_mutex_lock (g_messages_lock); old_printerr_func = glib_printerr_func; glib_printerr_func = func; + g_mutex_unlock (g_messages_lock); return old_printerr_func; } @@ -599,6 +648,7 @@ g_printerr (const gchar *format, { va_list args; gchar *string; + GPrintFunc local_glib_printerr_func; g_return_if_fail (format != NULL); @@ -606,8 +656,12 @@ g_printerr (const gchar *format, string = g_strdup_vprintf (format, args); va_end (args); - if (glib_printerr_func) - glib_printerr_func (string); + g_mutex_lock (g_messages_lock); + local_glib_printerr_func = glib_printerr_func; + g_mutex_unlock (g_messages_lock); + + if (local_glib_printerr_func) + local_glib_printerr_func (string); else { fputs (string, stderr); @@ -622,9 +676,11 @@ g_set_error_handler (GErrorFunc func) { GErrorFunc old_error_func; + g_mutex_lock (g_messages_lock); old_error_func = glib_error_func; glib_error_func = func; - + g_mutex_unlock (g_messages_lock); + return old_error_func; } @@ -634,8 +690,10 @@ g_set_warning_handler (GWarningFunc func) { GWarningFunc old_warning_func; + g_mutex_lock (g_messages_lock); old_warning_func = glib_warning_func; glib_warning_func = func; + g_mutex_unlock (g_messages_lock); return old_warning_func; } @@ -646,8 +704,17 @@ g_set_message_handler (GPrintFunc func) { GPrintFunc old_message_func; + g_mutex_lock (g_messages_lock); old_message_func = glib_message_func; glib_message_func = func; + g_mutex_unlock (g_messages_lock); return old_message_func; } + +void +g_messages_init (void) +{ + g_messages_lock = g_mutex_new(); + g_log_depth = g_private_new(NULL); +} diff --git a/glib/gnode.c b/glib/gnode.c index 9f6e544ba..089a4996d 100644 --- a/glib/gnode.c +++ b/glib/gnode.c @@ -19,6 +19,11 @@ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ + +/* + * MT safe + */ + #include "glib.h" /* node allocation @@ -34,10 +39,12 @@ struct _GAllocator /* from gmem.c */ GNode *free_nodes; /* implementation specific */ }; +static G_LOCK_DEFINE(current_allocator); static GAllocator *current_allocator = NULL; -void -g_node_push_allocator (GAllocator *allocator) +/* HOLDS: current_allocator_lock */ +static void +g_node_validate_allocator (GAllocator *allocator) { g_return_if_fail (allocator != NULL); g_return_if_fail (allocator->is_unused == TRUE); @@ -62,13 +69,22 @@ g_node_push_allocator (GAllocator *allocator) } allocator->is_unused = FALSE; +} + +void +g_node_push_allocator (GAllocator *allocator) +{ + g_node_validate_allocator ( allocator ); + g_lock (current_allocator); allocator->last = current_allocator; current_allocator = allocator; + g_unlock (current_allocator); } void g_node_pop_allocator (void) { + g_lock (current_allocator); if (current_allocator) { GAllocator *allocator; @@ -78,6 +94,7 @@ g_node_pop_allocator (void) allocator->last = NULL; allocator->is_unused = TRUE; } + g_unlock (current_allocator); } @@ -87,9 +104,15 @@ g_node_new (gpointer data) { GNode *node; + g_lock (current_allocator); if (!current_allocator) - g_node_push_allocator (g_allocator_new ("GLib default GNode allocator", 1024)); - + { + GAllocator *allocator = g_allocator_new ("GLib default GNode allocator", + 1024); + g_node_validate_allocator (allocator); + allocator->last = NULL; + current_allocator = allocator; + } if (!current_allocator->free_nodes) node = g_chunk_new (GNode, current_allocator->mem_chunk); else @@ -97,6 +120,7 @@ g_node_new (gpointer data) node = current_allocator->free_nodes; current_allocator->free_nodes = node->next; } + g_unlock (current_allocator); node->data = data; node->next = NULL; @@ -122,9 +146,11 @@ g_nodes_free (GNode *node) else break; } - + + g_lock (current_allocator); parent->next = current_allocator->free_nodes; current_allocator->free_nodes = node; + g_unlock (current_allocator); } void diff --git a/glib/gprimes.c b/glib/gprimes.c index 3d45c1ef7..404ebd605 100644 --- a/glib/gprimes.c +++ b/glib/gprimes.c @@ -16,6 +16,11 @@ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ + +/* + * MT safe + */ + #include "glib.h" static const guint g_primes[] = diff --git a/glib/grel.c b/glib/grel.c index 5fdf88098..544da6bfc 100644 --- a/glib/grel.c +++ b/glib/grel.c @@ -15,6 +15,11 @@ * License along with this library; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* + * MT safe + */ + #include "glib.h" #include #include diff --git a/glib/gscanner.c b/glib/gscanner.c index 02985a7f7..c6fd0dd4e 100644 --- a/glib/gscanner.c +++ b/glib/gscanner.c @@ -19,6 +19,11 @@ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ + +/* + * MT safe + */ + #define __gscanner_c__ #ifdef HAVE_CONFIG_H diff --git a/glib/gslist.c b/glib/gslist.c index 4efe2a575..1ed517ff6 100644 --- a/glib/gslist.c +++ b/glib/gslist.c @@ -16,6 +16,11 @@ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ + +/* + * MT safe + */ + #include "glib.h" @@ -30,10 +35,12 @@ struct _GAllocator /* from gmem.c */ GSList *free_lists; /* implementation specific */ }; +static G_LOCK_DEFINE(current_allocator); static GAllocator *current_allocator = NULL; -void -g_slist_push_allocator (GAllocator *allocator) +/* HOLDS: current_allocator_lock */ +static void +g_slist_validate_allocator (GAllocator *allocator) { g_return_if_fail (allocator != NULL); g_return_if_fail (allocator->is_unused == TRUE); @@ -58,13 +65,22 @@ g_slist_push_allocator (GAllocator *allocator) } allocator->is_unused = FALSE; +} + +void +g_slist_push_allocator (GAllocator *allocator) +{ + g_slist_validate_allocator (allocator); + g_lock (current_allocator); allocator->last = current_allocator; current_allocator = allocator; + g_unlock (current_allocator); } void g_slist_pop_allocator (void) { + g_lock (current_allocator); if (current_allocator) { GAllocator *allocator; @@ -74,6 +90,7 @@ g_slist_pop_allocator (void) allocator->last = NULL; allocator->is_unused = TRUE; } + g_unlock (current_allocator); } GSList* @@ -81,9 +98,15 @@ g_slist_alloc (void) { GSList *list; + g_lock (current_allocator); if (!current_allocator) - g_slist_push_allocator (g_allocator_new ("GLib default GSList allocator", 1024)); - + { + GAllocator *allocator = g_allocator_new ("GLib default GSList allocator", + 1024); + g_slist_validate_allocator (allocator); + allocator->last = NULL; + current_allocator = allocator; + } if (!current_allocator->free_lists) { list = g_chunk_new (GSList, current_allocator->mem_chunk); @@ -103,6 +126,8 @@ g_slist_alloc (void) current_allocator->free_lists = list->next; } } + g_unlock (current_allocator); + list->next = NULL; return list; @@ -114,8 +139,10 @@ g_slist_free (GSList *list) if (list) { list->data = list->next; + g_lock (current_allocator); list->next = current_allocator->free_lists; current_allocator->free_lists = list; + g_unlock (current_allocator); } } @@ -125,8 +152,10 @@ g_slist_free_1 (GSList *list) if (list) { list->data = NULL; + g_lock (current_allocator); list->next = current_allocator->free_lists; current_allocator->free_lists = list; + g_unlock (current_allocator); } } diff --git a/glib/gstrfuncs.c b/glib/gstrfuncs.c index ad28978ee..e154c56dc 100644 --- a/glib/gstrfuncs.c +++ b/glib/gstrfuncs.c @@ -17,6 +17,10 @@ * Boston, MA 02111-1307, USA. */ +/* + * MT safe + */ + #ifdef HAVE_CONFIG_H #include #endif @@ -208,7 +212,8 @@ g_strtod (const gchar *nptr, gchar* g_strerror (gint errnum) { - static char msg[64]; + static GStaticPrivate msg_private = G_STATIC_PRIVATE_INIT; + char *msg; #ifdef HAVE_STRERROR return strerror (errnum); @@ -634,7 +639,14 @@ g_strerror (gint errnum) if ((errnum > 0) && (errnum <= sys_nerr)) return sys_errlist [errnum]; #endif /* NO_SYS_ERRLIST */ - + + msg = g_static_private_get (&msg_private); + if( !msg ) + { + msg = g_new( gchar, 64 ); + g_static_private_set (&msg_private, msg, g_free); + } + sprintf (msg, "unknown error (%d)", errnum); return msg; } @@ -642,7 +654,8 @@ g_strerror (gint errnum) gchar* g_strsignal (gint signum) { - static char msg[64]; + static GStaticPrivate msg_private = G_STATIC_PRIVATE_INIT; + char *msg; #ifdef HAVE_STRSIGNAL extern char *strsignal (int sig); @@ -748,6 +761,13 @@ g_strsignal (gint signum) extern char *sys_siglist[]; return sys_siglist [signum]; #endif /* NO_SYS_SIGLIST */ + + msg = g_static_private_get (&msg_private); + if( !msg ) + { + msg = g_new( gchar, 64 ); + g_static_private_set (&msg_private, msg, g_free); + } sprintf (msg, "unknown signal (%d)", signum); return msg; diff --git a/glib/gstring.c b/glib/gstring.c index fa84fe7a2..312a54060 100644 --- a/glib/gstring.c +++ b/glib/gstring.c @@ -16,6 +16,11 @@ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ + +/* + * MT safe + */ + #include #include #include @@ -43,7 +48,7 @@ struct _GRealString gint alloc; }; - +static G_LOCK_DEFINE(string_mem_chunk); static GMemChunk *string_mem_chunk = NULL; /* Hash Functions. @@ -202,12 +207,14 @@ g_string_sized_new (guint dfl_size) { GRealString *string; + g_lock (string_mem_chunk); if (!string_mem_chunk) string_mem_chunk = g_mem_chunk_new ("string mem chunk", sizeof (GRealString), 1024, G_ALLOC_AND_FREE); string = g_chunk_new (GRealString, string_mem_chunk); + g_unlock (string_mem_chunk); string->alloc = 0; string->len = 0; @@ -241,7 +248,9 @@ g_string_free (GString *string, if (free_segment) g_free (string->str); + g_lock (string_mem_chunk); g_mem_chunk_free (string_mem_chunk, string); + g_unlock (string_mem_chunk); } GString* diff --git a/glib/gtimer.c b/glib/gtimer.c index 6e58fa0bd..0b6e86a8a 100644 --- a/glib/gtimer.c +++ b/glib/gtimer.c @@ -17,6 +17,10 @@ * Boston, MA 02111-1307, USA. */ +/* + * MT safe + */ + #ifdef HAVE_CONFIG_H #include #endif diff --git a/glib/gtree.c b/glib/gtree.c index 4d9e98a0b..006f15db7 100644 --- a/glib/gtree.c +++ b/glib/gtree.c @@ -16,6 +16,11 @@ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ + +/* + * MT safe + */ + #include "glib.h" @@ -78,6 +83,7 @@ static GTreeNode* g_tree_node_rotate_right (GTreeNode *node); static void g_tree_node_check (GTreeNode *node); +static G_LOCK_DEFINE(g_tree_global); static GMemChunk *node_mem_chunk = NULL; static GTreeNode *node_free_list = NULL; @@ -88,6 +94,7 @@ g_tree_node_new (gpointer key, { GTreeNode *node; + g_lock (g_tree_global); if (node_free_list) { node = node_free_list; @@ -102,7 +109,8 @@ g_tree_node_new (gpointer key, G_ALLOC_ONLY); node = g_chunk_new (GTreeNode, node_mem_chunk); - } + } + g_unlock (g_tree_global); node->balance = 0; node->left = NULL; @@ -120,9 +128,11 @@ g_tree_node_destroy (GTreeNode *node) { g_tree_node_destroy (node->right); g_tree_node_destroy (node->left); + g_lock (g_tree_global); node->right = node_free_list; node_free_list = node; - } + g_unlock (g_tree_global); + } } @@ -375,9 +385,11 @@ g_tree_node_remove (GTreeNode *node, node = g_tree_node_restore_right_balance (new_root, old_balance); } + g_lock (g_tree_global); garbage->right = node_free_list; node_free_list = garbage; - } + g_unlock (g_tree_global); + } else if (cmp < 0) { if (node->left) diff --git a/glib/gutils.c b/glib/gutils.c index cc6594937..9a91199b6 100644 --- a/glib/gutils.c +++ b/glib/gutils.c @@ -17,6 +17,10 @@ * Boston, MA 02111-1307, USA. */ +/* + * MT safe for the unix part, FIXME: make the win32 part MT safe as well. + */ + #ifdef HAVE_CONFIG_H #include #endif @@ -367,11 +371,14 @@ g_getenv (const gchar *variable) #endif } +static G_LOCK_DEFINE(g_utils_global); + static gchar *g_tmp_dir = NULL; static gchar *g_user_name = NULL; static gchar *g_real_name = NULL; static gchar *g_home_dir = NULL; +/* HOLDS: g_utils_global_lock */ static void g_get_any_init (void) { @@ -442,14 +449,16 @@ g_get_any_init (void) g_home_dir = NULL; # endif /* !NATIVE_WIN32 */ #endif /* !HAVE_PWD_H */ - } + } } gchar* g_get_user_name (void) { + g_lock (g_utils_global); if (!g_tmp_dir) g_get_any_init (); + g_unlock (g_utils_global); return g_user_name; } @@ -457,9 +466,11 @@ g_get_user_name (void) gchar* g_get_real_name (void) { + g_lock (g_utils_global); if (!g_tmp_dir) g_get_any_init (); - + g_unlock (g_utils_global); + return g_real_name; } @@ -472,8 +483,10 @@ g_get_real_name (void) gchar* g_get_home_dir (void) { + g_lock (g_utils_global); if (!g_tmp_dir) g_get_any_init (); + g_unlock (g_utils_global); return g_home_dir; } @@ -488,8 +501,10 @@ g_get_home_dir (void) gchar* g_get_tmp_dir (void) { + g_lock (g_utils_global); if (!g_tmp_dir) g_get_any_init (); + g_unlock (g_utils_global); return g_tmp_dir; } @@ -499,16 +514,25 @@ static gchar *g_prgname = NULL; gchar* g_get_prgname (void) { - return g_prgname; + gchar* retval; + + g_lock (g_utils_global); + retval = g_prgname; + g_unlock (g_utils_global); + + return retval; } void g_set_prgname (const gchar *prgname) { - gchar *c = g_prgname; - + gchar *c; + + g_lock (g_utils_global); + c = g_prgname; g_prgname = g_strdup (prgname); g_free (c); + g_unlock (g_utils_global); } guint diff --git a/glist.c b/glist.c index 41a09dd18..e74dee872 100644 --- a/glist.c +++ b/glist.c @@ -16,6 +16,11 @@ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ + +/* + * MT safe + */ + #include "glib.h" @@ -31,9 +36,11 @@ struct _GAllocator /* from gmem.c */ }; static GAllocator *current_allocator = NULL; +static G_LOCK_DEFINE(current_allocator); -void -g_list_push_allocator (GAllocator *allocator) +/* HOLDS: current_allocator_lock */ +static void +g_list_validate_allocator (GAllocator *allocator) { g_return_if_fail (allocator != NULL); g_return_if_fail (allocator->is_unused == TRUE); @@ -58,13 +65,22 @@ g_list_push_allocator (GAllocator *allocator) } allocator->is_unused = FALSE; +} + +void +g_list_push_allocator(GAllocator *allocator) +{ + g_list_validate_allocator ( allocator ); + g_lock (current_allocator); allocator->last = current_allocator; current_allocator = allocator; + g_unlock (current_allocator); } void g_list_pop_allocator (void) { + g_lock (current_allocator); if (current_allocator) { GAllocator *allocator; @@ -74,6 +90,7 @@ g_list_pop_allocator (void) allocator->last = NULL; allocator->is_unused = TRUE; } + g_unlock (current_allocator); } GList* @@ -81,9 +98,15 @@ g_list_alloc (void) { GList *list; + g_lock (current_allocator); if (!current_allocator) - g_list_push_allocator (g_allocator_new ("GLib default GList allocator", 1024)); - + { + GAllocator *allocator = g_allocator_new ("GLib default GList allocator", + 1024); + g_list_validate_allocator (allocator); + allocator->last = NULL; + current_allocator = allocator; + } if (!current_allocator->free_lists) { list = g_chunk_new (GList, current_allocator->mem_chunk); @@ -103,6 +126,7 @@ g_list_alloc (void) current_allocator->free_lists = list->next; } } + g_unlock (current_allocator); list->next = NULL; list->prev = NULL; @@ -112,23 +136,31 @@ g_list_alloc (void) void g_list_free (GList *list) { +#if 0 if (list) { - list->data = list->next; + list->data = list->next; + g_lock (current_allocator); list->next = current_allocator->free_lists; current_allocator->free_lists = list; + g_unlock (current_allocator); } +#endif } void g_list_free_1 (GList *list) { +#if 0 if (list) { - list->data = NULL; + list->data = NULL; + g_lock (current_allocator); list->next = current_allocator->free_lists; current_allocator->free_lists = list; + g_unlock (current_allocator); } +#endif } GList* diff --git a/gmain.c b/gmain.c index 1f13e9097..5d3ae8d46 100644 --- a/gmain.c +++ b/gmain.c @@ -20,9 +20,14 @@ * Boston, MA 02111-1307, USA. */ +/* + * MT safe + */ + #include "glib.h" #include #include +#include #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 (¤t_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 (¤t_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 (¤t_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; @@ -538,13 +633,29 @@ g_main_poll (gint timeout, gboolean use_priority, gint priority) void g_main_poll_add (gint priority, GPollFD *fd) +{ + g_lock (main_loop); + g_main_poll_add_unlocked (priority, fd); + g_unlock (main_loop); +} + +static void +g_main_poll_add_unlocked (gint priority, + GPollFD *fd) { GPollRec *lastrec, *pollrec, *newrec; if (!poll_chunk) poll_chunk = g_mem_chunk_create (GPollRec, 32, G_ALLOC_ONLY); - newrec = g_chunk_new (GPollRec, poll_chunk); + if (poll_free_list) + { + newrec = poll_free_list; + poll_free_list = newrec->next; + } + else + newrec = g_chunk_new (GPollRec, poll_chunk); + newrec->fd = fd; newrec->priority = priority; @@ -564,6 +675,8 @@ g_main_poll_add (gint priority, newrec->next = pollrec; n_poll_records++; + + g_unlock (main_loop); } void @@ -571,6 +684,8 @@ g_main_poll_remove (GPollFD *fd) { GPollRec *pollrec, *lastrec; + g_lock (main_loop); + lastrec = NULL; pollrec = poll_records; @@ -585,12 +700,15 @@ g_main_poll_remove (GPollFD *fd) pollrec->next = poll_free_list; poll_free_list = pollrec; + + n_poll_records--; + break; } lastrec = pollrec; pollrec = pollrec->next; } - n_poll_records--; + g_unlock (main_loop); } void diff --git a/gmem.c b/gmem.c index c29ee660f..a4907ffca 100644 --- a/gmem.c +++ b/gmem.c @@ -17,6 +17,10 @@ * Boston, MA 02111-1307, USA. */ +/* + * MT safe + */ + #ifdef HAVE_CONFIG_H #include #endif @@ -48,8 +52,12 @@ */ #if defined(ENABLE_MEM_PROFILE) && defined(ENABLE_MEM_PROFILE_EXCLUDES_MEM_CHUNKS) -#define ENTER_MEM_CHUNK_ROUTINE() allocating_for_mem_chunk++ -#define LEAVE_MEM_CHUNK_ROUTINE() allocating_for_mem_chunk-- +#define ENTER_MEM_CHUNK_ROUTINE() \ + g_static_set (allocating_for_mem_chunk, \ + g_static_get (allocating_for_mem_chunk) + 1) +#define ENTER_MEM_CHUNK_ROUTINE() \ + g_static_set (allocating_for_mem_chunk, \ + g_static_get (allocating_for_mem_chunk) - 1) #else #define ENTER_MEM_CHUNK_ROUTINE() #define LEAVE_MEM_CHUNK_ROUTINE() @@ -117,13 +125,19 @@ static gint g_mem_chunk_area_search (GMemArea *a, gchar *addr); +/* here we can't use StaticMutexes, as they depend upon a working + * g_malloc, the same holds true for StaticPrivate */ +static GMutex* mem_chunks_lock = NULL; static GRealMemChunk *mem_chunks = NULL; #ifdef ENABLE_MEM_PROFILE +static GMutex* mem_profile_lock; static gulong allocations[MEM_PROFILE_TABLE_SIZE] = { 0 }; static gulong allocated_mem = 0; static gulong freed_mem = 0; -static gint allocating_for_mem_chunk = 0; +static GPrivate* allocating_for_mem_chunk = NULL; +#define IS_IN_MEM_CHUNK_ROUTINE() \ + GPOINTER_TO_UINT (g_static_get (allocating_for_mem_chunk)) #endif /* ENABLE_MEM_PROFILE */ @@ -174,8 +188,9 @@ g_malloc (gulong size) *t = size; #ifdef ENABLE_MEM_PROFILE + g_mutex_lock (mem_profile_lock); # ifdef ENABLE_MEM_PROFILE_EXCLUDES_MEM_CHUNKS - if(!allocating_for_mem_chunk) { + if(!IS_IN_MEM_CHUNK_ROUTINE()) { # endif if (size <= MEM_PROFILE_TABLE_SIZE - 1) allocations[size-1] += 1; @@ -185,6 +200,7 @@ g_malloc (gulong size) # ifdef ENABLE_MEM_PROFILE_EXCLUDES_MEM_CHUNKS } # endif + g_mutex_unlock (mem_profile_lock); #endif /* ENABLE_MEM_PROFILE */ #endif /* ENABLE_MEM_PROFILE || ENABLE_MEM_CHECK */ @@ -237,8 +253,9 @@ g_malloc0 (gulong size) *t = size; # ifdef ENABLE_MEM_PROFILE + g_mutex_lock (mem_profile_lock); # ifdef ENABLE_MEM_PROFILE_EXCLUDES_MEM_CHUNKS - if(!allocating_for_mem_chunk) { + if(!IS_IN_MEM_CHUNK_ROUTINE()) { # endif if (size <= (MEM_PROFILE_TABLE_SIZE - 1)) allocations[size-1] += 1; @@ -248,8 +265,9 @@ g_malloc0 (gulong size) # ifdef ENABLE_MEM_PROFILE_EXCLUDES_MEM_CHUNKS } # endif + g_mutex_unlock (mem_profile_lock); # endif /* ENABLE_MEM_PROFILE */ -#endif /* ENABLE_MEM_PROFILE */ +#endif /* ENABLE_MEM_PROFILE || ENABLE_MEM_CHECK */ return p; @@ -286,7 +304,9 @@ g_realloc (gpointer mem, #if defined(ENABLE_MEM_PROFILE) || defined(ENABLE_MEM_CHECK) t = (gulong*) ((guchar*) mem - SIZEOF_LONG); #ifdef ENABLE_MEM_PROFILE + g_mutex_lock (mem_profile); freed_mem += *t; + g_mutex_unlock (mem_profile); #endif /* ENABLE_MEM_PROFILE */ mem = t; #endif /* ENABLE_MEM_PROFILE || ENABLE_MEM_CHECK */ @@ -321,8 +341,9 @@ g_realloc (gpointer mem, *t = size; #ifdef ENABLE_MEM_PROFILE + g_mutex_lock (mem_profile_lock); #ifdef ENABLE_MEM_PROFILE_EXCLUDES_MEM_CHUNKS - if(!allocating_for_mem_chunk) { + if(!IS_IN_MEM_CHUNK_ROUTINE()) { #endif if (size <= (MEM_PROFILE_TABLE_SIZE - 1)) allocations[size-1] += 1; @@ -332,6 +353,7 @@ g_realloc (gpointer mem, #ifdef ENABLE_MEM_PROFILE_EXCLUDES_MEM_CHUNKS } #endif + g_mutex_unlock (mem_profile_lock); #endif /* ENABLE_MEM_PROFILE */ #endif /* ENABLE_MEM_PROFILE || ENABLE_MEM_CHECK */ @@ -352,8 +374,10 @@ g_free (gpointer mem) #if defined(ENABLE_MEM_PROFILE) || defined(ENABLE_MEM_CHECK) t = (gulong*) ((guchar*) mem - SIZEOF_LONG); size = *t; -#ifdef ENABLE_MEM_PROFILE +#ifdef ENABLE_MEM_PROFILE + g_mutex_lock (mem_profile); freed_mem += size; + g_mutex_unlock (mem_profile); #endif /* ENABLE_MEM_PROFILE */ mem = t; #endif /* ENABLE_MEM_PROFILE || ENABLE_MEM_CHECK */ @@ -380,19 +404,29 @@ g_mem_profile (void) { #ifdef ENABLE_MEM_PROFILE gint i; - + gulong local_allocations[MEM_PROFILE_TABLE_SIZE]; + gulong local_allocated_mem; + gulong local_freed_mem; + + g_mutex_lock (mem_profile); for (i = 0; i < (MEM_PROFILE_TABLE_SIZE - 1); i++) - if (allocations[i] > 0) + 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 (local_allocations[i] > 0) g_log (g_log_domain_glib, G_LOG_LEVEL_INFO, - "%lu allocations of %d bytes\n", allocations[i], i + 1); + "%lu allocations of %d bytes\n", local_allocations[i], i + 1); - if (allocations[MEM_PROFILE_TABLE_SIZE - 1] > 0) + if (local_allocations[MEM_PROFILE_TABLE_SIZE - 1] > 0) g_log (g_log_domain_glib, G_LOG_LEVEL_INFO, "%lu allocations of greater than %d bytes\n", - allocations[MEM_PROFILE_TABLE_SIZE - 1], MEM_PROFILE_TABLE_SIZE - 1); - g_log (g_log_domain_glib, G_LOG_LEVEL_INFO, "%lu bytes allocated\n", allocated_mem); - g_log (g_log_domain_glib, G_LOG_LEVEL_INFO, "%lu bytes freed\n", freed_mem); - g_log (g_log_domain_glib, G_LOG_LEVEL_INFO, "%lu bytes in use\n", allocated_mem - freed_mem); + local_allocations[MEM_PROFILE_TABLE_SIZE - 1], MEM_PROFILE_TABLE_SIZE - 1); + g_log (g_log_domain_glib, G_LOG_LEVEL_INFO, "%lu bytes allocated\n", local_allocated_mem); + g_log (g_log_domain_glib, G_LOG_LEVEL_INFO, "%lu bytes freed\n", local_freed_mem); + g_log (g_log_domain_glib, G_LOG_LEVEL_INFO, "%lu bytes in use\n", local_allocated_mem - local_freed_mem); #endif /* ENABLE_MEM_PROFILE */ } @@ -460,11 +494,13 @@ g_mem_chunk_new (gchar *name, mem_chunk->area_size += mem_chunk->atom_size - (mem_chunk->area_size % mem_chunk->atom_size); */ + g_mutex_lock (mem_chunks_lock); mem_chunk->next = mem_chunks; mem_chunk->prev = NULL; if (mem_chunks) mem_chunks->prev = mem_chunk; mem_chunks = mem_chunk; + g_mutex_unlock (mem_chunks_lock); LEAVE_MEM_CHUNK_ROUTINE(); @@ -497,8 +533,10 @@ g_mem_chunk_destroy (GMemChunk *mem_chunk) if (rmem_chunk->prev) rmem_chunk->prev->next = rmem_chunk->next; + g_mutex_lock (mem_chunks_lock); if (rmem_chunk == mem_chunks) mem_chunks = mem_chunks->next; + g_mutex_unlock (mem_chunks_lock); if (rmem_chunk->type == G_ALLOC_AND_FREE) g_tree_destroy (rmem_chunk->mem_tree); @@ -826,21 +864,26 @@ g_mem_chunk_info (void) gint count; count = 0; + g_mutex_lock (mem_chunks_lock); mem_chunk = mem_chunks; while (mem_chunk) { count += 1; mem_chunk = mem_chunk->next; } + g_mutex_unlock (mem_chunks_lock); g_log (g_log_domain_glib, G_LOG_LEVEL_INFO, "%d mem chunks\n", count); + g_mutex_lock (mem_chunks_lock); mem_chunk = mem_chunks; + g_mutex_unlock (mem_chunks_lock); + while (mem_chunk) { g_mem_chunk_print ((GMemChunk*) mem_chunk); mem_chunk = mem_chunk->next; - } + } } void @@ -848,7 +891,9 @@ g_blow_chunks (void) { GRealMemChunk *mem_chunk; + g_mutex_lock (mem_chunks_lock); mem_chunk = mem_chunks; + g_mutex_unlock (mem_chunks_lock); while (mem_chunk) { g_mem_chunk_clean ((GMemChunk*) mem_chunk); @@ -940,3 +985,13 @@ g_allocator_free (GAllocator *allocator) g_free (allocator); } + +void +g_mem_init (void) +{ + mem_chunks_lock = g_mutex_new(); +#ifdef ENABLE_MEM_PROFILE + mem_profile_lock = g_mutex_new(); + allocating_for_mem_chunk = g_private_new(NULL); +#endif +} diff --git a/gmessages.c b/gmessages.c index e0c6eacb1..eb8aed7a8 100644 --- a/gmessages.c +++ b/gmessages.c @@ -17,6 +17,10 @@ * Boston, MA 02111-1307, USA. */ +/* + * MT safe + */ + #ifdef HAVE_CONFIG_H #include #endif @@ -31,7 +35,7 @@ #endif #ifdef NATIVE_WIN32 -/* Just use stdio. If we're out of memroy, we're hosed anyway. */ +/* Just use stdio. If we're out of memory, we're hosed anyway. */ #undef write static inline int @@ -67,6 +71,9 @@ struct _GLogHandler /* --- variables --- */ + +static GMutex* g_messages_lock = NULL; + const gchar *g_log_domain_glib = "GLib"; static GLogDomain *g_log_domains = NULL; static GLogLevelFlags g_log_always_fatal = G_LOG_FATAL_MASK; @@ -76,20 +83,27 @@ static GErrorFunc glib_error_func = NULL; static GWarningFunc glib_warning_func = NULL; static GPrintFunc glib_message_func = NULL; +static GPrivate* g_log_depth = NULL; + /* --- functions --- */ static inline GLogDomain* g_log_find_domain (const gchar *log_domain) { register GLogDomain *domain; - + + g_mutex_lock (g_messages_lock); domain = g_log_domains; while (domain) { if (strcmp (domain->log_domain, log_domain) == 0) - return domain; + { + g_mutex_unlock (g_messages_lock); + return domain; + } domain = domain->next; } + g_mutex_unlock (g_messages_lock); return NULL; } @@ -102,8 +116,11 @@ g_log_domain_new (const gchar *log_domain) domain->log_domain = g_strdup (log_domain); domain->fatal_mask = G_LOG_FATAL_MASK; domain->handlers = NULL; + + g_mutex_lock (g_messages_lock); domain->next = g_log_domains; g_log_domains = domain; + g_mutex_unlock (g_messages_lock); return domain; } @@ -116,7 +133,9 @@ g_log_domain_check_free (GLogDomain *domain) { register GLogDomain *last, *work; - last = NULL; + last = NULL; + + g_mutex_lock (g_messages_lock); work = g_log_domains; while (work) { @@ -131,7 +150,8 @@ g_log_domain_check_free (GLogDomain *domain) break; } work = work->next; - } + } + g_mutex_unlock (g_messages_lock); } } @@ -170,8 +190,10 @@ g_log_set_always_fatal (GLogLevelFlags fatal_mask) /* remove bogus flag */ fatal_mask &= ~G_LOG_FLAG_FATAL; + g_mutex_lock (g_messages_lock); old_mask = g_log_always_fatal; g_log_always_fatal = fatal_mask; + g_mutex_unlock (g_messages_lock); return old_mask; } @@ -223,7 +245,9 @@ g_log_set_handler (const gchar *log_domain, domain = g_log_domain_new (log_domain); handler = g_new (GLogHandler, 1); + g_mutex_lock (g_messages_lock); handler->id = ++handler_id; + g_mutex_unlock (g_messages_lock); handler->log_level = log_levels; handler->log_func = log_func; handler->data = user_data; @@ -311,19 +335,25 @@ g_logv (const gchar *log_domain, test_level = 1 << i; if (log_level & test_level) { - static guint g_log_depth = 0; + guint depth = GPOINTER_TO_UINT (g_private_get (g_log_depth)); GLogDomain *domain; GLogFunc log_func; gpointer data = NULL; domain = g_log_find_domain (log_domain ? log_domain : ""); - if (g_log_depth++) + if (depth) test_level |= G_LOG_FLAG_RECURSION; - if ((((domain ? domain->fatal_mask : G_LOG_FATAL_MASK) | g_log_always_fatal) & - test_level) != 0) - test_level |= G_LOG_FLAG_FATAL; + depth++; + g_private_set (g_log_depth, GUINT_TO_POINTER (depth)); + + g_mutex_lock (g_messages_lock); + if ((((domain ? domain->fatal_mask : G_LOG_FATAL_MASK) | + g_log_always_fatal) & test_level) != 0) + test_level |= G_LOG_FLAG_FATAL; + g_mutex_unlock (g_messages_lock); + log_func = g_log_domain_get_handler (domain, test_level, &data); log_func (log_domain, test_level, buffer, data); @@ -332,7 +362,8 @@ g_logv (const gchar *log_domain, if (test_level & G_LOG_FLAG_FATAL) abort (); - g_log_depth--; + depth--; + g_private_set (g_log_depth, GUINT_TO_POINTER (depth)); } } } @@ -362,8 +393,11 @@ g_log_default_handler (const gchar *log_domain, gint fd; #endif gboolean in_recursion; - gboolean is_fatal; - + gboolean is_fatal; + GErrorFunc local_glib_error_func; + GWarningFunc local_glib_warning_func; + GPrintFunc local_glib_message_func; + in_recursion = (log_level & G_LOG_FLAG_RECURSION) != 0; is_fatal = (log_level & G_LOG_FLAG_FATAL) != 0; log_level &= G_LOG_LEVEL_MASK; @@ -380,13 +414,19 @@ g_log_default_handler (const gchar *log_domain, fd = (log_level >= G_LOG_LEVEL_MESSAGE) ? 1 : 2; #endif + g_mutex_lock (g_messages_lock); + local_glib_error_func = glib_error_func; + local_glib_warning_func = glib_warning_func; + local_glib_message_func = glib_message_func; + g_mutex_unlock (g_messages_lock); + switch (log_level) { case G_LOG_LEVEL_ERROR: - if (!log_domain && glib_error_func) + if (!log_domain && local_glib_error_func) { /* compatibility code */ - glib_error_func (message); + local_glib_error_func (message); return; } /* use write(2) for output, in case we are out of memeory */ @@ -428,10 +468,10 @@ g_log_default_handler (const gchar *log_domain, write (fd, "\n", 1); break; case G_LOG_LEVEL_WARNING: - if (!log_domain && glib_warning_func) + if (!log_domain && local_glib_warning_func) { /* compatibility code */ - glib_warning_func (message); + local_glib_warning_func (message); return; } if (log_domain) @@ -453,10 +493,10 @@ g_log_default_handler (const gchar *log_domain, write (fd, "\n", 1); break; case G_LOG_LEVEL_MESSAGE: - if (!log_domain && glib_message_func) + if (!log_domain && local_glib_message_func) { /* compatibility code */ - glib_message_func (message); + local_glib_message_func (message); return; } if (log_domain) @@ -553,8 +593,10 @@ g_set_print_handler (GPrintFunc func) { GPrintFunc old_print_func; + g_mutex_lock (g_messages_lock); old_print_func = glib_print_func; glib_print_func = func; + g_mutex_unlock (g_messages_lock); return old_print_func; } @@ -565,6 +607,7 @@ g_print (const gchar *format, { va_list args; gchar *string; + GPrintFunc local_glib_print_func; g_return_if_fail (format != NULL); @@ -572,8 +615,12 @@ g_print (const gchar *format, string = g_strdup_vprintf (format, args); va_end (args); - if (glib_print_func) - glib_print_func (string); + g_mutex_lock (g_messages_lock); + local_glib_print_func = glib_print_func; + g_mutex_unlock (g_messages_lock); + + if (local_glib_print_func) + local_glib_print_func (string); else { fputs (string, stdout); @@ -587,8 +634,10 @@ g_set_printerr_handler (GPrintFunc func) { GPrintFunc old_printerr_func; + g_mutex_lock (g_messages_lock); old_printerr_func = glib_printerr_func; glib_printerr_func = func; + g_mutex_unlock (g_messages_lock); return old_printerr_func; } @@ -599,6 +648,7 @@ g_printerr (const gchar *format, { va_list args; gchar *string; + GPrintFunc local_glib_printerr_func; g_return_if_fail (format != NULL); @@ -606,8 +656,12 @@ g_printerr (const gchar *format, string = g_strdup_vprintf (format, args); va_end (args); - if (glib_printerr_func) - glib_printerr_func (string); + g_mutex_lock (g_messages_lock); + local_glib_printerr_func = glib_printerr_func; + g_mutex_unlock (g_messages_lock); + + if (local_glib_printerr_func) + local_glib_printerr_func (string); else { fputs (string, stderr); @@ -622,9 +676,11 @@ g_set_error_handler (GErrorFunc func) { GErrorFunc old_error_func; + g_mutex_lock (g_messages_lock); old_error_func = glib_error_func; glib_error_func = func; - + g_mutex_unlock (g_messages_lock); + return old_error_func; } @@ -634,8 +690,10 @@ g_set_warning_handler (GWarningFunc func) { GWarningFunc old_warning_func; + g_mutex_lock (g_messages_lock); old_warning_func = glib_warning_func; glib_warning_func = func; + g_mutex_unlock (g_messages_lock); return old_warning_func; } @@ -646,8 +704,17 @@ g_set_message_handler (GPrintFunc func) { GPrintFunc old_message_func; + g_mutex_lock (g_messages_lock); old_message_func = glib_message_func; glib_message_func = func; + g_mutex_unlock (g_messages_lock); return old_message_func; } + +void +g_messages_init (void) +{ + g_messages_lock = g_mutex_new(); + g_log_depth = g_private_new(NULL); +} diff --git a/gmodule/ChangeLog b/gmodule/ChangeLog index 4de434321..86dd222ae 100644 --- a/gmodule/ChangeLog +++ b/gmodule/ChangeLog @@ -1,3 +1,8 @@ +1998-12-10 Sebastian Wilhelmi + + * gmodule.c: Made it MT safe, the g_module_error() is now thread + specific. + Fri Nov 20 14:43:44 1998 Tim Janik * gmodule.c (_g_module_build_path): added empty default imlementation diff --git a/gmodule/gmodule-dl.c b/gmodule/gmodule-dl.c index 034e94bf0..4a5686616 100644 --- a/gmodule/gmodule-dl.c +++ b/gmodule/gmodule-dl.c @@ -16,6 +16,11 @@ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ + +/* + * MT safe + */ + #include /* Perl includes and instead of on some systmes? */ diff --git a/gmodule/gmodule-dld.c b/gmodule/gmodule-dld.c index b1d68d7d3..53b269b48 100644 --- a/gmodule/gmodule-dld.c +++ b/gmodule/gmodule-dld.c @@ -16,6 +16,11 @@ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ + +/* + * MT safe + */ + #include diff --git a/gmodule/gmodule-win32.c b/gmodule/gmodule-win32.c index 0cc1bacc3..98643ad23 100644 --- a/gmodule/gmodule-win32.c +++ b/gmodule/gmodule-win32.c @@ -17,6 +17,11 @@ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ + +/* + * MT safe + */ + #include #include diff --git a/gmodule/gmodule.c b/gmodule/gmodule.c index 9efa3f51b..71f614570 100644 --- a/gmodule/gmodule.c +++ b/gmodule/gmodule.c @@ -16,6 +16,11 @@ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ + +/* + * MT safe + */ + #include "gmodule.h" #include "gmoduleconf.h" #include @@ -59,10 +64,11 @@ static inline GModule* g_module_find_by_name (const gchar *name); /* --- variables --- */ -const char *g_log_domain_gmodule = "GModule"; -static GModule *modules = NULL; -static GModule *main_module = NULL; -static gchar *module_error = NULL; +static G_LOCK_DEFINE (g_module_global); +const char *g_log_domain_gmodule = "GModule"; +static GModule *modules = NULL; +static GModule *main_module = NULL; +static GStaticPrivate module_error_private = G_STATIC_PRIVATE_INIT; /* --- inline functions --- */ @@ -70,30 +76,45 @@ static inline GModule* g_module_find_by_handle (gpointer handle) { GModule *module; + GModule *retval = NULL; + g_lock (g_module_global); if (main_module && main_module->handle == handle) - return main_module; - - for (module = modules; module; module = module->next) - if (handle == module->handle) - return module; - return NULL; + retval = main_module; + else + for (module = modules; module; module = module->next) + if (handle == module->handle) + { + retval = module; + break; + } + g_unlock (g_module_global); + + return retval; } static inline GModule* g_module_find_by_name (const gchar *name) { GModule *module; + GModule *retval = NULL; + g_lock (g_module_global); for (module = modules; module; module = module->next) if (strcmp (name, module->file_name) == 0) - return module; - return NULL; + { + retval = module; + break; + } + g_unlock (g_module_global); + + return retval; } static inline void g_module_set_error (const gchar *error) { + gchar* module_error = g_static_private_get (&module_error_private); if (module_error) g_free (module_error); if (error) @@ -101,6 +122,7 @@ g_module_set_error (const gchar *error) else module_error = NULL; errno = 0; + g_static_private_set (&module_error_private, module_error, g_free); } @@ -175,7 +197,8 @@ g_module_open (const gchar *file_name, CHECK_ERROR (NULL); if (!file_name) - { + { + g_lock (g_module_global); if (!main_module) { handle = _g_module_self (); @@ -190,7 +213,8 @@ g_module_open (const gchar *file_name, main_module->next = NULL; } } - + g_unlock (g_module_global); + return main_module; } @@ -222,8 +246,8 @@ g_module_open (const gchar *file_name, return module; } - saved_error = module_error; - module_error = NULL; + saved_error = g_module_error(); + g_static_private_set (&module_error_private, NULL, NULL); g_module_set_error (NULL); module = g_new (GModule, 1); @@ -232,8 +256,10 @@ g_module_open (const gchar *file_name, module->ref_count = 1; module->is_resident = FALSE; module->unload = NULL; + g_lock (g_module_global); module->next = modules; modules = module; + g_unlock (g_module_global); /* check initialization */ if (g_module_symbol (module, "g_module_check_init", (gpointer) &check_init)) @@ -286,6 +312,8 @@ g_module_close (GModule *module) GModule *node; last = NULL; + + g_lock (g_module_global); node = modules; while (node) { @@ -301,6 +329,7 @@ g_module_close (GModule *module) node = last->next; } module->next = NULL; + g_unlock (g_module_global); _g_module_close (module->handle, FALSE); g_free (module->file_name); @@ -308,7 +337,7 @@ g_module_close (GModule *module) g_free (module); } - return module_error == NULL; + return g_module_error() == NULL; } void @@ -322,7 +351,7 @@ g_module_make_resident (GModule *module) gchar* g_module_error (void) { - return module_error; + return g_static_private_get (&module_error_private); } gboolean @@ -330,6 +359,7 @@ g_module_symbol (GModule *module, const gchar *symbol_name, gpointer *symbol) { + gchar *module_error; if (symbol) *symbol = NULL; CHECK_ERROR (FALSE); @@ -350,7 +380,7 @@ g_module_symbol (GModule *module, *symbol = _g_module_symbol (module->handle, symbol_name); #endif /* !G_MODULE_NEED_USCORE */ - if (module_error) + if ((module_error = g_module_error())) { gchar *error; diff --git a/gmutex.c b/gmutex.c new file mode 100644 index 000000000..b1d894799 --- /dev/null +++ b/gmutex.c @@ -0,0 +1,176 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * gmutex.c: MT safety related functions + * Copyright 1998 Sebastian Wilhelmi; University of Karlsruhe + * Owen Taylor + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * MT safe + */ + +#include "glib.h" + +typedef struct _GStaticPrivateNode GStaticPrivateNode; + +struct _GStaticPrivateNode { + gpointer data; + GDestroyNotify destroy; +}; + +static void g_static_private_free_data (gpointer data); +static void g_thread_fail (void); + +/* Global variables */ + +gboolean g_thread_use_default_impl = TRUE; +gboolean g_thread_supported = FALSE; + +GThreadFunctions g_thread_functions_for_glib_use = { + (GMutex*(*)())g_thread_fail, /* mutex_new */ + NULL, /* mutex_lock */ + NULL, /* mutex_trylock */ + NULL, /* mutex_unlock */ + NULL, /* mutex_free */ + (GCond*(*)())g_thread_fail, /* cond_new */ + NULL, /* cond_signal */ + NULL, /* cond_broadcast */ + NULL, /* cond_wait */ + NULL, /* cond_timed_wait */ + NULL, /* cond_free */ + (GPrivate*(*)(GDestroyNotify))g_thread_fail, /* private_new */ + NULL, /* private_get */ + NULL, /* private_set */ +}; + +/* Local data */ + +static GMutex *g_mutex_protect_static_mutex_allocation = NULL; +static GMutex *g_thread_specific_mutex = NULL; +static GPrivate *g_thread_specific_private = NULL; + +/* This must be called only once, before any threads are created. + * It will only be called from g_thread_init() in -lgthread. + */ +void +g_mutex_init (void) +{ + /* We let the main thread (the one that calls g_thread_init) inherit + the data, that it set before calling g_thread_init */ + gpointer private_old = g_thread_specific_private; + g_thread_specific_private = g_private_new (g_static_private_free_data); + + /* we can not use g_private_set here, as g_thread_supported is not + yet set TRUE, whereas the private_set function is already set. */ + g_thread_functions_for_glib_use.private_set (g_thread_specific_private, + private_old); + + g_mutex_protect_static_mutex_allocation = g_mutex_new(); + g_thread_specific_mutex = g_mutex_new(); +} + +GMutex * +g_static_mutex_get_mutex_impl (GMutex** mutex) +{ + if (!g_thread_supported) + return NULL; + + g_assert (g_mutex_protect_static_mutex_allocation); + + g_mutex_lock (g_mutex_protect_static_mutex_allocation); + + if (!(*mutex)) + *mutex = g_mutex_new(); + + g_mutex_unlock (g_mutex_protect_static_mutex_allocation); + + return *mutex; +} + +gpointer +g_static_private_get (GStaticPrivate *private) +{ + GArray *array; + + array = g_private_get (g_thread_specific_private); + if (!array) + return NULL; + + if (!private->index) + return NULL; + else if (private->index <= array->len) + return g_array_index (array, GStaticPrivateNode, (private->index - 1)).data; + else + return NULL; +} + +void +g_static_private_set (GStaticPrivate *private, + gpointer data, + GDestroyNotify notify) +{ + GArray *array; + static guint next_index = 0; + + array = g_private_get (g_thread_specific_private); + if (!array) + { + array = g_array_new (FALSE, FALSE, sizeof(GStaticPrivateNode)); + g_private_set (g_thread_specific_private, array); + } + + if (!private->index) + { + g_mutex_lock (g_thread_specific_mutex); + + if (!private->index) + private->index = ++next_index; + + g_mutex_unlock (g_thread_specific_mutex); + } + + if (private->index > array->len) + g_array_set_size (array, private->index); + + g_array_index (array, GStaticPrivateNode, (private->index - 1)).data = data; + g_array_index (array, GStaticPrivateNode, (private->index - 1)).destroy = notify; +} + +static void +g_static_private_free_data (gpointer data) +{ + if (data) + { + GArray* array = data; + guint i; + + for (i = 0; i < array->len; i++ ) + { + GStaticPrivateNode *node = &g_array_index (array, GStaticPrivateNode, i); + if (node->data && node->destroy) + node->destroy (node->data); + } + } +} + +static void +g_thread_fail (void) +{ + g_error ("The thread system is not yet initialized."); +} diff --git a/gnode.c b/gnode.c index 9f6e544ba..089a4996d 100644 --- a/gnode.c +++ b/gnode.c @@ -19,6 +19,11 @@ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ + +/* + * MT safe + */ + #include "glib.h" /* node allocation @@ -34,10 +39,12 @@ struct _GAllocator /* from gmem.c */ GNode *free_nodes; /* implementation specific */ }; +static G_LOCK_DEFINE(current_allocator); static GAllocator *current_allocator = NULL; -void -g_node_push_allocator (GAllocator *allocator) +/* HOLDS: current_allocator_lock */ +static void +g_node_validate_allocator (GAllocator *allocator) { g_return_if_fail (allocator != NULL); g_return_if_fail (allocator->is_unused == TRUE); @@ -62,13 +69,22 @@ g_node_push_allocator (GAllocator *allocator) } allocator->is_unused = FALSE; +} + +void +g_node_push_allocator (GAllocator *allocator) +{ + g_node_validate_allocator ( allocator ); + g_lock (current_allocator); allocator->last = current_allocator; current_allocator = allocator; + g_unlock (current_allocator); } void g_node_pop_allocator (void) { + g_lock (current_allocator); if (current_allocator) { GAllocator *allocator; @@ -78,6 +94,7 @@ g_node_pop_allocator (void) allocator->last = NULL; allocator->is_unused = TRUE; } + g_unlock (current_allocator); } @@ -87,9 +104,15 @@ g_node_new (gpointer data) { GNode *node; + g_lock (current_allocator); if (!current_allocator) - g_node_push_allocator (g_allocator_new ("GLib default GNode allocator", 1024)); - + { + GAllocator *allocator = g_allocator_new ("GLib default GNode allocator", + 1024); + g_node_validate_allocator (allocator); + allocator->last = NULL; + current_allocator = allocator; + } if (!current_allocator->free_nodes) node = g_chunk_new (GNode, current_allocator->mem_chunk); else @@ -97,6 +120,7 @@ g_node_new (gpointer data) node = current_allocator->free_nodes; current_allocator->free_nodes = node->next; } + g_unlock (current_allocator); node->data = data; node->next = NULL; @@ -122,9 +146,11 @@ g_nodes_free (GNode *node) else break; } - + + g_lock (current_allocator); parent->next = current_allocator->free_nodes; current_allocator->free_nodes = node; + g_unlock (current_allocator); } void diff --git a/gprimes.c b/gprimes.c index 3d45c1ef7..404ebd605 100644 --- a/gprimes.c +++ b/gprimes.c @@ -16,6 +16,11 @@ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ + +/* + * MT safe + */ + #include "glib.h" static const guint g_primes[] = diff --git a/grel.c b/grel.c index 5fdf88098..544da6bfc 100644 --- a/grel.c +++ b/grel.c @@ -15,6 +15,11 @@ * License along with this library; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* + * MT safe + */ + #include "glib.h" #include #include diff --git a/gscanner.c b/gscanner.c index 02985a7f7..c6fd0dd4e 100644 --- a/gscanner.c +++ b/gscanner.c @@ -19,6 +19,11 @@ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ + +/* + * MT safe + */ + #define __gscanner_c__ #ifdef HAVE_CONFIG_H diff --git a/gslist.c b/gslist.c index 4efe2a575..1ed517ff6 100644 --- a/gslist.c +++ b/gslist.c @@ -16,6 +16,11 @@ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ + +/* + * MT safe + */ + #include "glib.h" @@ -30,10 +35,12 @@ struct _GAllocator /* from gmem.c */ GSList *free_lists; /* implementation specific */ }; +static G_LOCK_DEFINE(current_allocator); static GAllocator *current_allocator = NULL; -void -g_slist_push_allocator (GAllocator *allocator) +/* HOLDS: current_allocator_lock */ +static void +g_slist_validate_allocator (GAllocator *allocator) { g_return_if_fail (allocator != NULL); g_return_if_fail (allocator->is_unused == TRUE); @@ -58,13 +65,22 @@ g_slist_push_allocator (GAllocator *allocator) } allocator->is_unused = FALSE; +} + +void +g_slist_push_allocator (GAllocator *allocator) +{ + g_slist_validate_allocator (allocator); + g_lock (current_allocator); allocator->last = current_allocator; current_allocator = allocator; + g_unlock (current_allocator); } void g_slist_pop_allocator (void) { + g_lock (current_allocator); if (current_allocator) { GAllocator *allocator; @@ -74,6 +90,7 @@ g_slist_pop_allocator (void) allocator->last = NULL; allocator->is_unused = TRUE; } + g_unlock (current_allocator); } GSList* @@ -81,9 +98,15 @@ g_slist_alloc (void) { GSList *list; + g_lock (current_allocator); if (!current_allocator) - g_slist_push_allocator (g_allocator_new ("GLib default GSList allocator", 1024)); - + { + GAllocator *allocator = g_allocator_new ("GLib default GSList allocator", + 1024); + g_slist_validate_allocator (allocator); + allocator->last = NULL; + current_allocator = allocator; + } if (!current_allocator->free_lists) { list = g_chunk_new (GSList, current_allocator->mem_chunk); @@ -103,6 +126,8 @@ g_slist_alloc (void) current_allocator->free_lists = list->next; } } + g_unlock (current_allocator); + list->next = NULL; return list; @@ -114,8 +139,10 @@ g_slist_free (GSList *list) if (list) { list->data = list->next; + g_lock (current_allocator); list->next = current_allocator->free_lists; current_allocator->free_lists = list; + g_unlock (current_allocator); } } @@ -125,8 +152,10 @@ g_slist_free_1 (GSList *list) if (list) { list->data = NULL; + g_lock (current_allocator); list->next = current_allocator->free_lists; current_allocator->free_lists = list; + g_unlock (current_allocator); } } diff --git a/gstrfuncs.c b/gstrfuncs.c index ad28978ee..e154c56dc 100644 --- a/gstrfuncs.c +++ b/gstrfuncs.c @@ -17,6 +17,10 @@ * Boston, MA 02111-1307, USA. */ +/* + * MT safe + */ + #ifdef HAVE_CONFIG_H #include #endif @@ -208,7 +212,8 @@ g_strtod (const gchar *nptr, gchar* g_strerror (gint errnum) { - static char msg[64]; + static GStaticPrivate msg_private = G_STATIC_PRIVATE_INIT; + char *msg; #ifdef HAVE_STRERROR return strerror (errnum); @@ -634,7 +639,14 @@ g_strerror (gint errnum) if ((errnum > 0) && (errnum <= sys_nerr)) return sys_errlist [errnum]; #endif /* NO_SYS_ERRLIST */ - + + msg = g_static_private_get (&msg_private); + if( !msg ) + { + msg = g_new( gchar, 64 ); + g_static_private_set (&msg_private, msg, g_free); + } + sprintf (msg, "unknown error (%d)", errnum); return msg; } @@ -642,7 +654,8 @@ g_strerror (gint errnum) gchar* g_strsignal (gint signum) { - static char msg[64]; + static GStaticPrivate msg_private = G_STATIC_PRIVATE_INIT; + char *msg; #ifdef HAVE_STRSIGNAL extern char *strsignal (int sig); @@ -748,6 +761,13 @@ g_strsignal (gint signum) extern char *sys_siglist[]; return sys_siglist [signum]; #endif /* NO_SYS_SIGLIST */ + + msg = g_static_private_get (&msg_private); + if( !msg ) + { + msg = g_new( gchar, 64 ); + g_static_private_set (&msg_private, msg, g_free); + } sprintf (msg, "unknown signal (%d)", signum); return msg; diff --git a/gstring.c b/gstring.c index fa84fe7a2..312a54060 100644 --- a/gstring.c +++ b/gstring.c @@ -16,6 +16,11 @@ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ + +/* + * MT safe + */ + #include #include #include @@ -43,7 +48,7 @@ struct _GRealString gint alloc; }; - +static G_LOCK_DEFINE(string_mem_chunk); static GMemChunk *string_mem_chunk = NULL; /* Hash Functions. @@ -202,12 +207,14 @@ g_string_sized_new (guint dfl_size) { GRealString *string; + g_lock (string_mem_chunk); if (!string_mem_chunk) string_mem_chunk = g_mem_chunk_new ("string mem chunk", sizeof (GRealString), 1024, G_ALLOC_AND_FREE); string = g_chunk_new (GRealString, string_mem_chunk); + g_unlock (string_mem_chunk); string->alloc = 0; string->len = 0; @@ -241,7 +248,9 @@ g_string_free (GString *string, if (free_segment) g_free (string->str); + g_lock (string_mem_chunk); g_mem_chunk_free (string_mem_chunk, string); + g_unlock (string_mem_chunk); } GString* diff --git a/gthread/.cvsignore b/gthread/.cvsignore new file mode 100644 index 000000000..ba4d80249 --- /dev/null +++ b/gthread/.cvsignore @@ -0,0 +1,8 @@ +Makefile.in +Makefile +.deps +*.lo +*.o +.libs +*.la +testgthread diff --git a/gthread/Makefile.am b/gthread/Makefile.am new file mode 100644 index 000000000..3b7bc9748 --- /dev/null +++ b/gthread/Makefile.am @@ -0,0 +1,21 @@ +## Process this file with automake to produce Makefile.in + +INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/gthread -DG_LOG_DOMAIN=g_log_domain_gthread + +EXTRA_DIST = \ + gthread-posix.c + +libglib = $(top_builddir)/libglib.la # -lglib + +lib_LTLIBRARIES = libgthread.la + +libgthread_la_SOURCES = gthread.c +libgthread_la_LDFLAGS = \ + -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) \ + -release $(LT_RELEASE) + +libgthread_la_LIBADD = \ + @G_THREAD_LIBS@ + +noinst_PROGRAMS = testgthread +testgthread_LDADD = ../libglib.la libgthread.la diff --git a/gthread/gthread-none.c b/gthread/gthread-none.c new file mode 100644 index 000000000..1240fd580 --- /dev/null +++ b/gthread/gthread-none.c @@ -0,0 +1,28 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * gthread.c: fallback thread system implementation + * Copyright 1998 Sebastian Wilhelmi; University of Karlsruhe + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * MT safe + */ + +static GThreadFunctions +g_mutex_functions_for_glib_use_default; /* is NULLified */ diff --git a/gthread/gthread-nspr.c b/gthread/gthread-nspr.c new file mode 100644 index 000000000..77672e5f0 --- /dev/null +++ b/gthread/gthread-nspr.c @@ -0,0 +1,218 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * gthread.c: nspr thread system implementation + * Copyright 1998 Sebastian Wilhelmi; University of Karlsruhe + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * MT safe + */ + +#include +#include +#include + +#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 (¤t_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 (¤t_time); + + if (abs_time->tv_sec < current_time.tv_sec || + (abs_time->tv_sec == current_time.tv_sec && + abs_time->tv_usec < current_time.tv_usec)) + return FALSE; + return TRUE; +} + +typedef struct _GPrivateNSPRData GPrivateNSPRData; +struct _GPrivateNSPRData + { + gpointer data; + GDestroyNotify destructor; + }; + +typedef struct _GPrivateNSPR GPrivateNSPR; +struct _GPrivateNSPR + { + PRUintn private; + GDestroyNotify destructor; + }; + +static GPrivateNSPRData * +g_private_nspr_data_constructor (GDestroyNotify destructor, gpointer data) +{ + /* we can not use g_new and friends, as they might use private data by + themself */ + GPrivateNSPRData *private = malloc (sizeof (GPrivateNSPRData)); + g_assert (private); + private->data = data; + private->destructor = destructor; + + return private; +} + +static void +g_private_nspr_data_destructor (gpointer data) +{ + GPrivateNSPRData *private = data; + if (private->destructor && private->data) + (*private->destructor) (private->data); + free (private); +} + +static GPrivate * +g_private_new_nspr_impl (GDestroyNotify destructor) +{ + GPrivateNSPR *result = g_new (GPrivateNSPR, 1); + PRStatus status = PR_NewThreadPrivateIndex (&result->private, + g_private_nspr_data_destructor); + g_assert (status == PR_SUCCESS); + + result->destructor = destructor; + return (GPrivate *) result; +} + +/* NOTE: the functions g_private_get and g_private_set may not use + functions from gmem.c and gmessages.c */ + +static GPrivateNSPRData * +g_private_nspr_data_get (GPrivateNSPR * private) +{ + GPrivateNSPRData *data; + + STDERR_ASSERT (private); + + data = PR_GetThreadPrivate (private->private); + if (!data) + { + data = g_private_nspr_data_constructor (private->destructor, NULL); + STDERR_ASSERT (PR_SetThreadPrivate (private->private, data) + == PR_SUCCESS); + } + + return data; +} + +static void +g_private_set_nspr_impl (GPrivate * private, gpointer value) +{ + if (!private) + return; + + g_private_nspr_data_get ((GPrivateNSPR *) private)->data = value; +} + +static gpointer +g_private_get_nspr_impl (GPrivate * private) +{ + if (!private) + return NULL; + + return g_private_nspr_data_get ((GPrivateNSPR *) private)->data; +} + +static GThreadFunctions g_thread_functions_for_glib_use_default = +{ + (GMutex * (*)())PR_NewLock, + (void (*)(GMutex *)) PR_Lock, + g_mutex_trylock_nspr_impl, + (void (*)(GMutex *)) PR_Unlock, + (void (*)(GMutex *)) PR_DestroyLock, + (GCond * (*)())PRP_NewNakedCondVar, + (void (*)(GCond *)) PRP_NakedNotify, + (void (*)(GCond *)) PRP_NakedBroadcast, + g_cond_wait_nspr_impl, + g_cond_timed_wait_nspr_impl, + (void (*)(GCond *)) PRP_DestroyNakedCondVar, + g_private_new_nspr_impl, + g_private_get_nspr_impl, + g_private_set_nspr_impl +}; diff --git a/gthread/gthread-posix.c b/gthread/gthread-posix.c new file mode 100644 index 000000000..5b59672fe --- /dev/null +++ b/gthread/gthread-posix.c @@ -0,0 +1,176 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * gthread.c: posix thread system implementation + * Copyright 1998 Sebastian Wilhelmi; University of Karlsruhe + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * MT safe + */ + +#include +#include +#include +#include + +#define posix_print_error( name, num ) \ + g_error( "file %s: line %d (%s): error %s during %s", \ + __FILE__, __LINE__, G_GNUC_PRETTY_FUNCTION, \ + g_strerror((num)), #name ) + +#define posix_check_for_error( what ) G_STMT_START{ \ + int error = (what); \ + if( error ) { posix_print_error( what, error ); } \ + }G_STMT_END + +static GMutex * +g_mutex_new_posix_impl (void) +{ + GMutex *result = (GMutex *) g_new (pthread_mutex_t, 1); + posix_check_for_error (pthread_mutex_init ((pthread_mutex_t *) result, NULL)); + return result; +} + +static void +g_mutex_free_posix_impl (GMutex * mutex) +{ + posix_check_for_error (pthread_mutex_destroy ((pthread_mutex_t *) mutex)); + free (mutex); +} + +/* NOTE: the functions g_mutex_lock and g_mutex_unlock may not use + functions from gmem.c and gmessages.c; */ + +/* pthread_mutex_lock, pthread_mutex_unlock can be taken directly, as + signature and semantic are right, but without error check then!!!!, + we might want to change this therefore. */ + +static gboolean +g_mutex_trylock_posix_impl (GMutex * mutex) +{ + int result; + + result = pthread_mutex_trylock ((pthread_mutex_t *) mutex); + if (result != EBUSY) + return FALSE; + + posix_check_for_error (result); + return TRUE; +} + +static GCond * +g_cond_new_posix_impl (void) +{ + GCond *result = (GCond *) g_new (pthread_cond_t, 1); + posix_check_for_error (pthread_cond_init ((pthread_cond_t *) result, NULL)); + return result; +} + +/* pthread_cond_signal, pthread_cond_broadcast and pthread_cond_wait + can be taken directly, as signature and semantic are right, but + without error check then!!!!, we might want to change this + therfore. */ + +#define G_MICROSEC 1000000 +#define G_NANOSEC 1000000000 + +static gboolean +g_cond_timed_wait_posix_impl (GCond * cond, + GMutex * entered_mutex, + GTimeVal * abs_time) +{ + int result; + struct timespec end_time; + gboolean timed_out; + + g_return_val_if_fail (cond != NULL, FALSE); + g_return_val_if_fail (entered_mutex != NULL, FALSE); + + if (!abs_time) + { + g_cond_wait (cond, entered_mutex); + return TRUE; + } + + end_time.tv_sec = abs_time->tv_sec; + end_time.tv_nsec = abs_time->tv_usec * (G_NANOSEC / G_MICROSEC); + g_assert (end_time.tv_nsec < G_NANOSEC); + result = pthread_cond_timedwait ((pthread_cond_t *) cond, + (pthread_mutex_t *) entered_mutex, + &end_time); + timed_out = (result == ETIMEDOUT); + if (!timed_out) + posix_check_for_error (result); + return !timed_out; +} + +static void +g_cond_free_posix_impl (GCond * cond) +{ + posix_check_for_error (pthread_cond_destroy ((pthread_cond_t *) cond)); + g_free (cond); +} + +static GPrivate * +g_private_new_posix_impl (GDestroyNotify destructor) +{ + GPrivate *result = (GPrivate *) g_new (pthread_key_t, 1); + posix_check_for_error (pthread_key_create ((pthread_key_t *) result, + destructor)); + return result; +} + +/* NOTE: the functions g_private_get and g_private_set may not use + functions from gmem.c and gmessages.c */ + +static void +g_private_set_posix_impl (GPrivate * private, gpointer value) +{ + if (!private) + return; + + pthread_setspecific (*(pthread_key_t *) private, value); +} + +static gpointer +g_private_get_posix_impl (GPrivate * private) +{ + if (!private) + return NULL; + + return pthread_getspecific (*(pthread_key_t *) private); +} + +static GThreadFunctions g_thread_functions_for_glib_use_default = +{ + g_mutex_new_posix_impl, + (void (*)(GMutex *)) pthread_mutex_lock, + g_mutex_trylock_posix_impl, + (void (*)(GMutex *)) pthread_mutex_unlock, + g_mutex_free_posix_impl, + g_cond_new_posix_impl, + (void (*)(GCond *)) pthread_cond_signal, + (void (*)(GCond *)) pthread_cond_broadcast, + (void (*)(GCond *, GMutex *)) pthread_cond_wait, + g_cond_timed_wait_posix_impl, + g_cond_free_posix_impl, + g_private_new_posix_impl, + g_private_get_posix_impl, + g_private_set_posix_impl +}; diff --git a/gthread/gthread-solaris.c b/gthread/gthread-solaris.c new file mode 100644 index 000000000..52d4c5552 --- /dev/null +++ b/gthread/gthread-solaris.c @@ -0,0 +1,177 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * gthread.c: solaris thread system implementation + * Copyright 1998 Sebastian Wilhelmi; University of Karlsruhe + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * MT safe + */ + +#include +#include +#include +#include + +#define solaris_print_error( name, num ) \ + g_error( "file %s: line %d (%s): error %s during %s", \ + __FILE__, __LINE__, G_GNUC_PRETTY_FUNCTION, \ + g_strerror((num)), #name ) + +#define solaris_check_for_error( what ) G_STMT_START{ \ + int error = (what); \ + if( error ) { solaris_print_error( what, error ); } \ + }G_STMT_END + +static GMutex * +g_mutex_new_solaris_impl (void) +{ + GMutex *result = (GMutex *) g_new (mutex_t, 1); + solaris_check_for_error (mutex_init ((mutex_t *) result, USYNC_PROCESS, 0)); + return result; +} + +static void +g_mutex_free_solaris_impl (GMutex * mutex) +{ + solaris_check_for_error (mutex_destroy ((mutex_t *) mutex)); + free (mutex); +} + +/* NOTE: the functions g_mutex_lock and g_mutex_unlock may not use + functions from gmem.c and gmessages.c; */ + +/* mutex_lock, mutex_unlock can be taken directly, as + signature and semantic are right, but without error check then!!!!, + we might want to change this therefore. */ + +static gboolean +g_mutex_trylock_solaris_impl (GMutex * mutex) +{ + int result; + result = mutex_trylock ((mutex_t *) mutex); + if (result == EBUSY) + return FALSE; + solaris_check_for_error (result); + return TRUE; +} + +static GCond * +g_cond_new_solaris_impl () +{ + GCond *result = (GCond *) g_new (cond_t, 1); + solaris_check_for_error (cond_init ((cond_t *) result, USYNC_THREAD, 0)); + return result; +} + +/* cond_signal, cond_broadcast and cond_wait + can be taken directly, as signature and semantic are right, but + without error check then!!!!, we might want to change this + therfore. */ + +#define G_MICROSEC 1000000 +#define G_NANOSEC 1000000000 + +static gboolean +g_cond_timed_wait_solaris_impl (GCond * cond, + GMutex * entered_mutex, + GTimeVal * abs_time) +{ + int result; + timestruc_t end_time; + gboolean timed_out; + + g_return_val_if_fail (cond != NULL, FALSE); + g_return_val_if_fail (entered_mutex != NULL, FALSE); + + if (!abs_time) + { + g_cond_wait (cond, entered_mutex); + return TRUE; + } + + end_time.tv_sec = abs_time->tv_sec; + end_time.tv_nsec = abs_time->tv_usec * (G_NANOSEC / G_MICROSEC); + g_assert (end_time.tv_nsec < G_NANOSEC); + result = cond_timedwait ((cond_t *) cond, (mutex_t *) entered_mutex, + &end_time); + timed_out = (result == ETIME); + if (!timed_out) + solaris_check_for_error (result); + return !timed_out; +} + +static void +g_cond_free_solaris_impl (GCond * cond) +{ + solaris_check_for_error (cond_destroy ((cond_t *) cond)); + g_free (cond); +} + +static GPrivate * +g_private_new_solaris_impl (GDestroyNotify destructor) +{ + GPrivate *result = (GPrivate *) g_new (thread_key_t,1); + solaris_check_for_error (thr_keycreate ((thread_key_t *) result, + destructor)); + return result; +} + +/* NOTE: the functions g_private_get and g_private_set may not use + functions from gmem.c and gmessages.c */ + +static void +g_private_set_solaris_impl (GPrivate * private, gpointer value) +{ + if (!private) + return; + + thr_setspecific (*(thread_key_t *) private, value); +} + +static gpointer +g_private_get_solaris_impl (GPrivate * private) +{ + gpointer result; + + if (!private) + return NULL; + + thr_getspecific (*(thread_key_t *) private, &result); + + return result; +} + +static GThreadFunctions g_thread_functions_for_glib_use_default = +{ + g_mutex_new_solaris_impl, + (void (*)(GMutex *)) mutex_lock, + g_mutex_trylock_solaris_impl, + (void (*)(GMutex *)) mutex_unlock, + g_mutex_free_solaris_impl, + g_cond_new_solaris_impl, + (void (*)(GCond *)) cond_signal, + (void (*)(GCond *)) cond_broadcast, + (void (*)(GCond *, GMutex *)) cond_wait, + g_cond_timed_wait_solaris_impl, + g_cond_free_solaris_impl, + g_private_new_solaris_impl, + g_private_get_solaris_impl, + g_private_set_solaris_impl +}; diff --git a/gthread/gthread.c b/gthread/gthread.c new file mode 100644 index 000000000..8ada7f89d --- /dev/null +++ b/gthread/gthread.c @@ -0,0 +1,101 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * gthread.c: thread related functions + * Copyright 1998 Sebastian Wilhelmi; University of Karlsruhe + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * MT safe + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +static const char *g_log_domain_gthread = "GThread"; +static gboolean thread_system_already_initialized = FALSE; + +#include G_THREAD_SOURCE + +void g_mutex_init (void); +void g_mem_init (void); +void g_messages_init (void); + +void +g_thread_init(GThreadFunctions* init) +{ + gboolean supported; + + if (thread_system_already_initialized) + g_error ("the glib thread system may only be initialized once."); + + thread_system_already_initialized = TRUE; + + if (init == NULL) + init = &g_thread_functions_for_glib_use_default; + else + g_thread_use_default_impl = FALSE; + + g_thread_functions_for_glib_use = *init; + + /* It is important, that g_thread_supported is not set before the + thread initialization functions of the different modules are + called */ + + supported = + init->mutex_new && + init->mutex_lock && + init->mutex_trylock && + init->mutex_unlock && + init->mutex_free && + init->cond_new && + init->cond_signal && + init->cond_broadcast && + init->cond_wait && + init->cond_timed_wait && + init->cond_free && + init->private_new && + init->private_get && + init->private_get; + + /* if somebody is calling g_thread_init (), it means that he wants to + have thread support, so check this */ + + if (!supported) + { + if (g_thread_use_default_impl) + g_error ("Threads are not supported on this platform."); + else + g_error ("The supplied thread function vector is invalid."); + } + + /* now call the thread initialization functions of the different + glib modules. BTW: order does matter, g_mutex_init MUST be first */ + + g_mutex_init (); + g_mem_init (); + g_messages_init (); + + /* now we can set g_thread_supported and thus enable all the thread + functions */ + + g_thread_supported = TRUE; +} diff --git a/gthread/testgthread.c b/gthread/testgthread.c new file mode 100644 index 000000000..be81f0490 --- /dev/null +++ b/gthread/testgthread.c @@ -0,0 +1,200 @@ +#include + +#define main testglib_main +#include +#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 + +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 (¤t_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, ¤t_time); + g_mutex_unlock (mutex); + + g_mutex_free (mutex); + g_cond_free (cond); +} + +gpointer +private_constructor () +{ + gpointer *result = g_new (gpointer, 2); + result[0] = 0; + result[1] = self_thread (); + g_print ("allocating data for the thread %p.\n", result[1]); + return result; +} + +void +private_destructor (gpointer data) +{ + gpointer *real = data; + g_print ("freeing data for the thread %p.\n", real[1]); + g_free (real); +} + +GStaticPrivate private; + +void +test_private_func (void *data) +{ + guint i = 0; + wait_thread (1); + while (i < TEST_PRIVATE_ROUNDS) + { + guint random_value = rand () % 10000; + guint *data = g_static_private_get (&private); + if (!data) + { + data = private_constructor (); + g_static_private_set (&private, data, private_destructor); + } + *data = random_value; + wait_thread (.2); + g_assert (*(guint *) g_static_private_get (&private) == random_value); + i++; + } +} + +void +test_private () +{ + int i; + gpointer threads[TEST_PRIVATE_THREADS]; + for (i = 0; i < TEST_PRIVATE_THREADS; i++) + { + threads[i] = new_thread (test_private_func, (gpointer) i); + } + for (i = 0; i < TEST_PRIVATE_THREADS; i++) + { + join_thread (threads[i]); + } + g_print ("\n"); +} + +int +main () +{ + test_mutexes (); + + g_thread_init (NULL); + + test_mutexes (); + + test_private (); + + /* later we might want to start n copies of that */ + testglib_main (0, NULL); + + return 0; +} diff --git a/gtimer.c b/gtimer.c index 6e58fa0bd..0b6e86a8a 100644 --- a/gtimer.c +++ b/gtimer.c @@ -17,6 +17,10 @@ * Boston, MA 02111-1307, USA. */ +/* + * MT safe + */ + #ifdef HAVE_CONFIG_H #include #endif diff --git a/gtree.c b/gtree.c index 4d9e98a0b..006f15db7 100644 --- a/gtree.c +++ b/gtree.c @@ -16,6 +16,11 @@ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ + +/* + * MT safe + */ + #include "glib.h" @@ -78,6 +83,7 @@ static GTreeNode* g_tree_node_rotate_right (GTreeNode *node); static void g_tree_node_check (GTreeNode *node); +static G_LOCK_DEFINE(g_tree_global); static GMemChunk *node_mem_chunk = NULL; static GTreeNode *node_free_list = NULL; @@ -88,6 +94,7 @@ g_tree_node_new (gpointer key, { GTreeNode *node; + g_lock (g_tree_global); if (node_free_list) { node = node_free_list; @@ -102,7 +109,8 @@ g_tree_node_new (gpointer key, G_ALLOC_ONLY); node = g_chunk_new (GTreeNode, node_mem_chunk); - } + } + g_unlock (g_tree_global); node->balance = 0; node->left = NULL; @@ -120,9 +128,11 @@ g_tree_node_destroy (GTreeNode *node) { g_tree_node_destroy (node->right); g_tree_node_destroy (node->left); + g_lock (g_tree_global); node->right = node_free_list; node_free_list = node; - } + g_unlock (g_tree_global); + } } @@ -375,9 +385,11 @@ g_tree_node_remove (GTreeNode *node, node = g_tree_node_restore_right_balance (new_root, old_balance); } + g_lock (g_tree_global); garbage->right = node_free_list; node_free_list = garbage; - } + g_unlock (g_tree_global); + } else if (cmp < 0) { if (node->left) diff --git a/gutils.c b/gutils.c index cc6594937..9a91199b6 100644 --- a/gutils.c +++ b/gutils.c @@ -17,6 +17,10 @@ * Boston, MA 02111-1307, USA. */ +/* + * MT safe for the unix part, FIXME: make the win32 part MT safe as well. + */ + #ifdef HAVE_CONFIG_H #include #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