| /* GLIB - Library of useful routines for C programming |
| * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald |
| * |
| * gmutex.c: MT safety related functions |
| * Copyright 1998 Sebastian Wilhelmi; University of Karlsruhe |
| * Owen Taylor |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Library General Public |
| * License as published by the Free Software Foundation; either |
| * version 2 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Library General Public License for more details. |
| * |
| * You should have received a copy of the GNU Library General Public |
| * License along with this library; if not, write to the |
| * Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
| * Boston, MA 02111-1307, USA. |
| */ |
| |
| /* |
| * MT safe |
| */ |
| |
| #include "glib.h" |
| |
| typedef struct _GStaticPrivateNode GStaticPrivateNode; |
| |
| struct _GStaticPrivateNode { |
| gpointer data; |
| GDestroyNotify destroy; |
| }; |
| |
| static void g_static_private_free_data (gpointer data); |
| static void g_thread_fail (void); |
| |
| /* Global variables */ |
| |
| gboolean g_thread_use_default_impl = TRUE; |
| gboolean g_threads_got_initialized = FALSE; |
| |
| GThreadFunctions g_thread_functions_for_glib_use = { |
| (GMutex*(*)())g_thread_fail, /* mutex_new */ |
| NULL, /* mutex_lock */ |
| NULL, /* mutex_trylock */ |
| NULL, /* mutex_unlock */ |
| NULL, /* mutex_free */ |
| (GCond*(*)())g_thread_fail, /* cond_new */ |
| NULL, /* cond_signal */ |
| NULL, /* cond_broadcast */ |
| NULL, /* cond_wait */ |
| NULL, /* cond_timed_wait */ |
| NULL, /* cond_free */ |
| (GPrivate*(*)(GDestroyNotify))g_thread_fail, /* private_new */ |
| NULL, /* private_get */ |
| NULL, /* private_set */ |
| }; |
| |
| /* Local data */ |
| |
| static GMutex *g_mutex_protect_static_mutex_allocation = NULL; |
| static GMutex *g_thread_specific_mutex = NULL; |
| static GPrivate *g_thread_specific_private = NULL; |
| |
| /* This must be called only once, before any threads are created. |
| * It will only be called from g_thread_init() in -lgthread. |
| */ |
| void |
| g_mutex_init (void) |
| { |
| /* We let the main thread (the one that calls g_thread_init) inherit |
| the data, that it set before calling g_thread_init */ |
| gpointer private_old = g_thread_specific_private; |
| g_thread_specific_private = g_private_new (g_static_private_free_data); |
| |
| /* we can not use g_private_set here, as g_threads_got_initialized is not |
| yet set TRUE, whereas the private_set function is already set. */ |
| g_thread_functions_for_glib_use.private_set (g_thread_specific_private, |
| private_old); |
| |
| g_mutex_protect_static_mutex_allocation = g_mutex_new(); |
| g_thread_specific_mutex = g_mutex_new(); |
| } |
| |
| GMutex * |
| g_static_mutex_get_mutex_impl (GMutex** mutex) |
| { |
| if (!g_thread_supported ()) |
| return NULL; |
| |
| g_assert (g_mutex_protect_static_mutex_allocation); |
| |
| g_mutex_lock (g_mutex_protect_static_mutex_allocation); |
| |
| if (!(*mutex)) |
| *mutex = g_mutex_new(); |
| |
| g_mutex_unlock (g_mutex_protect_static_mutex_allocation); |
| |
| return *mutex; |
| } |
| |
| gpointer |
| g_static_private_get (GStaticPrivate *private_key) |
| { |
| GArray *array; |
| |
| array = g_private_get (g_thread_specific_private); |
| if (!array) |
| return NULL; |
| |
| if (!private_key->index) |
| return NULL; |
| else if (private_key->index <= array->len) |
| return g_array_index (array, GStaticPrivateNode, (private_key->index - 1)).data; |
| else |
| return NULL; |
| } |
| |
| void |
| g_static_private_set (GStaticPrivate *private_key, |
| gpointer data, |
| GDestroyNotify notify) |
| { |
| GArray *array; |
| static guint next_index = 0; |
| |
| array = g_private_get (g_thread_specific_private); |
| if (!array) |
| { |
| array = g_array_new (FALSE, FALSE, sizeof(GStaticPrivateNode)); |
| g_private_set (g_thread_specific_private, array); |
| } |
| |
| if (!private_key->index) |
| { |
| g_mutex_lock (g_thread_specific_mutex); |
| |
| if (!private_key->index) |
| private_key->index = ++next_index; |
| |
| g_mutex_unlock (g_thread_specific_mutex); |
| } |
| |
| if (private_key->index > array->len) |
| g_array_set_size (array, private_key->index); |
| |
| g_array_index (array, GStaticPrivateNode, (private_key->index - 1)).data = data; |
| g_array_index (array, GStaticPrivateNode, (private_key->index - 1)).destroy = notify; |
| } |
| |
| static void |
| g_static_private_free_data (gpointer data) |
| { |
| if (data) |
| { |
| GArray* array = data; |
| guint i; |
| |
| for (i = 0; i < array->len; i++ ) |
| { |
| GStaticPrivateNode *node = &g_array_index (array, GStaticPrivateNode, i); |
| if (node->data && node->destroy) |
| node->destroy (node->data); |
| } |
| } |
| } |
| |
| static void |
| g_thread_fail (void) |
| { |
| g_error ("The thread system is not yet initialized."); |
| } |