Deprecated (undocumented) g_thread_gettime
[platform/upstream/glib.git] / gthread / gthread-impl.c
1 /* GLIB - Library of useful routines for C programming
2  * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * gthread.c: thread related functions
5  * Copyright 1998 Sebastian Wilhelmi; University of Karlsruhe
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 /*
24  * Modified by the GLib Team and others 1997-2000.  See the AUTHORS
25  * file for a list of people on the GLib Team.  See the ChangeLog
26  * files for a list of changes.  These files are distributed with
27  * GLib at ftp://ftp.gtk.org/pub/gtk/.
28  */
29
30 /*
31  * MT safe
32  */
33
34 #include "config.h"
35
36 #include "glib.h"
37 #include "gthreadprivate.h"
38
39 static GSystemThread zero_thread; /* This is initialized to all zero */
40 static gboolean thread_system_already_initialized = FALSE;
41 static gint g_thread_priority_map [G_THREAD_PRIORITY_URGENT + 1];
42
43 #include G_THREAD_SOURCE
44
45 #ifndef PRIORITY_LOW_VALUE
46 # define PRIORITY_LOW_VALUE 0
47 #endif
48
49 #ifndef PRIORITY_URGENT_VALUE
50 # define PRIORITY_URGENT_VALUE 0
51 #endif
52
53 #ifndef PRIORITY_NORMAL_VALUE
54 # define PRIORITY_NORMAL_VALUE                                          \
55   ((PRIORITY_LOW_VALUE * 6 + PRIORITY_URGENT_VALUE * 4) / 10)
56 #endif /* PRIORITY_NORMAL_VALUE */
57
58 #ifndef PRIORITY_HIGH_VALUE
59 # define PRIORITY_HIGH_VALUE                                            \
60   ((PRIORITY_NORMAL_VALUE + PRIORITY_URGENT_VALUE * 2) / 3)
61 #endif /* PRIORITY_HIGH_VALUE */
62
63 void g_mutex_init (void);
64 void g_mem_init (void);
65 void g_messages_init (void);
66 void g_convert_init (void);
67 void g_rand_init (void);
68 void g_main_thread_init (void);
69
70 typedef struct _GMutexDebugInfo GMutexDebugInfo;
71 struct _GMutexDebugInfo
72 {
73   gchar *location;
74   GSystemThread owner;
75 };
76
77 #define G_MUTEX_DEBUG_INFO(mutex)                                       \
78   (((GMutexDebugInfo*)(((char*)mutex)+G_MUTEX_SIZE)))
79
80 static GMutex *
81 g_mutex_new_errorcheck_impl (void)
82 {
83   GMutex *retval = g_thread_functions_for_glib_use_default.mutex_new ();
84   GMutexDebugInfo *info;
85   retval = g_realloc (retval, G_MUTEX_SIZE + sizeof (GMutexDebugInfo));
86
87   info = G_MUTEX_DEBUG_INFO (retval);
88   g_system_thread_assign (info->owner, zero_thread);
89   info->location = "invalid";
90
91   return retval;
92 }
93
94 static void
95 g_mutex_lock_errorcheck_impl (GMutex *mutex,
96                               const gulong magic,
97                               gchar * const location)
98 {
99   GMutexDebugInfo *info = G_MUTEX_DEBUG_INFO (mutex);
100   gchar *loc = (magic == G_MUTEX_DEBUG_MAGIC) ? location : "unknown";
101
102   GSystemThread self;
103   g_thread_functions_for_glib_use.thread_self (&self);
104
105   if (g_system_thread_equal (info->owner, self))
106     g_error ("Trying to recursively lock a mutex at '%s', "
107              "previously locked at '%s'",
108              loc, info->location);
109
110   g_thread_functions_for_glib_use_default.mutex_lock (mutex);
111
112   g_system_thread_assign (info->owner, self);
113   info->location = loc;
114 }
115
116 static gboolean
117 g_mutex_trylock_errorcheck_impl (GMutex *mutex,
118                                  const gulong magic,
119                                  gchar * const location)
120 {
121   GMutexDebugInfo *info = G_MUTEX_DEBUG_INFO (mutex);
122   gchar *loc = (magic == G_MUTEX_DEBUG_MAGIC) ? location : "unknown";
123
124   GSystemThread self;
125   g_thread_functions_for_glib_use.thread_self (&self);
126
127   if (g_system_thread_equal (info->owner, self))
128     g_error ("Trying to recursivly lock a mutex at '%s', "
129              "previously locked at '%s'",
130              loc, info->location);
131
132   if (!g_thread_functions_for_glib_use_default.mutex_trylock (mutex))
133     return FALSE;
134
135   g_system_thread_assign (info->owner, self);
136   info->location = loc;
137
138   return TRUE;
139 }
140
141 static void
142 g_mutex_unlock_errorcheck_impl (GMutex *mutex,
143                                 const gulong magic,
144                                 gchar * const location)
145 {
146   GMutexDebugInfo *info = G_MUTEX_DEBUG_INFO (mutex);
147   gchar *loc = (magic == G_MUTEX_DEBUG_MAGIC) ? location : "unknown";
148
149   GSystemThread self;
150   g_thread_functions_for_glib_use.thread_self (&self);
151
152   if (g_system_thread_equal (info->owner, zero_thread))
153     g_error ("Trying to unlock an unlocked mutex at '%s'", loc);
154
155   if (!g_system_thread_equal (info->owner, self))
156     g_warning ("Trying to unlock a mutex at '%s', "
157                "previously locked by a different thread at '%s'",
158                loc, info->location);
159
160   g_system_thread_assign (info->owner, zero_thread);
161   info->location = NULL;
162
163   g_thread_functions_for_glib_use_default.mutex_unlock (mutex);
164 }
165
166 static void
167 g_mutex_free_errorcheck_impl (GMutex *mutex,
168                               const gulong magic,
169                               gchar * const location)
170 {
171   GMutexDebugInfo *info = G_MUTEX_DEBUG_INFO (mutex);
172   gchar *loc = (magic == G_MUTEX_DEBUG_MAGIC) ? location : "unknown";
173
174   if (info && !g_system_thread_equal (info->owner, zero_thread))
175     g_error ("Trying to free a locked mutex at '%s', "
176              "which was previously locked at '%s'",
177              loc, info->location);
178
179   g_thread_functions_for_glib_use_default.mutex_free (mutex);
180 }
181
182 static void
183 g_cond_wait_errorcheck_impl (GCond *cond,
184                              GMutex *mutex,
185                              const gulong magic,
186                              gchar * const location)
187 {
188   GMutexDebugInfo *info = G_MUTEX_DEBUG_INFO (mutex);
189   gchar *loc = (magic == G_MUTEX_DEBUG_MAGIC) ? location : "unknown";
190
191   GSystemThread self;
192   g_thread_functions_for_glib_use.thread_self (&self);
193
194   if (g_system_thread_equal (info->owner, zero_thread))
195     g_error ("Trying to use an unlocked mutex in g_cond_wait() at '%s'", loc);
196
197   if (!g_system_thread_equal (info->owner, self))
198     g_error ("Trying to use a mutex locked by another thread in "
199              "g_cond_wait() at '%s'", loc);
200
201   g_system_thread_assign (info->owner, zero_thread);
202   loc = info->location;
203
204   g_thread_functions_for_glib_use_default.cond_wait (cond, mutex);
205
206   g_system_thread_assign (info->owner, self);
207   info->location = loc;
208 }
209
210
211 static gboolean
212 g_cond_timed_wait_errorcheck_impl (GCond *cond,
213                                    GMutex *mutex,
214                                    GTimeVal *end_time,
215                                    const gulong magic,
216                                    gchar * const location)
217 {
218   GMutexDebugInfo *info = G_MUTEX_DEBUG_INFO (mutex);
219   gchar *loc = (magic == G_MUTEX_DEBUG_MAGIC) ? location : "unknown";
220   gboolean retval;
221
222   GSystemThread self;
223   g_thread_functions_for_glib_use.thread_self (&self);
224
225   if (g_system_thread_equal (info->owner, zero_thread))
226     g_error ("Trying to use an unlocked mutex in g_cond_timed_wait() at '%s'",
227              loc);
228
229   if (!g_system_thread_equal (info->owner, self))
230     g_error ("Trying to use a mutex locked by another thread in "
231              "g_cond_timed_wait() at '%s'", loc);
232
233   g_system_thread_assign (info->owner, zero_thread);
234   loc = info->location;
235
236   retval = g_thread_functions_for_glib_use_default.cond_timed_wait (cond,
237                                                                     mutex,
238                                                                     end_time);
239
240   g_system_thread_assign (info->owner, self);
241   info->location = loc;
242
243   return retval;
244 }
245
246
247 /* unshadow function declaration. See gthread.h */
248 #undef g_thread_init
249
250 void
251 g_thread_init_with_errorcheck_mutexes (GThreadFunctions* init)
252 {
253   GThreadFunctions errorcheck_functions;
254   if (init)
255     g_error ("Errorcheck mutexes can only be used for native "
256              "thread implementations. Sorry." );
257
258 #ifdef HAVE_G_THREAD_IMPL_INIT
259   /* This isn't called in g_thread_init, as it doesn't think to get
260    * the default implementation, so we have to call it on our own.
261    *
262    * We must call this before copying
263    * g_thread_functions_for_glib_use_default as the
264    * implementation-specific init function might modify the contents
265    * of g_thread_functions_for_glib_use_default based on operating
266    * system version, C library version, or whatever. */
267   g_thread_impl_init();
268 #endif /* HAVE_G_THREAD_IMPL_INIT */
269
270   errorcheck_functions = g_thread_functions_for_glib_use_default;
271   errorcheck_functions.mutex_new = g_mutex_new_errorcheck_impl;
272   errorcheck_functions.mutex_lock =
273     (void (*)(GMutex *)) g_mutex_lock_errorcheck_impl;
274   errorcheck_functions.mutex_trylock =
275     (gboolean (*)(GMutex *)) g_mutex_trylock_errorcheck_impl;
276   errorcheck_functions.mutex_unlock =
277     (void (*)(GMutex *)) g_mutex_unlock_errorcheck_impl;
278   errorcheck_functions.mutex_free =
279     (void (*)(GMutex *)) g_mutex_free_errorcheck_impl;
280   errorcheck_functions.cond_wait =
281     (void (*)(GCond *, GMutex *)) g_cond_wait_errorcheck_impl;
282   errorcheck_functions.cond_timed_wait =
283     (gboolean (*)(GCond *, GMutex *, GTimeVal *))
284     g_cond_timed_wait_errorcheck_impl;
285
286   g_thread_init (&errorcheck_functions);
287 }
288
289 void
290 g_thread_init (GThreadFunctions* init)
291 {
292   gboolean supported;
293
294   if (thread_system_already_initialized)
295     {
296       if (init != NULL)
297         g_warning ("GThread system already initialized, ignoring custom thread implementation.");
298
299       return;
300     }
301
302   thread_system_already_initialized = TRUE;
303
304   if (init == NULL)
305     {
306 #ifdef HAVE_G_THREAD_IMPL_INIT
307       /* now do any initialization stuff required by the
308        * implementation, but only if called with a NULL argument, of
309        * course. Otherwise it's up to the user to do so. */
310       g_thread_impl_init();
311 #endif /* HAVE_G_THREAD_IMPL_INIT */
312       init = &g_thread_functions_for_glib_use_default;
313     }
314   else
315     g_thread_use_default_impl = FALSE;
316
317   g_thread_functions_for_glib_use = *init;
318
319   supported = (init->mutex_new &&
320                init->mutex_lock &&
321                init->mutex_trylock &&
322                init->mutex_unlock &&
323                init->mutex_free &&
324                init->cond_new &&
325                init->cond_signal &&
326                init->cond_broadcast &&
327                init->cond_wait &&
328                init->cond_timed_wait &&
329                init->cond_free &&
330                init->private_new &&
331                init->private_get &&
332                init->private_set &&
333                init->thread_create &&
334                init->thread_yield &&
335                init->thread_join &&
336                init->thread_exit &&
337                init->thread_set_priority &&
338                init->thread_self);
339
340   /* if somebody is calling g_thread_init (), it means that he wants to
341    * have thread support, so check this
342    */
343   if (!supported)
344     {
345       if (g_thread_use_default_impl)
346         g_error ("Threads are not supported on this platform.");
347       else
348         g_error ("The supplied thread function vector is invalid.");
349     }
350
351   g_thread_priority_map [G_THREAD_PRIORITY_LOW] = PRIORITY_LOW_VALUE;
352   g_thread_priority_map [G_THREAD_PRIORITY_NORMAL] = PRIORITY_NORMAL_VALUE;
353   g_thread_priority_map [G_THREAD_PRIORITY_HIGH] = PRIORITY_HIGH_VALUE;
354   g_thread_priority_map [G_THREAD_PRIORITY_URGENT] = PRIORITY_URGENT_VALUE;
355
356   g_thread_init_glib ();
357 }