diff options
author | Owen Taylor <otaylor@src.gnome.org> | 1998-12-15 05:28:02 +0000 |
---|---|---|
committer | Owen Taylor <otaylor@src.gnome.org> | 1998-12-15 05:28:02 +0000 |
commit | 931ea952650b013b834041b91b0c37a748ffd449 (patch) | |
tree | 0c97c450b0e07953d836f1603c6fcb0357a58149 /glib | |
parent | c8ba100dab8949c49097f11004c09ef36ea5136f (diff) | |
download | glib-931ea952650b013b834041b91b0c37a748ffd449.tar.gz |
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.
Diffstat (limited to 'glib')
-rw-r--r-- | glib/Makefile.am | 5 | ||||
-rw-r--r-- | glib/garray.c | 19 | ||||
-rw-r--r-- | glib/gbacktrace.c | 5 | ||||
-rw-r--r-- | glib/gcache.c | 11 | ||||
-rw-r--r-- | glib/gcompletion.c | 4 | ||||
-rw-r--r-- | glib/gdataset.c | 76 | ||||
-rw-r--r-- | glib/gdate.c | 24 | ||||
-rw-r--r-- | glib/gerror.c | 5 | ||||
-rw-r--r-- | glib/ghash.c | 13 | ||||
-rw-r--r-- | glib/ghook.c | 5 | ||||
-rw-r--r-- | glib/giochannel.c | 4 | ||||
-rw-r--r-- | glib/giounix.c | 4 | ||||
-rw-r--r-- | glib/glib.h | 134 | ||||
-rw-r--r-- | glib/glist.c | 44 | ||||
-rw-r--r-- | glib/gmain.c | 158 | ||||
-rw-r--r-- | glib/gmem.c | 89 | ||||
-rw-r--r-- | glib/gmessages.c | 115 | ||||
-rw-r--r-- | glib/gnode.c | 36 | ||||
-rw-r--r-- | glib/gprimes.c | 5 | ||||
-rw-r--r-- | glib/grel.c | 5 | ||||
-rw-r--r-- | glib/gscanner.c | 5 | ||||
-rw-r--r-- | glib/gslist.c | 37 | ||||
-rw-r--r-- | glib/gstrfuncs.c | 26 | ||||
-rw-r--r-- | glib/gstring.c | 11 | ||||
-rw-r--r-- | glib/gtimer.c | 4 | ||||
-rw-r--r-- | glib/gtree.c | 18 | ||||
-rw-r--r-- | glib/gutils.c | 34 |
27 files changed, 784 insertions, 112 deletions
diff --git a/glib/Makefile.am b/glib/Makefile.am index d2a10f588..a06082fa3 100644 --- a/glib/Makefile.am +++ b/glib/Makefile.am @@ -1,7 +1,7 @@ ## Process this file with automake to produce Makefile.in # build . first, then SUBDIRS -SUBDIRS = gmodule docs +SUBDIRS = gmodule gthread docs all-recursive-am: all-am # alpha `automake' supports this better #SUBDIRS = . gmodule docs @@ -50,7 +50,8 @@ libglib_la_SOURCES = \ gstring.c \ gstrfuncs.c \ gscanner.c \ - gutils.c + gutils.c \ + gmutex.c include_HEADERS = \ glib.h diff --git a/glib/garray.c b/glib/garray.c index 0247972ec..7f0803e3e 100644 --- a/glib/garray.c +++ b/glib/garray.c @@ -16,6 +16,11 @@ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ + +/* + * MT safe + */ + #include <string.h> #include "glib.h" @@ -40,9 +45,8 @@ static gint g_nearest_pow (gint num); static void g_array_maybe_expand (GRealArray *array, gint len); - static GMemChunk *array_mem_chunk = NULL; - +static G_LOCK_DEFINE(array_mem_chunk); GArray* g_array_new (gboolean zero_terminated, @@ -51,12 +55,14 @@ g_array_new (gboolean zero_terminated, { GRealArray *array; + g_lock (array_mem_chunk); if (!array_mem_chunk) array_mem_chunk = g_mem_chunk_new ("array mem chunk", sizeof (GRealArray), 1024, G_ALLOC_AND_FREE); array = g_chunk_new (GRealArray, array_mem_chunk); + g_unlock (array_mem_chunk); array->data = NULL; array->len = 0; @@ -75,7 +81,9 @@ g_array_free (GArray *array, if (free_segment) g_free (array->data); + g_lock (array_mem_chunk); g_mem_chunk_free (array_mem_chunk, array); + g_unlock (array_mem_chunk); } GArray* @@ -241,9 +249,8 @@ struct _GRealPtrArray static void g_ptr_array_maybe_expand (GRealPtrArray *array, gint len); - static GMemChunk *ptr_array_mem_chunk = NULL; - +static G_LOCK_DEFINE(ptr_array_mem_chunk); GPtrArray* @@ -251,12 +258,14 @@ g_ptr_array_new (void) { GRealPtrArray *array; + g_lock (ptr_array_mem_chunk); if (!ptr_array_mem_chunk) ptr_array_mem_chunk = g_mem_chunk_new ("array mem chunk", sizeof (GRealPtrArray), 1024, G_ALLOC_AND_FREE); array = g_chunk_new (GRealPtrArray, ptr_array_mem_chunk); + g_unlock (ptr_array_mem_chunk); array->pdata = NULL; array->len = 0; @@ -274,7 +283,9 @@ g_ptr_array_free (GPtrArray *array, if (free_segment) g_free (array->pdata); + g_lock (ptr_array_mem_chunk); g_mem_chunk_free (ptr_array_mem_chunk, array); + g_unlock (ptr_array_mem_chunk); } static void diff --git a/glib/gbacktrace.c b/glib/gbacktrace.c index 6aeb8b517..2615ce2b4 100644 --- a/glib/gbacktrace.c +++ b/glib/gbacktrace.c @@ -17,6 +17,11 @@ * Boston, MA 02111-1307, USA. */ +/* + * MT safe ; except for g_on_error_stack_trace, but who wants thread safety + * then + */ + #ifdef HAVE_CONFIG_H #include <config.h> #endif diff --git a/glib/gcache.c b/glib/gcache.c index b2fe77910..800bb2b13 100644 --- a/glib/gcache.c +++ b/glib/gcache.c @@ -16,6 +16,11 @@ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ + +/* + * MT safe + */ + #include "glib.h" @@ -56,7 +61,7 @@ static void g_cache_node_destroy (GCacheNode *node); static GMemChunk *node_mem_chunk = NULL; - +static G_LOCK_DEFINE(node_mem_chunk); GCache* g_cache_new (GCacheNewFunc value_new_func, @@ -193,11 +198,13 @@ g_cache_node_new (gpointer value) { GCacheNode *node; + g_lock (node_mem_chunk); if (!node_mem_chunk) node_mem_chunk = g_mem_chunk_new ("cache node mem chunk", sizeof (GCacheNode), 1024, G_ALLOC_AND_FREE); node = g_chunk_new (GCacheNode, node_mem_chunk); + g_unlock (node_mem_chunk); node->value = value; node->ref_count = 1; @@ -208,5 +215,7 @@ g_cache_node_new (gpointer value) static void g_cache_node_destroy (GCacheNode *node) { + g_lock (node_mem_chunk); g_mem_chunk_free (node_mem_chunk, node); + g_unlock (node_mem_chunk); } diff --git a/glib/gcompletion.c b/glib/gcompletion.c index 62ec244bc..cba2a86cb 100644 --- a/glib/gcompletion.c +++ b/glib/gcompletion.c @@ -17,6 +17,10 @@ * Boston, MA 02111-1307, USA. */ +/* + * MT safe + */ + #include "glib.h" #include <string.h> diff --git a/glib/gdataset.c b/glib/gdataset.c index 7dafc2191..f22b21d59 100644 --- a/glib/gdataset.c +++ b/glib/gdataset.c @@ -18,6 +18,12 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. */ + +/* + * MT safe ; FIXME: might still freeze, watch out, not thoroughly + * looked at yet. + */ + #include <string.h> #include "glib.h" @@ -61,18 +67,24 @@ static inline GQuark g_quark_new (gchar *string); /* --- variables --- */ +static G_LOCK_DEFINE(g_dataset_global); static GHashTable *g_dataset_location_ht = NULL; -static GDataset *g_dataset_cached = NULL; +static GDataset *g_dataset_cached = NULL; /* should this be + threadspecific? */ static GMemChunk *g_dataset_mem_chunk = NULL; static GMemChunk *g_data_mem_chunk = NULL; static GData *g_data_cache = NULL; static guint g_data_cache_length = 0; + +static G_LOCK_DEFINE(g_quark_global); static GHashTable *g_quark_ht = NULL; static gchar **g_quarks = NULL; static GQuark g_quark_seq_id = 0; /* --- functions --- */ + +/* HOLDS: g_dataset_global_lock */ static inline void g_datalist_clear_i (GData **datalist) { @@ -109,13 +121,16 @@ g_datalist_clear (GData **datalist) { g_return_if_fail (datalist != NULL); + g_lock (g_dataset_global); if (!g_dataset_location_ht) g_data_initialize (); while (*datalist) g_datalist_clear_i (datalist); + g_unlock (g_dataset_global); } +/* HOLDS: g_dataset_global_lock */ static inline GDataset* g_dataset_lookup (gconstpointer dataset_location) { @@ -131,6 +146,7 @@ g_dataset_lookup (gconstpointer dataset_location) return dataset; } +/* HOLDS: g_dataset_global_lock */ static void g_dataset_destroy_internal (GDataset *dataset) { @@ -158,6 +174,7 @@ g_dataset_destroy (gconstpointer dataset_location) { g_return_if_fail (dataset_location != NULL); + g_lock (g_dataset_global); if (g_dataset_location_ht) { register GDataset *dataset; @@ -166,8 +183,10 @@ g_dataset_destroy (gconstpointer dataset_location) if (dataset) g_dataset_destroy_internal (dataset); } + g_unlock (g_dataset_global); } +/* HOLDS: g_dataset_global_lock */ static inline void g_data_set_internal (GData **datalist, GQuark key_id, @@ -293,9 +312,10 @@ g_dataset_id_set_data_full (gconstpointer dataset_location, return; } + g_lock (g_dataset_global); if (!g_dataset_location_ht) g_data_initialize (); - + dataset = g_dataset_lookup (dataset_location); if (!dataset) { @@ -308,6 +328,7 @@ g_dataset_id_set_data_full (gconstpointer dataset_location, } g_data_set_internal (&dataset->datalist, key_id, data, destroy_func, dataset); + g_unlock (g_dataset_global); } void @@ -327,10 +348,12 @@ g_datalist_id_set_data_full (GData **datalist, return; } + g_lock (g_dataset_global); if (!g_dataset_location_ht) g_data_initialize (); g_data_set_internal (datalist, key_id, data, destroy_func, NULL); + g_unlock (g_dataset_global); } void @@ -339,6 +362,7 @@ g_dataset_id_remove_no_notify (gconstpointer dataset_location, { g_return_if_fail (dataset_location != NULL); + g_lock (g_dataset_global); if (key_id && g_dataset_location_ht) { GDataset *dataset; @@ -346,7 +370,8 @@ g_dataset_id_remove_no_notify (gconstpointer dataset_location, dataset = g_dataset_lookup (dataset_location); if (dataset) g_data_set_internal (&dataset->datalist, key_id, NULL, (GDestroyNotify) 42, dataset); - } + } + g_unlock (g_dataset_global); } void @@ -355,8 +380,10 @@ g_datalist_id_remove_no_notify (GData **datalist, { g_return_if_fail (datalist != NULL); + g_lock (g_dataset_global); if (key_id && g_dataset_location_ht) g_data_set_internal (datalist, key_id, NULL, (GDestroyNotify) 42, NULL); + g_unlock (g_dataset_global); } gpointer @@ -365,6 +392,7 @@ g_dataset_id_get_data (gconstpointer dataset_location, { g_return_val_if_fail (dataset_location != NULL, NULL); + g_lock (g_dataset_global); if (key_id && g_dataset_location_ht) { register GDataset *dataset; @@ -376,10 +404,14 @@ g_dataset_id_get_data (gconstpointer dataset_location, for (list = dataset->datalist; list; list = list->next) if (list->id == key_id) - return list->data; + { + g_unlock (g_dataset_global); + return list->data; + } } } - + g_unlock (g_dataset_global); + return NULL; } @@ -411,17 +443,23 @@ g_dataset_foreach (gconstpointer dataset_location, g_return_if_fail (dataset_location != NULL); g_return_if_fail (func != NULL); + g_lock (g_dataset_global); if (g_dataset_location_ht) { dataset = g_dataset_lookup (dataset_location); + g_unlock (g_dataset_global); if (dataset) { register GData *list; for (list = dataset->datalist; list; list = list->next) - func (list->id, list->data, user_data); + func (list->id, list->data, user_data); } } + else + { + g_unlock (g_dataset_global); + } } void @@ -446,6 +484,7 @@ g_datalist_init (GData **datalist) *datalist = NULL; } +/* HOLDS: g_dataset_global_lock */ static void g_data_initialize (void) { @@ -468,12 +507,15 @@ g_data_initialize (void) GQuark g_quark_try_string (const gchar *string) { + GQuark quark = 0; g_return_val_if_fail (string != NULL, 0); + g_lock (g_quark_global); if (g_quark_ht) - return (gulong) g_hash_table_lookup (g_quark_ht, string); - else - return 0; + quark = GPOINTER_TO_UINT (g_hash_table_lookup (g_quark_ht, string)); + g_unlock (g_quark_global); + + return quark; } GQuark @@ -483,6 +525,7 @@ g_quark_from_string (const gchar *string) g_return_val_if_fail (string != NULL, 0); + g_lock (g_quark_global); if (g_quark_ht) quark = (gulong) g_hash_table_lookup (g_quark_ht, string); else @@ -493,6 +536,7 @@ g_quark_from_string (const gchar *string) if (!quark) quark = g_quark_new (g_strdup (string)); + g_unlock (g_quark_global); return quark; } @@ -504,6 +548,7 @@ g_quark_from_static_string (const gchar *string) g_return_val_if_fail (string != NULL, 0); + g_lock (g_quark_global); if (g_quark_ht) quark = (gulong) g_hash_table_lookup (g_quark_ht, string); else @@ -514,19 +559,24 @@ g_quark_from_static_string (const gchar *string) if (!quark) quark = g_quark_new ((gchar*) string); - + g_unlock (g_quark_global); + return quark; } gchar* g_quark_to_string (GQuark quark) { + gchar* result = NULL; + g_lock (g_quark_global); if (quark > 0 && quark <= g_quark_seq_id) - return g_quarks[quark - 1]; - else - return NULL; + result = g_quarks[quark - 1]; + g_unlock (g_quark_global); + + return result; } +/* HOLDS: g_quark_global_lock */ static inline GQuark g_quark_new (gchar *string) { diff --git a/glib/gdate.c b/glib/gdate.c index 69c337def..7c60e23d9 100644 --- a/glib/gdate.c +++ b/glib/gdate.c @@ -16,6 +16,11 @@ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ + +/* + * MT safe + */ + #include "glib.h" #include <time.h> @@ -383,6 +388,8 @@ g_date_clear (GDate *d, guint ndates) memset (d, 0x0, ndates*sizeof (GDate)); } +static G_LOCK_DEFINE(g_date_global); + /* These are for the parser, output to the user should use * * g_date_strftime () - this creates more never-freed memory to annoy * all those memory debugger users. :-) @@ -429,6 +436,7 @@ typedef struct _GDateParseTokens GDateParseTokens; #define NUM_LEN 10 +/* HOLDS: g_date_global_lock */ static void g_date_fill_parse_tokens (const gchar *str, GDateParseTokens *pt) { @@ -488,7 +496,7 @@ g_date_fill_parse_tokens (const gchar *str, GDateParseTokens *pt) if (found != NULL) { pt->month = i; - return; + return; } } @@ -502,12 +510,13 @@ g_date_fill_parse_tokens (const gchar *str, GDateParseTokens *pt) return; } } - + ++i; - } + } } } +/* HOLDS: g_date_global_lock */ static void g_date_prepare_to_parse (const gchar *str, GDateParseTokens *pt) { @@ -641,6 +650,8 @@ g_date_set_parse (GDate *d, /* set invalid */ g_date_clear (d, 1); + g_lock (g_date_global); + g_date_prepare_to_parse (str, &pt); #ifdef G_ENABLE_DEBUG @@ -649,7 +660,11 @@ g_date_set_parse (GDate *d, #endif - if (pt.num_ints == 4) return; /* presumably a typo; bail out. */ + if (pt.num_ints == 4) + { + g_unlock (g_date_global); + return; /* presumably a typo; bail out. */ + } if (pt.num_ints > 1) { @@ -765,6 +780,7 @@ g_date_set_parse (GDate *d, else g_message ("Rejected DMY %u %u %u", day, m, y); #endif + g_unlock (g_date_global); } void diff --git a/glib/gerror.c b/glib/gerror.c index 6aeb8b517..2615ce2b4 100644 --- a/glib/gerror.c +++ b/glib/gerror.c @@ -17,6 +17,11 @@ * Boston, MA 02111-1307, USA. */ +/* + * MT safe ; except for g_on_error_stack_trace, but who wants thread safety + * then + */ + #ifdef HAVE_CONFIG_H #include <config.h> #endif diff --git a/glib/ghash.c b/glib/ghash.c index 4ab82b3fa..724036388 100644 --- a/glib/ghash.c +++ b/glib/ghash.c @@ -16,6 +16,11 @@ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ + +/* + * MT safe + */ + #include "glib.h" @@ -52,6 +57,8 @@ static void g_hash_node_destroy (GHashNode *hash_node); static void g_hash_nodes_destroy (GHashNode *hash_node); +static G_LOCK_DEFINE(g_hash_global); + static GMemChunk *node_mem_chunk = NULL; static GHashNode *node_free_list = NULL; @@ -338,6 +345,7 @@ g_hash_node_new (gpointer key, { GHashNode *hash_node; + g_lock (g_hash_global); if (node_free_list) { hash_node = node_free_list; @@ -352,6 +360,7 @@ g_hash_node_new (gpointer key, hash_node = g_chunk_new (GHashNode, node_mem_chunk); } + g_unlock (g_hash_global); hash_node->key = key; hash_node->value = value; @@ -363,8 +372,10 @@ g_hash_node_new (gpointer key, static void g_hash_node_destroy (GHashNode *hash_node) { + g_lock (g_hash_global); hash_node->next = node_free_list; node_free_list = hash_node; + g_unlock (g_hash_global); } static void @@ -380,6 +391,8 @@ g_hash_nodes_destroy (GHashNode *hash_node) while (node->next) node = node->next; + g_lock (g_hash_global); node->next = node_free_list; node_free_list = hash_node; + g_unlock (g_hash_global); } diff --git a/glib/ghook.c b/glib/ghook.c index 47a2874a4..b683b7c31 100644 --- a/glib/ghook.c +++ b/glib/ghook.c @@ -19,6 +19,11 @@ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ + +/* + * MT safe + */ + #include "glib.h" diff --git a/glib/giochannel.c b/glib/giochannel.c index fa4262602..0693a084b 100644 --- a/glib/giochannel.c +++ b/glib/giochannel.c @@ -20,6 +20,10 @@ * Boston, MA 02111-1307, USA. */ +/* + * MT safe + */ + #include "glib.h" #include <unistd.h> diff --git a/glib/giounix.c b/glib/giounix.c index 5e605a478..82944be89 100644 --- a/glib/giounix.c +++ b/glib/giounix.c @@ -20,6 +20,10 @@ * Boston, MA 02111-1307, USA. */ +/* + * MT safe + */ + #include "glib.h" #include <sys/types.h> #include <unistd.h> diff --git a/glib/glib.h b/glib/glib.h index 33fa042e9..d4d1aaa77 100644 --- a/glib/glib.h +++ b/glib/glib.h @@ -2597,6 +2597,140 @@ gint gwin_closedir (DIR *dir); #endif /* NATIVE_WIN32 */ +/* functions for thread support for glib. */ + +typedef struct _GMutex GMutex; +typedef struct _GCond GCond; +typedef struct _GPrivate GPrivate; +typedef struct _GStaticPrivate GStaticPrivate; + +typedef struct _GThreadFunctions GThreadFunctions; +struct _GThreadFunctions +{ + GMutex* (*mutex_new) (void); + void (*mutex_lock) (GMutex* mutex); + gboolean (*mutex_trylock) (GMutex* mutex); + void (*mutex_unlock) (GMutex* mutex); + void (*mutex_free) (GMutex* mutex); + GCond* (*cond_new) (void); + void (*cond_signal) (GCond* cond); + void (*cond_broadcast) (GCond* cond); + void (*cond_wait) (GCond* cond, GMutex* mutex); + gboolean (*cond_timed_wait) (GCond* cond, GMutex* mutex, + GTimeVal *end_time); + void (*cond_free) (GCond* cond); + GPrivate* (*private_new) (GDestroyNotify destructor); + gpointer (*private_get) (GPrivate* private); + void (*private_set) (GPrivate* private, gpointer value); +}; + +GUTILS_C_VAR GThreadFunctions g_thread_functions_for_glib_use; +GUTILS_C_VAR gboolean g_thread_use_default_impl; +GUTILS_C_VAR gboolean g_thread_supported; + +/* initializes the mutex/cond/private implementation for glib, might + * only be called once, and must not be called directly or indirectly + * from another glib-function, e.g. as a callback. */ +void g_thread_init(GThreadFunctions* init); + +/* Internal functions for fallback static mutex implementation + * Please don't use it directly + */ +GMutex* g_static_mutex_get_mutex_impl(GMutex** mutex); + +#define G_USE_THREAD_FUNC_UNCOND(name,arg) \ + (*g_thread_functions_for_glib_use.name)arg +#define G_USE_THREAD_FUNC(name,fail,arg) \ + (g_thread_supported ? G_USE_THREAD_FUNC_UNCOND(name,arg) : (fail)) + +/* keep in mind, all those mutexes and static mutexes are not + * recursive in general, don't rely on that */ +#define g_mutex_new() G_USE_THREAD_FUNC_UNCOND(mutex_new,()) +#define g_mutex_lock(mutex) G_USE_THREAD_FUNC(mutex_lock,(void)0,(mutex)) +#define g_mutex_trylock(mutex) G_USE_THREAD_FUNC(mutex_trylock,TRUE,(mutex)) +#define g_mutex_unlock(mutex) G_USE_THREAD_FUNC(mutex_unlock,(void)0,(mutex)) +#define g_mutex_free(mutex) G_USE_THREAD_FUNC(mutex_free,(void)0,(mutex)) +#define g_cond_new() G_USE_THREAD_FUNC_UNCOND(cond_new,()) +#define g_cond_signal(cond) G_USE_THREAD_FUNC(cond_signal,(void)0,(cond)) +#define g_cond_broadcast(cond) G_USE_THREAD_FUNC(cond_broadcast,(void)0,(cond)) +#define g_cond_wait(cond,mutex) G_USE_THREAD_FUNC(cond_wait,(void)0,(cond,mutex)) +#define g_cond_timed_wait(cond,mutex,abs_time) \ + G_USE_THREAD_FUNC(cond_timed_wait,TRUE,(cond,mutex,abs_time)) +#define g_cond_free(cond) G_USE_THREAD_FUNC(cond_free,(void)0,(cond)) + +#define g_private_new(destructor) \ + G_USE_THREAD_FUNC_UNCOND(private_new,(destructor)) +#define g_private_get(private) \ + G_USE_THREAD_FUNC(private_get,((gpointer)private),(private)) +#define g_private_set(private,value) \ + G_USE_THREAD_FUNC(private_set,(void)(private=(GPrivate *)(value)), \ + (private,value)) + +/* GStaticMutex'es can be statically initialized with the value + * G_STATIC_MUTEX_INIT, and then they can directly be used, that is + * much easier, than having to explicitly allocate the mutex before + * use */ +#define g_static_mutex_lock(mutex) \ + g_mutex_lock( g_static_mutex_get_mutex(mutex) ) +#define g_static_mutex_trylock(mutex) \ + g_mutex_trylock( g_static_mutex_get_mutex(mutex) ) +#define g_static_mutex_unlock(mutex) \ + g_mutex_unlock( g_static_mutex_get_mutex(mutex) ) + +struct _GStaticPrivate +{ + guint index; +}; + +#define G_STATIC_PRIVATE_INIT { 0 } + +gpointer g_static_private_get (GStaticPrivate* private); +void g_static_private_set (GStaticPrivate *private, + gpointer data, + GDestroyNotify notify); + +/* these are some convenience macros, for using StaticMutex'es, you + * define them by G_LOCK_DEFINE(name), where name could for example be the + * name of the protected varibale, and you (un)lock them with + * g_(un)lock(name) */ +#define g_lock_name(name) (name ## _lock) +#define G_LOCK_DEFINE(name) GStaticMutex g_lock_name(name)=G_STATIC_MUTEX_INIT + +#ifdef G_DEBUG_LOCKS +#define g_lock(name) G_STMT_START{ \ + g_log (G_LOG_DOMAIN, \ + G_LOG_LEVEL_MESSAGE, \ + "file %s: line %d (%s): locking: %s ", \ + __FILE__, \ + __LINE__, \ + __PRETTY_FUNCTION__, \ + #name); \ + g_static_mutex_lock(g_lock_name(name)); \ + }G_STMT_END +#define g_unlock(name) G_STMT_START{ \ + g_log (G_LOG_DOMAIN, \ + G_LOG_LEVEL_MESSAGE, \ + "file %s: line %d (%s): unlocking: %s ", \ + __FILE__, \ + __LINE__, \ + __PRETTY_FUNCTION__, \ + #name); \ + g_static_mutex_unlock(g_lock_name(name)); \ + }G_STMT_END +#define g_trylock(name) G_STMT_START{ \ + g_log (G_LOG_DOMAIN, \ + G_LOG_LEVEL_MESSAGE, \ + "file %s: line %d (%s): try locking: %s ", \ + __FILE__, \ + __LINE__, \ + __PRETTY_FUNCTION__, \ + #name); \ + }G_STMT_END, g_static_mutex_trylock(g_lock_name(name)) +#else /* !G_DEBUG_LOCKS */ +#define g_lock(name) g_static_mutex_lock(g_lock_name(name)) +#define g_unlock(name) g_static_mutex_unlock(g_lock_name(name)) +#define g_trylock(name) g_static_mutex_trylock(g_lock_name(name)) +#endif #ifdef __cplusplus } diff --git a/glib/glist.c b/glib/glist.c index 41a09dd18..e74dee872 100644 --- a/glib/glist.c +++ b/glib/glist.c @@ -16,6 +16,11 @@ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ + +/* + * MT safe + */ + #include "glib.h" @@ -31,9 +36,11 @@ struct _GAllocator /* from gmem.c */ }; static GAllocator *current_allocator = NULL; +static G_LOCK_DEFINE(current_allocator); -void -g_list_push_allocator (GAllocator *allocator) +/* HOLDS: current_allocator_lock */ +static void +g_list_validate_allocator (GAllocator *allocator) { g_return_if_fail (allocator != NULL); g_return_if_fail (allocator->is_unused == TRUE); @@ -58,13 +65,22 @@ g_list_push_allocator (GAllocator *allocator) } allocator->is_unused = FALSE; +} + +void +g_list_push_allocator(GAllocator *allocator) +{ + g_list_validate_allocator ( allocator ); + g_lock (current_allocator); allocator->last = current_allocator; current_allocator = allocator; + g_unlock (current_allocator); } void g_list_pop_allocator (void) { + g_lock (current_allocator); if (current_allocator) { GAllocator *allocator; @@ -74,6 +90,7 @@ g_list_pop_allocator (void) allocator->last = NULL; allocator->is_unused = TRUE; } + g_unlock (current_allocator); } GList* @@ -81,9 +98,15 @@ g_list_alloc (void) { GList *list; + g_lock (current_allocator); if (!current_allocator) - g_list_push_allocator (g_allocator_new ("GLib default GList allocator", 1024)); - + { + GAllocator *allocator = g_allocator_new ("GLib default GList allocator", + 1024); + g_list_validate_allocator (allocator); + allocator->last = NULL; + current_allocator = allocator; + } if (!current_allocator->free_lists) { list = g_chunk_new (GList, current_allocator->mem_chunk); @@ -103,6 +126,7 @@ g_list_alloc (void) current_allocator->free_lists = list->next; } } + g_unlock (current_allocator); list->next = NULL; list->prev = NULL; @@ -112,23 +136,31 @@ g_list_alloc (void) void g_list_free (GList *list) { +#if 0 if (list) { - list->data = list->next; + list->data = list->next; + g_lock (current_allocator); list->next = current_allocator->free_lists; current_allocator->free_lists = list; + g_unlock (current_allocator); } +#endif } void g_list_free_1 (GList *list) { +#if 0 if (list) { - list->data = NULL; + list->data = NULL; + g_lock (current_allocator); list->next = current_allocator->free_lists; current_allocator->free_lists = list; + g_unlock (current_allocator); } +#endif } GList* diff --git a/glib/gmain.c b/glib/gmain.c index 1f13e9097..5d3ae8d46 100644 --- a/glib/gmain.c +++ b/glib/gmain.c @@ -20,9 +20,14 @@ * Boston, MA 02111-1307, USA. */ +/* + * MT safe + */ + #include "glib.h" #include <sys/time.h> #include <unistd.h> +#include <errno.h> #include "config.h" /* Types */ @@ -65,9 +70,12 @@ struct _GPollRec { /* Forward declarations */ -static void g_main_poll (gint timeout, - gboolean use_priority, - gint priority); +static void g_main_poll (gint timeout, + gboolean use_priority, + gint priority); +static void g_main_poll_add_unlocked (gint priority, + GPollFD *fd); + static gboolean g_timeout_prepare (gpointer source_data, GTimeVal *current_time, gint *timeout); @@ -90,6 +98,11 @@ static gboolean g_idle_dispatch (gpointer source_data, static GSList *pending_dispatches = NULL; static GHookList source_list = { 0 }; +/* The following lock is used for both the list of sources + * and the list of poll records + */ +static G_LOCK_DEFINE (main_loop); + static GSourceFuncs timeout_funcs = { g_timeout_prepare, g_timeout_check, @@ -104,6 +117,17 @@ static GSourceFuncs idle_funcs = { (GDestroyNotify)g_free }; +static GPollRec *poll_records = NULL; +static GPollRec *poll_free_list = NULL; +static GMemChunk *poll_chunk; +static guint n_poll_records = 0; + +/* this pipe is used to wake up the main loop when a source is added. + */ +static gint wake_up_pipe[2] = { -1, -1 }; +static GPollFD wake_up_rec; +static gboolean poll_waiting = FALSE; + #ifdef HAVE_POLL static GPollFunc poll_func = (GPollFunc)poll; #else @@ -205,8 +229,11 @@ g_source_add (gint priority, gpointer user_data, GDestroyNotify notify) { + guint return_val; GSource *source; + g_lock (main_loop); + if (!source_list.is_setup) g_hook_list_init (&source_list, sizeof(GSource)); @@ -224,31 +251,55 @@ g_source_add (gint priority, if (can_recurse) source->hook.flags |= G_SOURCE_CAN_RECURSE; - return source->hook.hook_id; + return_val = source->hook.hook_id; + + /* Now wake up the main loop if it is waiting in the poll() */ + + if (poll_waiting) + { + poll_waiting = FALSE; + write (wake_up_pipe[1], "A", 1); + } + + g_unlock (main_loop); + + return return_val; } void g_source_remove (guint tag) { - GHook *hook = g_hook_get (&source_list, tag); + GHook *hook; + + g_lock (main_loop); + + hook = g_hook_get (&source_list, tag); if (hook) { GSource *source = (GSource *)hook; ((GSourceFuncs *)source->hook.func)->destroy (source->source_data); g_hook_destroy_link (&source_list, hook); } + + g_unlock (main_loop); } void g_source_remove_by_user_data (gpointer user_data) { - GHook *hook = g_hook_find_data (&source_list, TRUE, user_data); + GHook *hook; + + g_lock (main_loop); + + hook = g_hook_find_data (&source_list, TRUE, user_data); if (hook) { GSource *source = (GSource *)hook; ((GSourceFuncs *)source->hook.func)->destroy (source->source_data); g_hook_destroy_link (&source_list, hook); } + + g_unlock (main_loop); } static gboolean @@ -262,7 +313,11 @@ g_source_find_source_data (GHook *hook, void g_source_remove_by_source_data (gpointer source_data) { - GHook *hook = g_hook_find (&source_list, TRUE, + GHook *hook; + + g_lock (main_loop); + + hook = g_hook_find (&source_list, TRUE, g_source_find_source_data, source_data); if (hook) { @@ -270,6 +325,8 @@ g_source_remove_by_source_data (gpointer source_data) ((GSourceFuncs *)source->hook.func)->destroy (source->source_data); g_hook_destroy_link (&source_list, hook); } + + g_unlock (main_loop); } void g_get_current_time (GTimeVal *result) @@ -279,6 +336,7 @@ void g_get_current_time (GTimeVal *result) /* Running the main loop */ +/* HOLDS: main_loop_lock */ static void g_main_dispatch (GTimeVal *current_time) { @@ -294,10 +352,20 @@ g_main_dispatch (GTimeVal *current_time) if (G_HOOK_IS_VALID (source)) { + gboolean (*dispatch) (gpointer, GTimeVal *, gpointer); + gpointer hook_data = source->hook.data; + gpointer source_data = source->source_data; + + dispatch = ((GSourceFuncs *)source->hook.func)->dispatch; + source->hook.flags |= G_HOOK_FLAG_IN_CALL; - need_destroy = !((GSourceFuncs *)source->hook.func)->dispatch (source->source_data, - current_time, - source->hook.data); + + g_unlock (main_loop); + need_destroy = ! dispatch(source_data, + current_time, + hook_data); + g_lock (main_loop); + source->hook.flags &= ~G_HOOK_FLAG_IN_CALL; if (need_destroy) @@ -320,10 +388,13 @@ g_main_iterate (gboolean block, gboolean dispatch) gint nready = 0; gint current_priority = 0; gint timeout; + gboolean retval = FALSE; g_return_val_if_fail (!block || dispatch, FALSE); g_get_current_time (¤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; @@ -539,12 +634,28 @@ void g_main_poll_add (gint priority, GPollFD *fd) { + g_lock (main_loop); + g_main_poll_add_unlocked (priority, fd); + g_unlock (main_loop); +} + +static void +g_main_poll_add_unlocked (gint priority, + GPollFD *fd) +{ GPollRec *lastrec, *pollrec, *newrec; if (!poll_chunk) poll_chunk = g_mem_chunk_create (GPollRec, 32, G_ALLOC_ONLY); - newrec = g_chunk_new (GPollRec, poll_chunk); + if (poll_free_list) + { + newrec = poll_free_list; + poll_free_list = newrec->next; + } + else + newrec = g_chunk_new (GPollRec, poll_chunk); + newrec->fd = fd; newrec->priority = priority; @@ -564,6 +675,8 @@ g_main_poll_add (gint priority, newrec->next = pollrec; n_poll_records++; + + g_unlock (main_loop); } void @@ -571,6 +684,8 @@ g_main_poll_remove (GPollFD *fd) { GPollRec *pollrec, *lastrec; + g_lock (main_loop); + lastrec = NULL; pollrec = poll_records; @@ -585,12 +700,15 @@ g_main_poll_remove (GPollFD *fd) pollrec->next = poll_free_list; poll_free_list = pollrec; + + n_poll_records--; + break; } lastrec = pollrec; pollrec = pollrec->next; } - n_poll_records--; + g_unlock (main_loop); } void diff --git a/glib/gmem.c b/glib/gmem.c index c29ee660f..a4907ffca 100644 --- a/glib/gmem.c +++ b/glib/gmem.c @@ -17,6 +17,10 @@ * Boston, MA 02111-1307, USA. */ +/* + * MT safe + */ + #ifdef HAVE_CONFIG_H #include <config.h> #endif @@ -48,8 +52,12 @@ */ #if defined(ENABLE_MEM_PROFILE) && defined(ENABLE_MEM_PROFILE_EXCLUDES_MEM_CHUNKS) -#define ENTER_MEM_CHUNK_ROUTINE() allocating_for_mem_chunk++ -#define LEAVE_MEM_CHUNK_ROUTINE() allocating_for_mem_chunk-- +#define ENTER_MEM_CHUNK_ROUTINE() \ + g_static_set (allocating_for_mem_chunk, \ + g_static_get (allocating_for_mem_chunk) + 1) +#define ENTER_MEM_CHUNK_ROUTINE() \ + g_static_set (allocating_for_mem_chunk, \ + g_static_get (allocating_for_mem_chunk) - 1) #else #define ENTER_MEM_CHUNK_ROUTINE() #define LEAVE_MEM_CHUNK_ROUTINE() @@ -117,13 +125,19 @@ static gint g_mem_chunk_area_search (GMemArea *a, gchar *addr); +/* here we can't use StaticMutexes, as they depend upon a working + * g_malloc, the same holds true for StaticPrivate */ +static GMutex* mem_chunks_lock = NULL; static GRealMemChunk *mem_chunks = NULL; #ifdef ENABLE_MEM_PROFILE +static GMutex* mem_profile_lock; static gulong allocations[MEM_PROFILE_TABLE_SIZE] = { 0 }; static gulong allocated_mem = 0; static gulong freed_mem = 0; -static gint allocating_for_mem_chunk = 0; +static GPrivate* allocating_for_mem_chunk = NULL; +#define IS_IN_MEM_CHUNK_ROUTINE() \ + GPOINTER_TO_UINT (g_static_get (allocating_for_mem_chunk)) #endif /* ENABLE_MEM_PROFILE */ @@ -174,8 +188,9 @@ g_malloc (gulong size) *t = size; #ifdef ENABLE_MEM_PROFILE + g_mutex_lock (mem_profile_lock); # ifdef ENABLE_MEM_PROFILE_EXCLUDES_MEM_CHUNKS - if(!allocating_for_mem_chunk) { + if(!IS_IN_MEM_CHUNK_ROUTINE()) { # endif if (size <= MEM_PROFILE_TABLE_SIZE - 1) allocations[size-1] += 1; @@ -185,6 +200,7 @@ g_malloc (gulong size) # ifdef ENABLE_MEM_PROFILE_EXCLUDES_MEM_CHUNKS } # endif + g_mutex_unlock (mem_profile_lock); #endif /* ENABLE_MEM_PROFILE */ #endif /* ENABLE_MEM_PROFILE || ENABLE_MEM_CHECK */ @@ -237,8 +253,9 @@ g_malloc0 (gulong size) *t = size; # ifdef ENABLE_MEM_PROFILE + g_mutex_lock (mem_profile_lock); # ifdef ENABLE_MEM_PROFILE_EXCLUDES_MEM_CHUNKS - if(!allocating_for_mem_chunk) { + if(!IS_IN_MEM_CHUNK_ROUTINE()) { # endif if (size <= (MEM_PROFILE_TABLE_SIZE - 1)) allocations[size-1] += 1; @@ -248,8 +265,9 @@ g_malloc0 (gulong size) # ifdef ENABLE_MEM_PROFILE_EXCLUDES_MEM_CHUNKS } # endif + g_mutex_unlock (mem_profile_lock); # endif /* ENABLE_MEM_PROFILE */ -#endif /* ENABLE_MEM_PROFILE */ +#endif /* ENABLE_MEM_PROFILE || ENABLE_MEM_CHECK */ return p; @@ -286,7 +304,9 @@ g_realloc (gpointer mem, #if defined(ENABLE_MEM_PROFILE) || defined(ENABLE_MEM_CHECK) t = (gulong*) ((guchar*) mem - SIZEOF_LONG); #ifdef ENABLE_MEM_PROFILE + g_mutex_lock (mem_profile); freed_mem += *t; + g_mutex_unlock (mem_profile); #endif /* ENABLE_MEM_PROFILE */ mem = t; #endif /* ENABLE_MEM_PROFILE || ENABLE_MEM_CHECK */ @@ -321,8 +341,9 @@ g_realloc (gpointer mem, *t = size; #ifdef ENABLE_MEM_PROFILE + g_mutex_lock (mem_profile_lock); #ifdef ENABLE_MEM_PROFILE_EXCLUDES_MEM_CHUNKS - if(!allocating_for_mem_chunk) { + if(!IS_IN_MEM_CHUNK_ROUTINE()) { #endif if (size <= (MEM_PROFILE_TABLE_SIZE - 1)) allocations[size-1] += 1; @@ -332,6 +353,7 @@ g_realloc (gpointer mem, #ifdef ENABLE_MEM_PROFILE_EXCLUDES_MEM_CHUNKS } #endif + g_mutex_unlock (mem_profile_lock); #endif /* ENABLE_MEM_PROFILE */ #endif /* ENABLE_MEM_PROFILE || ENABLE_MEM_CHECK */ @@ -352,8 +374,10 @@ g_free (gpointer mem) #if defined(ENABLE_MEM_PROFILE) || defined(ENABLE_MEM_CHECK) t = (gulong*) ((guchar*) mem - SIZEOF_LONG); size = *t; -#ifdef ENABLE_MEM_PROFILE +#ifdef ENABLE_MEM_PROFILE + g_mutex_lock (mem_profile); freed_mem += size; + g_mutex_unlock (mem_profile); #endif /* ENABLE_MEM_PROFILE */ mem = t; #endif /* ENABLE_MEM_PROFILE || ENABLE_MEM_CHECK */ @@ -380,19 +404,29 @@ g_mem_profile (void) { #ifdef ENABLE_MEM_PROFILE gint i; - + gulong local_allocations[MEM_PROFILE_TABLE_SIZE]; + gulong local_allocated_mem; + gulong local_freed_mem; + + g_mutex_lock (mem_profile); + for (i = 0; i < (MEM_PROFILE_TABLE_SIZE - 1); i++) + local_allocations[i] = allocations[i]; + local_allocated_mem = allocated_mem; + local_freed_mem = freed_mem; + g_mutex_unlock (mem_profile); + for (i = 0; i < (MEM_PROFILE_TABLE_SIZE - 1); i++) - if (allocations[i] > 0) + if (local_allocations[i] > 0) g_log (g_log_domain_glib, G_LOG_LEVEL_INFO, - "%lu allocations of %d bytes\n", allocations[i], i + 1); + "%lu allocations of %d bytes\n", local_allocations[i], i + 1); - if (allocations[MEM_PROFILE_TABLE_SIZE - 1] > 0) + if (local_allocations[MEM_PROFILE_TABLE_SIZE - 1] > 0) g_log (g_log_domain_glib, G_LOG_LEVEL_INFO, "%lu allocations of greater than %d bytes\n", - allocations[MEM_PROFILE_TABLE_SIZE - 1], MEM_PROFILE_TABLE_SIZE - 1); - g_log (g_log_domain_glib, G_LOG_LEVEL_INFO, "%lu bytes allocated\n", allocated_mem); - g_log (g_log_domain_glib, G_LOG_LEVEL_INFO, "%lu bytes freed\n", freed_mem); - g_log (g_log_domain_glib, G_LOG_LEVEL_INFO, "%lu bytes in use\n", allocated_mem - freed_mem); + local_allocations[MEM_PROFILE_TABLE_SIZE - 1], MEM_PROFILE_TABLE_SIZE - 1); + g_log (g_log_domain_glib, G_LOG_LEVEL_INFO, "%lu bytes allocated\n", local_allocated_mem); + g_log (g_log_domain_glib, G_LOG_LEVEL_INFO, "%lu bytes freed\n", local_freed_mem); + g_log (g_log_domain_glib, G_LOG_LEVEL_INFO, "%lu bytes in use\n", local_allocated_mem - local_freed_mem); #endif /* ENABLE_MEM_PROFILE */ } @@ -460,11 +494,13 @@ g_mem_chunk_new (gchar *name, mem_chunk->area_size += mem_chunk->atom_size - (mem_chunk->area_size % mem_chunk->atom_size); */ + g_mutex_lock (mem_chunks_lock); mem_chunk->next = mem_chunks; mem_chunk->prev = NULL; if (mem_chunks) mem_chunks->prev = mem_chunk; mem_chunks = mem_chunk; + g_mutex_unlock (mem_chunks_lock); LEAVE_MEM_CHUNK_ROUTINE(); @@ -497,8 +533,10 @@ g_mem_chunk_destroy (GMemChunk *mem_chunk) if (rmem_chunk->prev) rmem_chunk->prev->next = rmem_chunk->next; + g_mutex_lock (mem_chunks_lock); if (rmem_chunk == mem_chunks) mem_chunks = mem_chunks->next; + g_mutex_unlock (mem_chunks_lock); if (rmem_chunk->type == G_ALLOC_AND_FREE) g_tree_destroy (rmem_chunk->mem_tree); @@ -826,21 +864,26 @@ g_mem_chunk_info (void) gint count; count = 0; + g_mutex_lock (mem_chunks_lock); mem_chunk = mem_chunks; while (mem_chunk) { count += 1; mem_chunk = mem_chunk->next; } + g_mutex_unlock (mem_chunks_lock); g_log (g_log_domain_glib, G_LOG_LEVEL_INFO, "%d mem chunks\n", count); + g_mutex_lock (mem_chunks_lock); mem_chunk = mem_chunks; + g_mutex_unlock (mem_chunks_lock); + while (mem_chunk) { g_mem_chunk_print ((GMemChunk*) mem_chunk); mem_chunk = mem_chunk->next; - } + } } void @@ -848,7 +891,9 @@ g_blow_chunks (void) { GRealMemChunk *mem_chunk; + g_mutex_lock (mem_chunks_lock); mem_chunk = mem_chunks; + g_mutex_unlock (mem_chunks_lock); while (mem_chunk) { g_mem_chunk_clean ((GMemChunk*) mem_chunk); @@ -940,3 +985,13 @@ g_allocator_free (GAllocator *allocator) g_free (allocator); } + +void +g_mem_init (void) +{ + mem_chunks_lock = g_mutex_new(); +#ifdef ENABLE_MEM_PROFILE + mem_profile_lock = g_mutex_new(); + allocating_for_mem_chunk = g_private_new(NULL); +#endif +} diff --git a/glib/gmessages.c b/glib/gmessages.c index e0c6eacb1..eb8aed7a8 100644 --- a/glib/gmessages.c +++ b/glib/gmessages.c @@ -17,6 +17,10 @@ * Boston, MA 02111-1307, USA. */ +/* + * MT safe + */ + #ifdef HAVE_CONFIG_H #include <config.h> #endif @@ -31,7 +35,7 @@ #endif #ifdef NATIVE_WIN32 -/* Just use stdio. If we're out of memroy, we're hosed anyway. */ +/* Just use stdio. If we're out of memory, we're hosed anyway. */ #undef write static inline int @@ -67,6 +71,9 @@ struct _GLogHandler /* --- variables --- */ + +static GMutex* g_messages_lock = NULL; + const gchar *g_log_domain_glib = "GLib"; static GLogDomain *g_log_domains = NULL; static GLogLevelFlags g_log_always_fatal = G_LOG_FATAL_MASK; @@ -76,20 +83,27 @@ static GErrorFunc glib_error_func = NULL; static GWarningFunc glib_warning_func = NULL; static GPrintFunc glib_message_func = NULL; +static GPrivate* g_log_depth = NULL; + /* --- functions --- */ static inline GLogDomain* g_log_find_domain (const gchar *log_domain) { register GLogDomain *domain; - + + g_mutex_lock (g_messages_lock); domain = g_log_domains; while (domain) { if (strcmp (domain->log_domain, log_domain) == 0) - return domain; + { + g_mutex_unlock (g_messages_lock); + return domain; + } domain = domain->next; } + g_mutex_unlock (g_messages_lock); return NULL; } @@ -102,8 +116,11 @@ g_log_domain_new (const gchar *log_domain) domain->log_domain = g_strdup (log_domain); domain->fatal_mask = G_LOG_FATAL_MASK; domain->handlers = NULL; + + g_mutex_lock (g_messages_lock); domain->next = g_log_domains; g_log_domains = domain; + g_mutex_unlock (g_messages_lock); return domain; } @@ -116,7 +133,9 @@ g_log_domain_check_free (GLogDomain *domain) { register GLogDomain *last, *work; - last = NULL; + last = NULL; + + g_mutex_lock (g_messages_lock); work = g_log_domains; while (work) { @@ -131,7 +150,8 @@ g_log_domain_check_free (GLogDomain *domain) break; } work = work->next; - } + } + g_mutex_unlock (g_messages_lock); } } @@ -170,8 +190,10 @@ g_log_set_always_fatal (GLogLevelFlags fatal_mask) /* remove bogus flag */ fatal_mask &= ~G_LOG_FLAG_FATAL; + g_mutex_lock (g_messages_lock); old_mask = g_log_always_fatal; g_log_always_fatal = fatal_mask; + g_mutex_unlock (g_messages_lock); return old_mask; } @@ -223,7 +245,9 @@ g_log_set_handler (const gchar *log_domain, domain = g_log_domain_new (log_domain); handler = g_new (GLogHandler, 1); + g_mutex_lock (g_messages_lock); handler->id = ++handler_id; + g_mutex_unlock (g_messages_lock); handler->log_level = log_levels; handler->log_func = log_func; handler->data = user_data; @@ -311,19 +335,25 @@ g_logv (const gchar *log_domain, test_level = 1 << i; if (log_level & test_level) { - static guint g_log_depth = 0; + guint depth = GPOINTER_TO_UINT (g_private_get (g_log_depth)); GLogDomain *domain; GLogFunc log_func; gpointer data = NULL; domain = g_log_find_domain (log_domain ? log_domain : ""); - if (g_log_depth++) + if (depth) test_level |= G_LOG_FLAG_RECURSION; - if ((((domain ? domain->fatal_mask : G_LOG_FATAL_MASK) | g_log_always_fatal) & - test_level) != 0) - test_level |= G_LOG_FLAG_FATAL; + depth++; + g_private_set (g_log_depth, GUINT_TO_POINTER (depth)); + + g_mutex_lock (g_messages_lock); + if ((((domain ? domain->fatal_mask : G_LOG_FATAL_MASK) | + g_log_always_fatal) & test_level) != 0) + test_level |= G_LOG_FLAG_FATAL; + g_mutex_unlock (g_messages_lock); + log_func = g_log_domain_get_handler (domain, test_level, &data); log_func (log_domain, test_level, buffer, data); @@ -332,7 +362,8 @@ g_logv (const gchar *log_domain, if (test_level & G_LOG_FLAG_FATAL) abort (); - g_log_depth--; + depth--; + g_private_set (g_log_depth, GUINT_TO_POINTER (depth)); } } } @@ -362,8 +393,11 @@ g_log_default_handler (const gchar *log_domain, gint fd; #endif gboolean in_recursion; - gboolean is_fatal; - + gboolean is_fatal; + GErrorFunc local_glib_error_func; + GWarningFunc local_glib_warning_func; + GPrintFunc local_glib_message_func; + in_recursion = (log_level & G_LOG_FLAG_RECURSION) != 0; is_fatal = (log_level & G_LOG_FLAG_FATAL) != 0; log_level &= G_LOG_LEVEL_MASK; @@ -380,13 +414,19 @@ g_log_default_handler (const gchar *log_domain, fd = (log_level >= G_LOG_LEVEL_MESSAGE) ? 1 : 2; #endif + g_mutex_lock (g_messages_lock); + local_glib_error_func = glib_error_func; + local_glib_warning_func = glib_warning_func; + local_glib_message_func = glib_message_func; + g_mutex_unlock (g_messages_lock); + switch (log_level) { case G_LOG_LEVEL_ERROR: - if (!log_domain && glib_error_func) + if (!log_domain && local_glib_error_func) { /* compatibility code */ - glib_error_func (message); + local_glib_error_func (message); return; } /* use write(2) for output, in case we are out of memeory */ @@ -428,10 +468,10 @@ g_log_default_handler (const gchar *log_domain, write (fd, "\n", 1); break; case G_LOG_LEVEL_WARNING: - if (!log_domain && glib_warning_func) + if (!log_domain && local_glib_warning_func) { /* compatibility code */ - glib_warning_func (message); + local_glib_warning_func (message); return; } if (log_domain) @@ -453,10 +493,10 @@ g_log_default_handler (const gchar *log_domain, write (fd, "\n", 1); break; case G_LOG_LEVEL_MESSAGE: - if (!log_domain && glib_message_func) + if (!log_domain && local_glib_message_func) { /* compatibility code */ - glib_message_func (message); + local_glib_message_func (message); return; } if (log_domain) @@ -553,8 +593,10 @@ g_set_print_handler (GPrintFunc func) { GPrintFunc old_print_func; + g_mutex_lock (g_messages_lock); old_print_func = glib_print_func; glib_print_func = func; + g_mutex_unlock (g_messages_lock); return old_print_func; } @@ -565,6 +607,7 @@ g_print (const gchar *format, { va_list args; gchar *string; + GPrintFunc local_glib_print_func; g_return_if_fail (format != NULL); @@ -572,8 +615,12 @@ g_print (const gchar *format, string = g_strdup_vprintf (format, args); va_end (args); - if (glib_print_func) - glib_print_func (string); + g_mutex_lock (g_messages_lock); + local_glib_print_func = glib_print_func; + g_mutex_unlock (g_messages_lock); + + if (local_glib_print_func) + local_glib_print_func (string); else { fputs (string, stdout); @@ -587,8 +634,10 @@ g_set_printerr_handler (GPrintFunc func) { GPrintFunc old_printerr_func; + g_mutex_lock (g_messages_lock); old_printerr_func = glib_printerr_func; glib_printerr_func = func; + g_mutex_unlock (g_messages_lock); return old_printerr_func; } @@ -599,6 +648,7 @@ g_printerr (const gchar *format, { va_list args; gchar *string; + GPrintFunc local_glib_printerr_func; g_return_if_fail (format != NULL); @@ -606,8 +656,12 @@ g_printerr (const gchar *format, string = g_strdup_vprintf (format, args); va_end (args); - if (glib_printerr_func) - glib_printerr_func (string); + g_mutex_lock (g_messages_lock); + local_glib_printerr_func = glib_printerr_func; + g_mutex_unlock (g_messages_lock); + + if (local_glib_printerr_func) + local_glib_printerr_func (string); else { fputs (string, stderr); @@ -622,9 +676,11 @@ g_set_error_handler (GErrorFunc func) { GErrorFunc old_error_func; + g_mutex_lock (g_messages_lock); old_error_func = glib_error_func; glib_error_func = func; - + g_mutex_unlock (g_messages_lock); + return old_error_func; } @@ -634,8 +690,10 @@ g_set_warning_handler (GWarningFunc func) { GWarningFunc old_warning_func; + g_mutex_lock (g_messages_lock); old_warning_func = glib_warning_func; glib_warning_func = func; + g_mutex_unlock (g_messages_lock); return old_warning_func; } @@ -646,8 +704,17 @@ g_set_message_handler (GPrintFunc func) { GPrintFunc old_message_func; + g_mutex_lock (g_messages_lock); old_message_func = glib_message_func; glib_message_func = func; + g_mutex_unlock (g_messages_lock); return old_message_func; } + +void +g_messages_init (void) +{ + g_messages_lock = g_mutex_new(); + g_log_depth = g_private_new(NULL); +} diff --git a/glib/gnode.c b/glib/gnode.c index 9f6e544ba..089a4996d 100644 --- a/glib/gnode.c +++ b/glib/gnode.c @@ -19,6 +19,11 @@ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ + +/* + * MT safe + */ + #include "glib.h" /* node allocation @@ -34,10 +39,12 @@ struct _GAllocator /* from gmem.c */ GNode *free_nodes; /* implementation specific */ }; +static G_LOCK_DEFINE(current_allocator); static GAllocator *current_allocator = NULL; -void -g_node_push_allocator (GAllocator *allocator) +/* HOLDS: current_allocator_lock */ +static void +g_node_validate_allocator (GAllocator *allocator) { g_return_if_fail (allocator != NULL); g_return_if_fail (allocator->is_unused == TRUE); @@ -62,13 +69,22 @@ g_node_push_allocator (GAllocator *allocator) } allocator->is_unused = FALSE; +} + +void +g_node_push_allocator (GAllocator *allocator) +{ + g_node_validate_allocator ( allocator ); + g_lock (current_allocator); allocator->last = current_allocator; current_allocator = allocator; + g_unlock (current_allocator); } void g_node_pop_allocator (void) { + g_lock (current_allocator); if (current_allocator) { GAllocator *allocator; @@ -78,6 +94,7 @@ g_node_pop_allocator (void) allocator->last = NULL; allocator->is_unused = TRUE; } + g_unlock (current_allocator); } @@ -87,9 +104,15 @@ g_node_new (gpointer data) { GNode *node; + g_lock (current_allocator); if (!current_allocator) - g_node_push_allocator (g_allocator_new ("GLib default GNode allocator", 1024)); - + { + GAllocator *allocator = g_allocator_new ("GLib default GNode allocator", + 1024); + g_node_validate_allocator (allocator); + allocator->last = NULL; + current_allocator = allocator; + } if (!current_allocator->free_nodes) node = g_chunk_new (GNode, current_allocator->mem_chunk); else @@ -97,6 +120,7 @@ g_node_new (gpointer data) node = current_allocator->free_nodes; current_allocator->free_nodes = node->next; } + g_unlock (current_allocator); node->data = data; node->next = NULL; @@ -122,9 +146,11 @@ g_nodes_free (GNode *node) else break; } - + + g_lock (current_allocator); parent->next = current_allocator->free_nodes; current_allocator->free_nodes = node; + g_unlock (current_allocator); } void diff --git a/glib/gprimes.c b/glib/gprimes.c index 3d45c1ef7..404ebd605 100644 --- a/glib/gprimes.c +++ b/glib/gprimes.c @@ -16,6 +16,11 @@ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ + +/* + * MT safe + */ + #include "glib.h" static const guint g_primes[] = diff --git a/glib/grel.c b/glib/grel.c index 5fdf88098..544da6bfc 100644 --- a/glib/grel.c +++ b/glib/grel.c @@ -15,6 +15,11 @@ * License along with this library; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* + * MT safe + */ + #include "glib.h" #include <stdarg.h> #include <string.h> diff --git a/glib/gscanner.c b/glib/gscanner.c index 02985a7f7..c6fd0dd4e 100644 --- a/glib/gscanner.c +++ b/glib/gscanner.c @@ -19,6 +19,11 @@ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ + +/* + * MT safe + */ + #define __gscanner_c__ #ifdef HAVE_CONFIG_H diff --git a/glib/gslist.c b/glib/gslist.c index 4efe2a575..1ed517ff6 100644 --- a/glib/gslist.c +++ b/glib/gslist.c @@ -16,6 +16,11 @@ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ + +/* + * MT safe + */ + #include "glib.h" @@ -30,10 +35,12 @@ struct _GAllocator /* from gmem.c */ GSList *free_lists; /* implementation specific */ }; +static G_LOCK_DEFINE(current_allocator); static GAllocator *current_allocator = NULL; -void -g_slist_push_allocator (GAllocator *allocator) +/* HOLDS: current_allocator_lock */ +static void +g_slist_validate_allocator (GAllocator *allocator) { g_return_if_fail (allocator != NULL); g_return_if_fail (allocator->is_unused == TRUE); @@ -58,13 +65,22 @@ g_slist_push_allocator (GAllocator *allocator) } allocator->is_unused = FALSE; +} + +void +g_slist_push_allocator (GAllocator *allocator) +{ + g_slist_validate_allocator (allocator); + g_lock (current_allocator); allocator->last = current_allocator; current_allocator = allocator; + g_unlock (current_allocator); } void g_slist_pop_allocator (void) { + g_lock (current_allocator); if (current_allocator) { GAllocator *allocator; @@ -74,6 +90,7 @@ g_slist_pop_allocator (void) allocator->last = NULL; allocator->is_unused = TRUE; } + g_unlock (current_allocator); } GSList* @@ -81,9 +98,15 @@ g_slist_alloc (void) { GSList *list; + g_lock (current_allocator); if (!current_allocator) - g_slist_push_allocator (g_allocator_new ("GLib default GSList allocator", 1024)); - + { + GAllocator *allocator = g_allocator_new ("GLib default GSList allocator", + 1024); + g_slist_validate_allocator (allocator); + allocator->last = NULL; + current_allocator = allocator; + } if (!current_allocator->free_lists) { list = g_chunk_new (GSList, current_allocator->mem_chunk); @@ -103,6 +126,8 @@ g_slist_alloc (void) current_allocator->free_lists = list->next; } } + g_unlock (current_allocator); + list->next = NULL; return list; @@ -114,8 +139,10 @@ g_slist_free (GSList *list) if (list) { list->data = list->next; + g_lock (current_allocator); list->next = current_allocator->free_lists; current_allocator->free_lists = list; + g_unlock (current_allocator); } } @@ -125,8 +152,10 @@ g_slist_free_1 (GSList *list) if (list) { list->data = NULL; + g_lock (current_allocator); list->next = current_allocator->free_lists; current_allocator->free_lists = list; + g_unlock (current_allocator); } } diff --git a/glib/gstrfuncs.c b/glib/gstrfuncs.c index ad28978ee..e154c56dc 100644 --- a/glib/gstrfuncs.c +++ b/glib/gstrfuncs.c @@ -17,6 +17,10 @@ * Boston, MA 02111-1307, USA. */ +/* + * MT safe + */ + #ifdef HAVE_CONFIG_H #include <config.h> #endif @@ -208,7 +212,8 @@ g_strtod (const gchar *nptr, gchar* g_strerror (gint errnum) { - static char msg[64]; + static GStaticPrivate msg_private = G_STATIC_PRIVATE_INIT; + char *msg; #ifdef HAVE_STRERROR return strerror (errnum); @@ -634,7 +639,14 @@ g_strerror (gint errnum) if ((errnum > 0) && (errnum <= sys_nerr)) return sys_errlist [errnum]; #endif /* NO_SYS_ERRLIST */ - + + msg = g_static_private_get (&msg_private); + if( !msg ) + { + msg = g_new( gchar, 64 ); + g_static_private_set (&msg_private, msg, g_free); + } + sprintf (msg, "unknown error (%d)", errnum); return msg; } @@ -642,7 +654,8 @@ g_strerror (gint errnum) gchar* g_strsignal (gint signum) { - static char msg[64]; + static GStaticPrivate msg_private = G_STATIC_PRIVATE_INIT; + char *msg; #ifdef HAVE_STRSIGNAL extern char *strsignal (int sig); @@ -748,6 +761,13 @@ g_strsignal (gint signum) extern char *sys_siglist[]; return sys_siglist [signum]; #endif /* NO_SYS_SIGLIST */ + + msg = g_static_private_get (&msg_private); + if( !msg ) + { + msg = g_new( gchar, 64 ); + g_static_private_set (&msg_private, msg, g_free); + } sprintf (msg, "unknown signal (%d)", signum); return msg; diff --git a/glib/gstring.c b/glib/gstring.c index fa84fe7a2..312a54060 100644 --- a/glib/gstring.c +++ b/glib/gstring.c @@ -16,6 +16,11 @@ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ + +/* + * MT safe + */ + #include <stdarg.h> #include <stdlib.h> #include <stdio.h> @@ -43,7 +48,7 @@ struct _GRealString gint alloc; }; - +static G_LOCK_DEFINE(string_mem_chunk); static GMemChunk *string_mem_chunk = NULL; /* Hash Functions. @@ -202,12 +207,14 @@ g_string_sized_new (guint dfl_size) { GRealString *string; + g_lock (string_mem_chunk); if (!string_mem_chunk) string_mem_chunk = g_mem_chunk_new ("string mem chunk", sizeof (GRealString), 1024, G_ALLOC_AND_FREE); string = g_chunk_new (GRealString, string_mem_chunk); + g_unlock (string_mem_chunk); string->alloc = 0; string->len = 0; @@ -241,7 +248,9 @@ g_string_free (GString *string, if (free_segment) g_free (string->str); + g_lock (string_mem_chunk); g_mem_chunk_free (string_mem_chunk, string); + g_unlock (string_mem_chunk); } GString* diff --git a/glib/gtimer.c b/glib/gtimer.c index 6e58fa0bd..0b6e86a8a 100644 --- a/glib/gtimer.c +++ b/glib/gtimer.c @@ -17,6 +17,10 @@ * Boston, MA 02111-1307, USA. */ +/* + * MT safe + */ + #ifdef HAVE_CONFIG_H #include <config.h> #endif diff --git a/glib/gtree.c b/glib/gtree.c index 4d9e98a0b..006f15db7 100644 --- a/glib/gtree.c +++ b/glib/gtree.c @@ -16,6 +16,11 @@ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ + +/* + * MT safe + */ + #include "glib.h" @@ -78,6 +83,7 @@ static GTreeNode* g_tree_node_rotate_right (GTreeNode *node); static void g_tree_node_check (GTreeNode *node); +static G_LOCK_DEFINE(g_tree_global); static GMemChunk *node_mem_chunk = NULL; static GTreeNode *node_free_list = NULL; @@ -88,6 +94,7 @@ g_tree_node_new (gpointer key, { GTreeNode *node; + g_lock (g_tree_global); if (node_free_list) { node = node_free_list; @@ -102,7 +109,8 @@ g_tree_node_new (gpointer key, G_ALLOC_ONLY); node = g_chunk_new (GTreeNode, node_mem_chunk); - } + } + g_unlock (g_tree_global); node->balance = 0; node->left = NULL; @@ -120,9 +128,11 @@ g_tree_node_destroy (GTreeNode *node) { g_tree_node_destroy (node->right); g_tree_node_destroy (node->left); + g_lock (g_tree_global); node->right = node_free_list; node_free_list = node; - } + g_unlock (g_tree_global); + } } @@ -375,9 +385,11 @@ g_tree_node_remove (GTreeNode *node, node = g_tree_node_restore_right_balance (new_root, old_balance); } + g_lock (g_tree_global); garbage->right = node_free_list; node_free_list = garbage; - } + g_unlock (g_tree_global); + } else if (cmp < 0) { if (node->left) diff --git a/glib/gutils.c b/glib/gutils.c index cc6594937..9a91199b6 100644 --- a/glib/gutils.c +++ b/glib/gutils.c @@ -17,6 +17,10 @@ * Boston, MA 02111-1307, USA. */ +/* + * MT safe for the unix part, FIXME: make the win32 part MT safe as well. + */ + #ifdef HAVE_CONFIG_H #include <config.h> #endif @@ -367,11 +371,14 @@ g_getenv (const gchar *variable) #endif } +static G_LOCK_DEFINE(g_utils_global); + static gchar *g_tmp_dir = NULL; static gchar *g_user_name = NULL; static gchar *g_real_name = NULL; static gchar *g_home_dir = NULL; +/* HOLDS: g_utils_global_lock */ static void g_get_any_init (void) { @@ -442,14 +449,16 @@ g_get_any_init (void) g_home_dir = NULL; # endif /* !NATIVE_WIN32 */ #endif /* !HAVE_PWD_H */ - } + } } gchar* g_get_user_name (void) { + g_lock (g_utils_global); if (!g_tmp_dir) g_get_any_init (); + g_unlock (g_utils_global); return g_user_name; } @@ -457,9 +466,11 @@ g_get_user_name (void) gchar* g_get_real_name (void) { + g_lock (g_utils_global); if (!g_tmp_dir) g_get_any_init (); - + g_unlock (g_utils_global); + return g_real_name; } @@ -472,8 +483,10 @@ g_get_real_name (void) gchar* g_get_home_dir (void) { + g_lock (g_utils_global); if (!g_tmp_dir) g_get_any_init (); + g_unlock (g_utils_global); return g_home_dir; } @@ -488,8 +501,10 @@ g_get_home_dir (void) gchar* g_get_tmp_dir (void) { + g_lock (g_utils_global); if (!g_tmp_dir) g_get_any_init (); + g_unlock (g_utils_global); return g_tmp_dir; } @@ -499,16 +514,25 @@ static gchar *g_prgname = NULL; gchar* g_get_prgname (void) { - return g_prgname; + gchar* retval; + + g_lock (g_utils_global); + retval = g_prgname; + g_unlock (g_utils_global); + + return retval; } void g_set_prgname (const gchar *prgname) { - gchar *c = g_prgname; - + gchar *c; + + g_lock (g_utils_global); + c = g_prgname; g_prgname = g_strdup (prgname); g_free (c); + g_unlock (g_utils_global); } guint |