From 41e2001d85966ce3bd9133e49b070a00926bd6ea Mon Sep 17 00:00:00 2001 From: Sebastian Wilhelmi Date: Tue, 13 Feb 2001 15:57:44 +0000 Subject: [PATCH] Added functions g_static_rec_mutex_init, g_static_rec_mutex_free, 2001-02-13 Sebastian Wilhelmi * gthread.c, gthread.h: Added functions g_static_rec_mutex_init, g_static_rec_mutex_free, g_static_private_init, g_static_private_free, g_static_rw_lock_init to allow the usage of all those types dynamically. (g_static_rw_lock_free already existed). Aditionally freed static_private indeces are reused now. Untill now the array would just grow if you would use more and more static_private. That required adding a slist of all running threads, which could potentially be of good use later. It is not exported however. Renamed a LOCK and small indentation fixes. * tests/thread-test.c: Test the new static_private index freing and reusing feature. --- ChangeLog | 16 ++++ ChangeLog.pre-2-0 | 16 ++++ ChangeLog.pre-2-10 | 16 ++++ ChangeLog.pre-2-12 | 16 ++++ ChangeLog.pre-2-2 | 16 ++++ ChangeLog.pre-2-4 | 16 ++++ ChangeLog.pre-2-6 | 16 ++++ ChangeLog.pre-2-8 | 16 ++++ glib/gthread.c | 178 ++++++++++++++++++++++++++++++++++---------- glib/gthread.h | 31 ++++---- gthread.c | 178 ++++++++++++++++++++++++++++++++++---------- gthread.h | 31 ++++---- tests/thread-test.c | 65 +++++++++++++--- 13 files changed, 498 insertions(+), 113 deletions(-) diff --git a/ChangeLog b/ChangeLog index 860f8360..aa4b7829 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,19 @@ +2001-02-13 Sebastian Wilhelmi + + * gthread.c, gthread.h: Added functions g_static_rec_mutex_init, + g_static_rec_mutex_free, g_static_private_init, + g_static_private_free, g_static_rw_lock_init to allow the usage of + all those types dynamically. (g_static_rw_lock_free already + existed). Aditionally freed static_private indeces are reused + now. Untill now the array would just grow if you would use more + and more static_private. That required adding a slist of all + running threads, which could potentially be of good use later. It + is not exported however. Renamed a LOCK and small indentation + fixes. + + * tests/thread-test.c: Test the new static_private index freing + and reusing feature. + Mon Feb 12 15:01:09 2001 Owen Taylor * configure.in (gtk_doc_min_version): Add check for gtk-doc version. diff --git a/ChangeLog.pre-2-0 b/ChangeLog.pre-2-0 index 860f8360..aa4b7829 100644 --- a/ChangeLog.pre-2-0 +++ b/ChangeLog.pre-2-0 @@ -1,3 +1,19 @@ +2001-02-13 Sebastian Wilhelmi + + * gthread.c, gthread.h: Added functions g_static_rec_mutex_init, + g_static_rec_mutex_free, g_static_private_init, + g_static_private_free, g_static_rw_lock_init to allow the usage of + all those types dynamically. (g_static_rw_lock_free already + existed). Aditionally freed static_private indeces are reused + now. Untill now the array would just grow if you would use more + and more static_private. That required adding a slist of all + running threads, which could potentially be of good use later. It + is not exported however. Renamed a LOCK and small indentation + fixes. + + * tests/thread-test.c: Test the new static_private index freing + and reusing feature. + Mon Feb 12 15:01:09 2001 Owen Taylor * configure.in (gtk_doc_min_version): Add check for gtk-doc version. diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10 index 860f8360..aa4b7829 100644 --- a/ChangeLog.pre-2-10 +++ b/ChangeLog.pre-2-10 @@ -1,3 +1,19 @@ +2001-02-13 Sebastian Wilhelmi + + * gthread.c, gthread.h: Added functions g_static_rec_mutex_init, + g_static_rec_mutex_free, g_static_private_init, + g_static_private_free, g_static_rw_lock_init to allow the usage of + all those types dynamically. (g_static_rw_lock_free already + existed). Aditionally freed static_private indeces are reused + now. Untill now the array would just grow if you would use more + and more static_private. That required adding a slist of all + running threads, which could potentially be of good use later. It + is not exported however. Renamed a LOCK and small indentation + fixes. + + * tests/thread-test.c: Test the new static_private index freing + and reusing feature. + Mon Feb 12 15:01:09 2001 Owen Taylor * configure.in (gtk_doc_min_version): Add check for gtk-doc version. diff --git a/ChangeLog.pre-2-12 b/ChangeLog.pre-2-12 index 860f8360..aa4b7829 100644 --- a/ChangeLog.pre-2-12 +++ b/ChangeLog.pre-2-12 @@ -1,3 +1,19 @@ +2001-02-13 Sebastian Wilhelmi + + * gthread.c, gthread.h: Added functions g_static_rec_mutex_init, + g_static_rec_mutex_free, g_static_private_init, + g_static_private_free, g_static_rw_lock_init to allow the usage of + all those types dynamically. (g_static_rw_lock_free already + existed). Aditionally freed static_private indeces are reused + now. Untill now the array would just grow if you would use more + and more static_private. That required adding a slist of all + running threads, which could potentially be of good use later. It + is not exported however. Renamed a LOCK and small indentation + fixes. + + * tests/thread-test.c: Test the new static_private index freing + and reusing feature. + Mon Feb 12 15:01:09 2001 Owen Taylor * configure.in (gtk_doc_min_version): Add check for gtk-doc version. diff --git a/ChangeLog.pre-2-2 b/ChangeLog.pre-2-2 index 860f8360..aa4b7829 100644 --- a/ChangeLog.pre-2-2 +++ b/ChangeLog.pre-2-2 @@ -1,3 +1,19 @@ +2001-02-13 Sebastian Wilhelmi + + * gthread.c, gthread.h: Added functions g_static_rec_mutex_init, + g_static_rec_mutex_free, g_static_private_init, + g_static_private_free, g_static_rw_lock_init to allow the usage of + all those types dynamically. (g_static_rw_lock_free already + existed). Aditionally freed static_private indeces are reused + now. Untill now the array would just grow if you would use more + and more static_private. That required adding a slist of all + running threads, which could potentially be of good use later. It + is not exported however. Renamed a LOCK and small indentation + fixes. + + * tests/thread-test.c: Test the new static_private index freing + and reusing feature. + Mon Feb 12 15:01:09 2001 Owen Taylor * configure.in (gtk_doc_min_version): Add check for gtk-doc version. diff --git a/ChangeLog.pre-2-4 b/ChangeLog.pre-2-4 index 860f8360..aa4b7829 100644 --- a/ChangeLog.pre-2-4 +++ b/ChangeLog.pre-2-4 @@ -1,3 +1,19 @@ +2001-02-13 Sebastian Wilhelmi + + * gthread.c, gthread.h: Added functions g_static_rec_mutex_init, + g_static_rec_mutex_free, g_static_private_init, + g_static_private_free, g_static_rw_lock_init to allow the usage of + all those types dynamically. (g_static_rw_lock_free already + existed). Aditionally freed static_private indeces are reused + now. Untill now the array would just grow if you would use more + and more static_private. That required adding a slist of all + running threads, which could potentially be of good use later. It + is not exported however. Renamed a LOCK and small indentation + fixes. + + * tests/thread-test.c: Test the new static_private index freing + and reusing feature. + Mon Feb 12 15:01:09 2001 Owen Taylor * configure.in (gtk_doc_min_version): Add check for gtk-doc version. diff --git a/ChangeLog.pre-2-6 b/ChangeLog.pre-2-6 index 860f8360..aa4b7829 100644 --- a/ChangeLog.pre-2-6 +++ b/ChangeLog.pre-2-6 @@ -1,3 +1,19 @@ +2001-02-13 Sebastian Wilhelmi + + * gthread.c, gthread.h: Added functions g_static_rec_mutex_init, + g_static_rec_mutex_free, g_static_private_init, + g_static_private_free, g_static_rw_lock_init to allow the usage of + all those types dynamically. (g_static_rw_lock_free already + existed). Aditionally freed static_private indeces are reused + now. Untill now the array would just grow if you would use more + and more static_private. That required adding a slist of all + running threads, which could potentially be of good use later. It + is not exported however. Renamed a LOCK and small indentation + fixes. + + * tests/thread-test.c: Test the new static_private index freing + and reusing feature. + Mon Feb 12 15:01:09 2001 Owen Taylor * configure.in (gtk_doc_min_version): Add check for gtk-doc version. diff --git a/ChangeLog.pre-2-8 b/ChangeLog.pre-2-8 index 860f8360..aa4b7829 100644 --- a/ChangeLog.pre-2-8 +++ b/ChangeLog.pre-2-8 @@ -1,3 +1,19 @@ +2001-02-13 Sebastian Wilhelmi + + * gthread.c, gthread.h: Added functions g_static_rec_mutex_init, + g_static_rec_mutex_free, g_static_private_init, + g_static_private_free, g_static_rw_lock_init to allow the usage of + all those types dynamically. (g_static_rw_lock_free already + existed). Aditionally freed static_private indeces are reused + now. Untill now the array would just grow if you would use more + and more static_private. That required adding a slist of all + running threads, which could potentially be of good use later. It + is not exported however. Renamed a LOCK and small indentation + fixes. + + * tests/thread-test.c: Test the new static_private index freing + and reusing feature. + Mon Feb 12 15:01:09 2001 Owen Taylor * configure.in (gtk_doc_min_version): Add check for gtk-doc version. diff --git a/glib/gthread.c b/glib/gthread.c index 71b56271..7ec6568d 100644 --- a/glib/gthread.c +++ b/glib/gthread.c @@ -52,7 +52,7 @@ #endif /* GLIB_SIZEOF_SYSTEM_THREAD == SIZEOF_VOID_P */ GQuark -g_thread_error_quark() +g_thread_error_quark (void) { static GQuark quark; if (!quark) @@ -117,8 +117,11 @@ GThreadFunctions g_thread_functions_for_glib_use = { /* 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; +static GSList *g_thread_all_threads = NULL; +static GSList *g_thread_free_indeces = NULL; + +G_LOCK_DEFINE_STATIC (g_thread); /* This must be called only once, before any threads are created. * It will only be called from g_thread_init() in -lgthread. @@ -137,8 +140,17 @@ g_mutex_init (void) G_THREAD_UF (private_set, (g_thread_specific_private, main_thread)); G_THREAD_UF (thread_self, (&main_thread->system_thread)); - g_mutex_protect_static_mutex_allocation = g_mutex_new(); - g_thread_specific_mutex = g_mutex_new(); + g_mutex_protect_static_mutex_allocation = g_mutex_new (); +} + +void +g_static_mutex_init (GStaticMutex *mutex) +{ + static GStaticMutex init_mutex = G_STATIC_MUTEX_INIT; + + g_return_if_fail (mutex); + + memcpy (mutex, &init_mutex, sizeof (GStaticMutex)); } GMutex * @@ -152,23 +164,13 @@ g_static_mutex_get_mutex_impl (GMutex** mutex) g_mutex_lock (g_mutex_protect_static_mutex_allocation); if (!(*mutex)) - *mutex = g_mutex_new(); + *mutex = g_mutex_new (); g_mutex_unlock (g_mutex_protect_static_mutex_allocation); return *mutex; } -void -g_static_mutex_init (GStaticMutex *mutex) -{ - static GStaticMutex init_mutex = G_STATIC_MUTEX_INIT; - - g_return_if_fail (mutex); - - memcpy (mutex, &init_mutex, sizeof (GStaticMutex)); -} - void g_static_mutex_free (GStaticMutex* mutex) { @@ -186,6 +188,16 @@ g_static_mutex_free (GStaticMutex* mutex) *runtime_mutex = NULL; } +void +g_static_rec_mutex_init (GStaticRecMutex *mutex) +{ + static GStaticRecMutex init_mutex = G_STATIC_REC_MUTEX_INIT; + + g_return_if_fail (mutex); + + memcpy (mutex, &init_mutex, sizeof (GStaticRecMutex)); +} + void g_static_rec_mutex_lock (GStaticRecMutex* mutex) { @@ -284,6 +296,19 @@ g_static_rec_mutex_unlock_full (GStaticRecMutex *mutex) return depth; } +void +g_static_rec_mutex_free (GStaticRecMutex *mutex) +{ + g_return_if_fail (mutex); + + g_static_mutex_free (&mutex->mutex); +} + +void +g_static_private_init (GStaticPrivate *private_key) +{ + private_key->index = 0; +} gpointer g_static_private_get (GStaticPrivate *private_key) @@ -343,12 +368,23 @@ g_static_private_set_for_thread (GStaticPrivate *private_key, if (!private_key->index) { - g_mutex_lock (g_thread_specific_mutex); + G_LOCK (g_thread); if (!private_key->index) - private_key->index = ++next_index; + { + if (g_thread_free_indeces) + { + private_key->index = + GPOINTER_TO_UINT (g_thread_free_indeces->data); + g_thread_free_indeces = + g_slist_delete_link (g_thread_free_indeces, + g_thread_free_indeces); + } + else + private_key->index = ++next_index; + } - g_mutex_unlock (g_thread_specific_mutex); + G_UNLOCK (g_thread); } if (private_key->index > array->len) @@ -372,6 +408,35 @@ g_static_private_set_for_thread (GStaticPrivate *private_key, } } +void +g_static_private_free (GStaticPrivate *private_key) +{ + GStaticPrivate copied_key; + GSList *list; + + copied_key.index = private_key->index; + private_key->index = 0; + + if (!copied_key.index) + return; + + G_LOCK (g_thread); + list = g_thread_all_threads; + while (list) + { + GThread *thread = list->data; + list = list->next; + + G_UNLOCK (g_thread); + g_static_private_set_for_thread (&copied_key, thread, NULL, NULL); + G_LOCK (g_thread); + } + g_thread_free_indeces = + g_slist_prepend (g_thread_free_indeces, + GUINT_TO_POINTER (copied_key.index)); + G_UNLOCK (g_thread); +} + static void g_thread_cleanup (gpointer data) { @@ -396,6 +461,10 @@ g_thread_cleanup (gpointer data) it is, the structure is freed in g_thread_join */ if (!thread->thread.joinable) { + G_LOCK (g_thread); + g_thread_all_threads = g_slist_remove (g_thread_all_threads, data); + G_UNLOCK (g_thread); + /* Just to make sure, this isn't used any more */ g_system_thread_assign (thread->system_thread, zero_thread); g_free (thread); @@ -409,8 +478,6 @@ g_thread_fail (void) g_error ("The thread system is not yet initialized."); } -G_LOCK_DEFINE_STATIC (g_thread_create); - static void g_thread_create_proxy (gpointer data) { @@ -423,8 +490,8 @@ g_thread_create_proxy (gpointer data) /* the lock makes sure, that thread->system_thread is written, before thread->func is called. See g_thread_create. */ - G_LOCK (g_thread_create); - G_UNLOCK (g_thread_create); + G_LOCK (g_thread); + G_UNLOCK (g_thread); thread->func (thread->arg); } @@ -450,11 +517,12 @@ g_thread_create (GThreadFunc thread_func, result->func = thread_func; result->arg = arg; result->private_data = NULL; - G_LOCK (g_thread_create); + G_LOCK (g_thread); G_THREAD_UF (thread_create, (g_thread_create_proxy, result, stack_size, joinable, bound, priority, &result->system_thread, &local_error)); - G_UNLOCK (g_thread_create); + g_thread_all_threads = g_slist_prepend (g_thread_all_threads, result); + G_UNLOCK (g_thread); if (local_error) { @@ -478,6 +546,10 @@ g_thread_join (GThread* thread) G_THREAD_UF (thread_join, (&real->system_thread)); + G_LOCK (g_thread); + g_thread_all_threads = g_slist_remove (g_thread_all_threads, thread); + G_UNLOCK (g_thread); + /* Just to make sure, this isn't used any more */ thread->joinable = 0; g_system_thread_assign (real->system_thread, zero_thread); @@ -505,7 +577,7 @@ g_thread_set_priority (GThread* thread, } GThread* -g_thread_self() +g_thread_self (void) { GRealThread* thread = g_private_get (g_thread_specific_private); @@ -526,20 +598,36 @@ g_thread_self() if (g_thread_supported ()) G_THREAD_UF (thread_self, (&thread->system_thread)); - g_private_set (g_thread_specific_private, thread); + g_private_set (g_thread_specific_private, thread); + + G_LOCK (g_thread); + g_thread_all_threads = g_slist_prepend (g_thread_all_threads, thread); + G_UNLOCK (g_thread); } return (GThread*)thread; } -static void inline g_static_rw_lock_wait (GCond** cond, GStaticMutex* mutex) +void +g_static_rw_lock_init (GStaticRWLock* lock) +{ + static GStaticRWLock init_lock = G_STATIC_RW_LOCK_INIT; + + g_return_if_fail (lock); + + memcpy (lock, &init_lock, sizeof (GStaticRWLock)); +} + +static void inline +g_static_rw_lock_wait (GCond** cond, GStaticMutex* mutex) { if (!*cond) *cond = g_cond_new (); g_cond_wait (*cond, g_static_mutex_get_mutex (mutex)); } -static void inline g_static_rw_lock_signal (GStaticRWLock* lock) +static void inline +g_static_rw_lock_signal (GStaticRWLock* lock) { if (lock->want_to_write && lock->write_cond) g_cond_signal (lock->write_cond); @@ -547,7 +635,8 @@ static void inline g_static_rw_lock_signal (GStaticRWLock* lock) g_cond_broadcast (lock->read_cond); } -void g_static_rw_lock_reader_lock (GStaticRWLock* lock) +void +g_static_rw_lock_reader_lock (GStaticRWLock* lock) { g_return_if_fail (lock); @@ -561,7 +650,8 @@ void g_static_rw_lock_reader_lock (GStaticRWLock* lock) g_static_mutex_unlock (&lock->mutex); } -gboolean g_static_rw_lock_reader_trylock (GStaticRWLock* lock) +gboolean +g_static_rw_lock_reader_trylock (GStaticRWLock* lock) { gboolean ret_val = FALSE; @@ -580,7 +670,8 @@ gboolean g_static_rw_lock_reader_trylock (GStaticRWLock* lock) return ret_val; } -void g_static_rw_lock_reader_unlock (GStaticRWLock* lock) +void +g_static_rw_lock_reader_unlock (GStaticRWLock* lock) { g_return_if_fail (lock); @@ -594,7 +685,8 @@ void g_static_rw_lock_reader_unlock (GStaticRWLock* lock) g_static_mutex_unlock (&lock->mutex); } -void g_static_rw_lock_writer_lock (GStaticRWLock* lock) +void +g_static_rw_lock_writer_lock (GStaticRWLock* lock) { g_return_if_fail (lock); @@ -610,7 +702,8 @@ void g_static_rw_lock_writer_lock (GStaticRWLock* lock) g_static_mutex_unlock (&lock->mutex); } -gboolean g_static_rw_lock_writer_trylock (GStaticRWLock* lock) +gboolean +g_static_rw_lock_writer_trylock (GStaticRWLock* lock) { gboolean ret_val = FALSE; @@ -629,7 +722,8 @@ gboolean g_static_rw_lock_writer_trylock (GStaticRWLock* lock) return ret_val; } -void g_static_rw_lock_writer_unlock (GStaticRWLock* lock) +void +g_static_rw_lock_writer_unlock (GStaticRWLock* lock) { g_return_if_fail (lock); @@ -642,14 +736,20 @@ void g_static_rw_lock_writer_unlock (GStaticRWLock* lock) g_static_mutex_unlock (&lock->mutex); } -void g_static_rw_lock_free (GStaticRWLock* lock) +void +g_static_rw_lock_free (GStaticRWLock* lock) { g_return_if_fail (lock); if (lock->read_cond) - g_cond_free (lock->read_cond); + { + g_cond_free (lock->read_cond); + lock->read_cond = NULL; + } if (lock->write_cond) - g_cond_free (lock->write_cond); - + { + g_cond_free (lock->write_cond); + lock->write_cond = NULL; + } + g_static_mutex_free (&lock->mutex); } - diff --git a/glib/gthread.h b/glib/gthread.h index 1f86418f..44145d56 100644 --- a/glib/gthread.h +++ b/glib/gthread.h @@ -46,8 +46,8 @@ G_BEGIN_DECLS /* GLib Thread support */ -extern GQuark g_thread_error_quark(); -#define G_THREAD_ERROR g_thread_error_quark() +extern GQuark g_thread_error_quark (void); +#define G_THREAD_ERROR g_thread_error_quark () typedef enum { @@ -235,16 +235,18 @@ struct _GStaticPrivate guint index; }; #define G_STATIC_PRIVATE_INIT { 0 } -gpointer g_static_private_get (GStaticPrivate *private_key); -void g_static_private_set (GStaticPrivate *private_key, - gpointer data, - GDestroyNotify notify); -gpointer g_static_private_get_for_thread (GStaticPrivate *private_key, - GThread *thread); -void g_static_private_set_for_thread (GStaticPrivate *private_key, - GThread *thread, - gpointer data, - GDestroyNotify notify); +void g_static_private_init (GStaticPrivate *private_key); +gpointer g_static_private_get (GStaticPrivate *private_key); +void g_static_private_set (GStaticPrivate *private_key, + gpointer data, + GDestroyNotify notify); +gpointer g_static_private_get_for_thread (GStaticPrivate *private_key, + GThread *thread); +void g_static_private_set_for_thread (GStaticPrivate *private_key, + GThread *thread, + gpointer data, + GDestroyNotify notify); +void g_static_private_free (GStaticPrivate *private_key); typedef struct _GStaticRecMutex GStaticRecMutex; struct _GStaticRecMutex @@ -255,12 +257,14 @@ struct _GStaticRecMutex }; #define G_STATIC_REC_MUTEX_INIT { G_STATIC_MUTEX_INIT } +void g_static_rec_mutex_init (GStaticRecMutex *mutex); void g_static_rec_mutex_lock (GStaticRecMutex *mutex); gboolean g_static_rec_mutex_trylock (GStaticRecMutex *mutex); void g_static_rec_mutex_unlock (GStaticRecMutex *mutex); void g_static_rec_mutex_lock_full (GStaticRecMutex *mutex, guint depth); guint g_static_rec_mutex_unlock_full (GStaticRecMutex *mutex); +void g_static_rec_mutex_free (GStaticRecMutex *mutex); typedef struct _GStaticRWLock GStaticRWLock; struct _GStaticRWLock @@ -275,13 +279,14 @@ struct _GStaticRWLock #define G_STATIC_RW_LOCK_INIT { G_STATIC_MUTEX_INIT, NULL, NULL, 0, FALSE, FALSE } +void g_static_rw_lock_init (GStaticRWLock* lock); void g_static_rw_lock_reader_lock (GStaticRWLock* lock); gboolean g_static_rw_lock_reader_trylock (GStaticRWLock* lock); void g_static_rw_lock_reader_unlock (GStaticRWLock* lock); void g_static_rw_lock_writer_lock (GStaticRWLock* lock); gboolean g_static_rw_lock_writer_trylock (GStaticRWLock* lock); void g_static_rw_lock_writer_unlock (GStaticRWLock* lock); -void g_static_rw_lock_free (GStaticRWLock* lock); +void g_static_rw_lock_free (GStaticRWLock* lock); /* these are some convenience macros that expand to nothing if GLib * was configured with --disable-threads. for using StaticMutexes, diff --git a/gthread.c b/gthread.c index 71b56271..7ec6568d 100644 --- a/gthread.c +++ b/gthread.c @@ -52,7 +52,7 @@ #endif /* GLIB_SIZEOF_SYSTEM_THREAD == SIZEOF_VOID_P */ GQuark -g_thread_error_quark() +g_thread_error_quark (void) { static GQuark quark; if (!quark) @@ -117,8 +117,11 @@ GThreadFunctions g_thread_functions_for_glib_use = { /* 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; +static GSList *g_thread_all_threads = NULL; +static GSList *g_thread_free_indeces = NULL; + +G_LOCK_DEFINE_STATIC (g_thread); /* This must be called only once, before any threads are created. * It will only be called from g_thread_init() in -lgthread. @@ -137,8 +140,17 @@ g_mutex_init (void) G_THREAD_UF (private_set, (g_thread_specific_private, main_thread)); G_THREAD_UF (thread_self, (&main_thread->system_thread)); - g_mutex_protect_static_mutex_allocation = g_mutex_new(); - g_thread_specific_mutex = g_mutex_new(); + g_mutex_protect_static_mutex_allocation = g_mutex_new (); +} + +void +g_static_mutex_init (GStaticMutex *mutex) +{ + static GStaticMutex init_mutex = G_STATIC_MUTEX_INIT; + + g_return_if_fail (mutex); + + memcpy (mutex, &init_mutex, sizeof (GStaticMutex)); } GMutex * @@ -152,23 +164,13 @@ g_static_mutex_get_mutex_impl (GMutex** mutex) g_mutex_lock (g_mutex_protect_static_mutex_allocation); if (!(*mutex)) - *mutex = g_mutex_new(); + *mutex = g_mutex_new (); g_mutex_unlock (g_mutex_protect_static_mutex_allocation); return *mutex; } -void -g_static_mutex_init (GStaticMutex *mutex) -{ - static GStaticMutex init_mutex = G_STATIC_MUTEX_INIT; - - g_return_if_fail (mutex); - - memcpy (mutex, &init_mutex, sizeof (GStaticMutex)); -} - void g_static_mutex_free (GStaticMutex* mutex) { @@ -186,6 +188,16 @@ g_static_mutex_free (GStaticMutex* mutex) *runtime_mutex = NULL; } +void +g_static_rec_mutex_init (GStaticRecMutex *mutex) +{ + static GStaticRecMutex init_mutex = G_STATIC_REC_MUTEX_INIT; + + g_return_if_fail (mutex); + + memcpy (mutex, &init_mutex, sizeof (GStaticRecMutex)); +} + void g_static_rec_mutex_lock (GStaticRecMutex* mutex) { @@ -284,6 +296,19 @@ g_static_rec_mutex_unlock_full (GStaticRecMutex *mutex) return depth; } +void +g_static_rec_mutex_free (GStaticRecMutex *mutex) +{ + g_return_if_fail (mutex); + + g_static_mutex_free (&mutex->mutex); +} + +void +g_static_private_init (GStaticPrivate *private_key) +{ + private_key->index = 0; +} gpointer g_static_private_get (GStaticPrivate *private_key) @@ -343,12 +368,23 @@ g_static_private_set_for_thread (GStaticPrivate *private_key, if (!private_key->index) { - g_mutex_lock (g_thread_specific_mutex); + G_LOCK (g_thread); if (!private_key->index) - private_key->index = ++next_index; + { + if (g_thread_free_indeces) + { + private_key->index = + GPOINTER_TO_UINT (g_thread_free_indeces->data); + g_thread_free_indeces = + g_slist_delete_link (g_thread_free_indeces, + g_thread_free_indeces); + } + else + private_key->index = ++next_index; + } - g_mutex_unlock (g_thread_specific_mutex); + G_UNLOCK (g_thread); } if (private_key->index > array->len) @@ -372,6 +408,35 @@ g_static_private_set_for_thread (GStaticPrivate *private_key, } } +void +g_static_private_free (GStaticPrivate *private_key) +{ + GStaticPrivate copied_key; + GSList *list; + + copied_key.index = private_key->index; + private_key->index = 0; + + if (!copied_key.index) + return; + + G_LOCK (g_thread); + list = g_thread_all_threads; + while (list) + { + GThread *thread = list->data; + list = list->next; + + G_UNLOCK (g_thread); + g_static_private_set_for_thread (&copied_key, thread, NULL, NULL); + G_LOCK (g_thread); + } + g_thread_free_indeces = + g_slist_prepend (g_thread_free_indeces, + GUINT_TO_POINTER (copied_key.index)); + G_UNLOCK (g_thread); +} + static void g_thread_cleanup (gpointer data) { @@ -396,6 +461,10 @@ g_thread_cleanup (gpointer data) it is, the structure is freed in g_thread_join */ if (!thread->thread.joinable) { + G_LOCK (g_thread); + g_thread_all_threads = g_slist_remove (g_thread_all_threads, data); + G_UNLOCK (g_thread); + /* Just to make sure, this isn't used any more */ g_system_thread_assign (thread->system_thread, zero_thread); g_free (thread); @@ -409,8 +478,6 @@ g_thread_fail (void) g_error ("The thread system is not yet initialized."); } -G_LOCK_DEFINE_STATIC (g_thread_create); - static void g_thread_create_proxy (gpointer data) { @@ -423,8 +490,8 @@ g_thread_create_proxy (gpointer data) /* the lock makes sure, that thread->system_thread is written, before thread->func is called. See g_thread_create. */ - G_LOCK (g_thread_create); - G_UNLOCK (g_thread_create); + G_LOCK (g_thread); + G_UNLOCK (g_thread); thread->func (thread->arg); } @@ -450,11 +517,12 @@ g_thread_create (GThreadFunc thread_func, result->func = thread_func; result->arg = arg; result->private_data = NULL; - G_LOCK (g_thread_create); + G_LOCK (g_thread); G_THREAD_UF (thread_create, (g_thread_create_proxy, result, stack_size, joinable, bound, priority, &result->system_thread, &local_error)); - G_UNLOCK (g_thread_create); + g_thread_all_threads = g_slist_prepend (g_thread_all_threads, result); + G_UNLOCK (g_thread); if (local_error) { @@ -478,6 +546,10 @@ g_thread_join (GThread* thread) G_THREAD_UF (thread_join, (&real->system_thread)); + G_LOCK (g_thread); + g_thread_all_threads = g_slist_remove (g_thread_all_threads, thread); + G_UNLOCK (g_thread); + /* Just to make sure, this isn't used any more */ thread->joinable = 0; g_system_thread_assign (real->system_thread, zero_thread); @@ -505,7 +577,7 @@ g_thread_set_priority (GThread* thread, } GThread* -g_thread_self() +g_thread_self (void) { GRealThread* thread = g_private_get (g_thread_specific_private); @@ -526,20 +598,36 @@ g_thread_self() if (g_thread_supported ()) G_THREAD_UF (thread_self, (&thread->system_thread)); - g_private_set (g_thread_specific_private, thread); + g_private_set (g_thread_specific_private, thread); + + G_LOCK (g_thread); + g_thread_all_threads = g_slist_prepend (g_thread_all_threads, thread); + G_UNLOCK (g_thread); } return (GThread*)thread; } -static void inline g_static_rw_lock_wait (GCond** cond, GStaticMutex* mutex) +void +g_static_rw_lock_init (GStaticRWLock* lock) +{ + static GStaticRWLock init_lock = G_STATIC_RW_LOCK_INIT; + + g_return_if_fail (lock); + + memcpy (lock, &init_lock, sizeof (GStaticRWLock)); +} + +static void inline +g_static_rw_lock_wait (GCond** cond, GStaticMutex* mutex) { if (!*cond) *cond = g_cond_new (); g_cond_wait (*cond, g_static_mutex_get_mutex (mutex)); } -static void inline g_static_rw_lock_signal (GStaticRWLock* lock) +static void inline +g_static_rw_lock_signal (GStaticRWLock* lock) { if (lock->want_to_write && lock->write_cond) g_cond_signal (lock->write_cond); @@ -547,7 +635,8 @@ static void inline g_static_rw_lock_signal (GStaticRWLock* lock) g_cond_broadcast (lock->read_cond); } -void g_static_rw_lock_reader_lock (GStaticRWLock* lock) +void +g_static_rw_lock_reader_lock (GStaticRWLock* lock) { g_return_if_fail (lock); @@ -561,7 +650,8 @@ void g_static_rw_lock_reader_lock (GStaticRWLock* lock) g_static_mutex_unlock (&lock->mutex); } -gboolean g_static_rw_lock_reader_trylock (GStaticRWLock* lock) +gboolean +g_static_rw_lock_reader_trylock (GStaticRWLock* lock) { gboolean ret_val = FALSE; @@ -580,7 +670,8 @@ gboolean g_static_rw_lock_reader_trylock (GStaticRWLock* lock) return ret_val; } -void g_static_rw_lock_reader_unlock (GStaticRWLock* lock) +void +g_static_rw_lock_reader_unlock (GStaticRWLock* lock) { g_return_if_fail (lock); @@ -594,7 +685,8 @@ void g_static_rw_lock_reader_unlock (GStaticRWLock* lock) g_static_mutex_unlock (&lock->mutex); } -void g_static_rw_lock_writer_lock (GStaticRWLock* lock) +void +g_static_rw_lock_writer_lock (GStaticRWLock* lock) { g_return_if_fail (lock); @@ -610,7 +702,8 @@ void g_static_rw_lock_writer_lock (GStaticRWLock* lock) g_static_mutex_unlock (&lock->mutex); } -gboolean g_static_rw_lock_writer_trylock (GStaticRWLock* lock) +gboolean +g_static_rw_lock_writer_trylock (GStaticRWLock* lock) { gboolean ret_val = FALSE; @@ -629,7 +722,8 @@ gboolean g_static_rw_lock_writer_trylock (GStaticRWLock* lock) return ret_val; } -void g_static_rw_lock_writer_unlock (GStaticRWLock* lock) +void +g_static_rw_lock_writer_unlock (GStaticRWLock* lock) { g_return_if_fail (lock); @@ -642,14 +736,20 @@ void g_static_rw_lock_writer_unlock (GStaticRWLock* lock) g_static_mutex_unlock (&lock->mutex); } -void g_static_rw_lock_free (GStaticRWLock* lock) +void +g_static_rw_lock_free (GStaticRWLock* lock) { g_return_if_fail (lock); if (lock->read_cond) - g_cond_free (lock->read_cond); + { + g_cond_free (lock->read_cond); + lock->read_cond = NULL; + } if (lock->write_cond) - g_cond_free (lock->write_cond); - + { + g_cond_free (lock->write_cond); + lock->write_cond = NULL; + } + g_static_mutex_free (&lock->mutex); } - diff --git a/gthread.h b/gthread.h index 1f86418f..44145d56 100644 --- a/gthread.h +++ b/gthread.h @@ -46,8 +46,8 @@ G_BEGIN_DECLS /* GLib Thread support */ -extern GQuark g_thread_error_quark(); -#define G_THREAD_ERROR g_thread_error_quark() +extern GQuark g_thread_error_quark (void); +#define G_THREAD_ERROR g_thread_error_quark () typedef enum { @@ -235,16 +235,18 @@ struct _GStaticPrivate guint index; }; #define G_STATIC_PRIVATE_INIT { 0 } -gpointer g_static_private_get (GStaticPrivate *private_key); -void g_static_private_set (GStaticPrivate *private_key, - gpointer data, - GDestroyNotify notify); -gpointer g_static_private_get_for_thread (GStaticPrivate *private_key, - GThread *thread); -void g_static_private_set_for_thread (GStaticPrivate *private_key, - GThread *thread, - gpointer data, - GDestroyNotify notify); +void g_static_private_init (GStaticPrivate *private_key); +gpointer g_static_private_get (GStaticPrivate *private_key); +void g_static_private_set (GStaticPrivate *private_key, + gpointer data, + GDestroyNotify notify); +gpointer g_static_private_get_for_thread (GStaticPrivate *private_key, + GThread *thread); +void g_static_private_set_for_thread (GStaticPrivate *private_key, + GThread *thread, + gpointer data, + GDestroyNotify notify); +void g_static_private_free (GStaticPrivate *private_key); typedef struct _GStaticRecMutex GStaticRecMutex; struct _GStaticRecMutex @@ -255,12 +257,14 @@ struct _GStaticRecMutex }; #define G_STATIC_REC_MUTEX_INIT { G_STATIC_MUTEX_INIT } +void g_static_rec_mutex_init (GStaticRecMutex *mutex); void g_static_rec_mutex_lock (GStaticRecMutex *mutex); gboolean g_static_rec_mutex_trylock (GStaticRecMutex *mutex); void g_static_rec_mutex_unlock (GStaticRecMutex *mutex); void g_static_rec_mutex_lock_full (GStaticRecMutex *mutex, guint depth); guint g_static_rec_mutex_unlock_full (GStaticRecMutex *mutex); +void g_static_rec_mutex_free (GStaticRecMutex *mutex); typedef struct _GStaticRWLock GStaticRWLock; struct _GStaticRWLock @@ -275,13 +279,14 @@ struct _GStaticRWLock #define G_STATIC_RW_LOCK_INIT { G_STATIC_MUTEX_INIT, NULL, NULL, 0, FALSE, FALSE } +void g_static_rw_lock_init (GStaticRWLock* lock); void g_static_rw_lock_reader_lock (GStaticRWLock* lock); gboolean g_static_rw_lock_reader_trylock (GStaticRWLock* lock); void g_static_rw_lock_reader_unlock (GStaticRWLock* lock); void g_static_rw_lock_writer_lock (GStaticRWLock* lock); gboolean g_static_rw_lock_writer_trylock (GStaticRWLock* lock); void g_static_rw_lock_writer_unlock (GStaticRWLock* lock); -void g_static_rw_lock_free (GStaticRWLock* lock); +void g_static_rw_lock_free (GStaticRWLock* lock); /* these are some convenience macros that expand to nothing if GLib * was configured with --disable-threads. for using StaticMutexes, diff --git a/tests/thread-test.c b/tests/thread-test.c index 1fc6b836..3e689b53 100644 --- a/tests/thread-test.c +++ b/tests/thread-test.c @@ -81,9 +81,11 @@ test_g_static_rec_mutex (void) #define THREADS 10 -static GStaticPrivate test_g_static_private_private = G_STATIC_PRIVATE_INIT; +static GStaticPrivate test_g_static_private_private1 = G_STATIC_PRIVATE_INIT; +static GStaticPrivate test_g_static_private_private2 = G_STATIC_PRIVATE_INIT; static GStaticMutex test_g_static_private_mutex = G_STATIC_MUTEX_INIT; static guint test_g_static_private_counter = 0; +static guint test_g_static_private_ready = 0; static gpointer test_g_static_private_constructor (void) @@ -109,20 +111,51 @@ test_g_static_private_thread (gpointer data) { guint number = GPOINTER_TO_INT (data); guint i; - guint* private; + guint *private1, *private2; for (i = 0; i < 10; i++) { number = number * 11 + 1; /* A very simple and bad RNG ;-) */ - private = g_static_private_get (&test_g_static_private_private); - if (!private || number % 7 > 3) + private1 = g_static_private_get (&test_g_static_private_private1); + if (!private1 || number % 7 > 3) { - private = test_g_static_private_constructor (); - g_static_private_set (&test_g_static_private_private, private, + private1 = test_g_static_private_constructor (); + g_static_private_set (&test_g_static_private_private1, private1, test_g_static_private_destructor); } - *private = number; + *private1 = number; + private2 = g_static_private_get (&test_g_static_private_private2); + if (!private2 || number % 13 > 5) + { + private2 = test_g_static_private_constructor (); + g_static_private_set (&test_g_static_private_private2, private2, + test_g_static_private_destructor); + } + *private2 = number * 2; + g_usleep (G_USEC_PER_SEC / 5); + g_assert (number == *private1); + g_assert (number * 2 == *private2); + } + g_static_mutex_lock (&test_g_static_private_mutex); + test_g_static_private_ready++; + g_static_mutex_unlock (&test_g_static_private_mutex); + + /* Busy wait is not nice but that's just a test */ + while (test_g_static_private_ready != 0) + g_usleep (G_USEC_PER_SEC / 5); + + for (i = 0; i < 10; i++) + { + private2 = g_static_private_get (&test_g_static_private_private2); + number = number * 11 + 1; /* A very simple and bad RNG ;-) */ + if (!private2 || number % 13 > 5) + { + private2 = test_g_static_private_constructor (); + g_static_private_set (&test_g_static_private_private2, private2, + test_g_static_private_destructor); + } + *private2 = number * 2; g_usleep (G_USEC_PER_SEC / 5); - g_assert (number == *private); + g_assert (number * 2 == *private2); } } @@ -131,6 +164,9 @@ test_g_static_private (void) { GThread *threads[THREADS]; guint i; + + test_g_static_private_ready = 0; + for (i = 0; i < THREADS; i++) { threads[i] = g_thread_create (test_g_static_private_thread, @@ -138,6 +174,17 @@ test_g_static_private (void) 0, TRUE, TRUE, G_THREAD_PRIORITY_NORMAL, NULL); } + + /* Busy wait is not nice but that's just a test */ + while (test_g_static_private_ready != THREADS) + g_usleep (G_USEC_PER_SEC / 5); + + /* Reuse the static private */ + g_static_private_free (&test_g_static_private_private2); + g_static_private_init (&test_g_static_private_private2); + + test_g_static_private_ready = 0; + for (i = 0; i < THREADS; i++) { g_thread_join (threads[i]); @@ -231,7 +278,7 @@ run_all_tests() test_g_mutex (); test_g_static_rec_mutex (); test_g_static_private (); - test_g_static_rw_lock (); + test_g_static_rw_lock (); } int -- 2.34.1