cleaned up the errno mess for GETPWUID. we especially don't want to
[platform/upstream/glib.git] / gmutex.c
1 /* GLIB - Library of useful routines for C programming
2  * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * gmutex.c: MT safety related functions
5  * Copyright 1998 Sebastian Wilhelmi; University of Karlsruhe
6  *                Owen Taylor
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public
19  * License along with this library; if not, write to the
20  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21  * Boston, MA 02111-1307, USA.
22  */
23
24 /* 
25  * MT safe
26  */
27
28 #include "glib.h"
29
30 typedef struct _GStaticPrivateNode GStaticPrivateNode;
31
32 struct _GStaticPrivateNode {
33   gpointer       data;
34   GDestroyNotify destroy;
35 };
36
37 static void g_static_private_free_data (gpointer data);
38 static void g_thread_fail (void);
39
40 /* Global variables */
41
42 gboolean g_thread_use_default_impl = TRUE;
43 gboolean g_threads_got_initialized = FALSE;
44
45 GThreadFunctions g_thread_functions_for_glib_use = {
46   (GMutex*(*)())g_thread_fail,                 /* mutex_new */
47   NULL,                                        /* mutex_lock */
48   NULL,                                        /* mutex_trylock */
49   NULL,                                        /* mutex_unlock */
50   NULL,                                        /* mutex_free */
51   (GCond*(*)())g_thread_fail,                  /* cond_new */
52   NULL,                                        /* cond_signal */
53   NULL,                                        /* cond_broadcast */
54   NULL,                                        /* cond_wait */
55   NULL,                                        /* cond_timed_wait  */
56   NULL,                                        /* cond_free */
57   (GPrivate*(*)(GDestroyNotify))g_thread_fail, /* private_new */
58   NULL,                                        /* private_get */
59   NULL,                                        /* private_set */
60 }; 
61
62 /* Local data */
63
64 static GMutex   *g_mutex_protect_static_mutex_allocation = NULL;
65 static GMutex   *g_thread_specific_mutex = NULL;
66 static GPrivate *g_thread_specific_private = NULL;
67
68 /* This must be called only once, before any threads are created.
69  * It will only be called from g_thread_init() in -lgthread.
70  */
71 void
72 g_mutex_init (void)
73 {
74   /* We let the main thread (the one that calls g_thread_init) inherit
75      the data, that it set before calling g_thread_init */
76   gpointer private_old = g_thread_specific_private;
77   g_thread_specific_private = g_private_new (g_static_private_free_data);
78
79   /* we can not use g_private_set here, as g_threads_got_initialized is not
80      yet set TRUE, whereas the private_set function is already set. */
81   g_thread_functions_for_glib_use.private_set (g_thread_specific_private, 
82                                                private_old);
83
84   g_mutex_protect_static_mutex_allocation = g_mutex_new();
85   g_thread_specific_mutex = g_mutex_new();
86 }
87
88 GMutex *
89 g_static_mutex_get_mutex_impl (GMutex** mutex)
90 {
91   if (!g_thread_supported ())
92     return NULL;
93
94   g_assert (g_mutex_protect_static_mutex_allocation);
95
96   g_mutex_lock (g_mutex_protect_static_mutex_allocation);
97
98   if (!(*mutex)) 
99     *mutex = g_mutex_new(); 
100
101   g_mutex_unlock (g_mutex_protect_static_mutex_allocation);
102   
103   return *mutex;
104 }
105
106 gpointer
107 g_static_private_get (GStaticPrivate *private_key)
108 {
109   GArray *array;
110
111   array = g_private_get (g_thread_specific_private);
112   if (!array)
113     return NULL;
114
115   if (!private_key->index)
116     return NULL;
117   else if (private_key->index <= array->len)
118     return g_array_index (array, GStaticPrivateNode, (private_key->index - 1)).data;
119   else
120     return NULL;
121 }
122
123 void
124 g_static_private_set (GStaticPrivate *private_key, 
125                       gpointer        data,
126                       GDestroyNotify  notify)
127 {
128   GArray *array;
129   static guint next_index = 0;
130   
131   array = g_private_get (g_thread_specific_private);
132   if (!array)
133     {
134       array = g_array_new (FALSE, FALSE, sizeof(GStaticPrivateNode));
135       g_private_set (g_thread_specific_private, array);
136     }
137
138   if (!private_key->index)
139     {
140       g_mutex_lock (g_thread_specific_mutex);
141
142       if (!private_key->index)
143         private_key->index = ++next_index;
144
145       g_mutex_unlock (g_thread_specific_mutex);
146     }
147
148   if (private_key->index > array->len)
149     g_array_set_size (array, private_key->index);
150
151   g_array_index (array, GStaticPrivateNode, (private_key->index - 1)).data = data;
152   g_array_index (array, GStaticPrivateNode, (private_key->index - 1)).destroy = notify;
153 }
154
155 static void
156 g_static_private_free_data (gpointer data)
157 {
158   if (data)
159     {
160       GArray* array = data;
161       guint i;
162       
163       for (i = 0; i < array->len; i++ )
164         {
165           GStaticPrivateNode *node = &g_array_index (array, GStaticPrivateNode, i);
166           if (node->data && node->destroy)
167             node->destroy (node->data);
168         }
169     }
170 }
171
172 static void
173 g_thread_fail (void)
174 {
175   g_error ("The thread system is not yet initialized.");
176 }