0aaef25f1f33745a72d2b5660f765dca75869510
[platform/upstream/glib.git] / glib / gthread.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  * Modified by the GLib Team and others 1997-1999.  See the AUTHORS
26  * file for a list of people on the GLib Team.  See the ChangeLog
27  * files for a list of changes.  These files are distributed with
28  * GLib at ftp://ftp.gtk.org/pub/gtk/. 
29  */
30
31 /* 
32  * MT safe
33  */
34
35 #include "glib.h"
36 #include <unistd.h>
37
38 typedef struct _GRealThread GRealThread;
39
40 struct  _GRealThread
41 {
42   GThread thread;
43   GThreadFunc func;
44   gpointer arg;
45   gpointer system_thread;
46   gpointer private_data;
47 };
48
49 typedef struct _GStaticPrivateNode GStaticPrivateNode;
50
51 struct _GStaticPrivateNode
52 {
53   gpointer       data;
54   GDestroyNotify destroy;
55 };
56
57 static void g_thread_cleanup (gpointer data);
58 static void g_thread_fail (void);
59
60 /* Global variables */
61
62 gboolean g_thread_use_default_impl = TRUE;
63 gboolean g_threads_got_initialized = FALSE;
64
65 GThreadFunctions g_thread_functions_for_glib_use = {
66   (GMutex*(*)())g_thread_fail,                 /* mutex_new */
67   NULL,                                        /* mutex_lock */
68   NULL,                                        /* mutex_trylock */
69   NULL,                                        /* mutex_unlock */
70   NULL,                                        /* mutex_free */
71   (GCond*(*)())g_thread_fail,                  /* cond_new */
72   NULL,                                        /* cond_signal */
73   NULL,                                        /* cond_broadcast */
74   NULL,                                        /* cond_wait */
75   NULL,                                        /* cond_timed_wait  */
76   NULL,                                        /* cond_free */
77   (GPrivate*(*)(GDestroyNotify))g_thread_fail, /* private_new */
78   NULL,                                        /* private_get */
79   NULL,                                        /* private_set */
80   (gpointer(*)(GThreadFunc, gpointer, gulong, 
81                gboolean, gboolean, 
82                GThreadPriority))g_thread_fail, /* thread_create */
83   NULL,                                        /* thread_yield */
84   NULL,                                        /* thread_join */
85   NULL,                                        /* thread_exit */
86   NULL,                                        /* thread_set_priority */
87   NULL                                         /* thread_self */
88 }; 
89
90 /* Local data */
91
92 static GMutex   *g_mutex_protect_static_mutex_allocation = NULL;
93 static GMutex   *g_thread_specific_mutex = NULL;
94 static GPrivate *g_thread_specific_private = NULL;
95
96 /* This must be called only once, before any threads are created.
97  * It will only be called from g_thread_init() in -lgthread.
98  */
99 void
100 g_mutex_init (void)
101 {
102   gpointer private_old;
103  
104   /* We let the main thread (the one that calls g_thread_init) inherit
105    * the data, that it set before calling g_thread_init
106    */
107   private_old = g_thread_specific_private;
108
109   g_thread_specific_private = g_private_new (g_thread_cleanup);
110
111   /* we can not use g_private_set here, as g_threads_got_initialized is not
112    * yet set TRUE, whereas the private_set function is already set.
113    */
114   g_thread_functions_for_glib_use.private_set (g_thread_specific_private, 
115                                                private_old);
116
117   g_mutex_protect_static_mutex_allocation = g_mutex_new();
118   g_thread_specific_mutex = g_mutex_new();
119   
120 }
121
122 GMutex *
123 g_static_mutex_get_mutex_impl (GMutex** mutex)
124 {
125   if (!g_thread_supported ())
126     return NULL;
127
128   g_assert (g_mutex_protect_static_mutex_allocation);
129
130   g_mutex_lock (g_mutex_protect_static_mutex_allocation);
131
132   if (!(*mutex)) 
133     *mutex = g_mutex_new(); 
134
135   g_mutex_unlock (g_mutex_protect_static_mutex_allocation);
136   
137   return *mutex;
138 }
139
140 #ifndef g_static_rec_mutex_lock
141 /* That means, that g_static_rec_mutex_lock is not defined to be 
142  * g_static_mutex_lock, we have to provide an implementation ourselves.
143  */
144 void
145 g_static_rec_mutex_lock (GStaticRecMutex* mutex)
146 {
147   guint counter = GPOINTER_TO_UINT (g_static_private_get (&mutex->counter));
148   if (counter == 0)
149     {
150       g_static_mutex_lock (&mutex->mutex);
151     }
152   counter++;
153   g_static_private_set (&mutex->counter, GUINT_TO_POINTER (counter), NULL);
154 }
155
156 gboolean
157 g_static_rec_mutex_trylock (GStaticRecMutex* mutex)
158 {
159   guint counter = GPOINTER_TO_UINT (g_static_private_get (&mutex->counter));
160   if (counter == 0)
161     {
162       if (!g_static_mutex_trylock (&mutex->mutex)) return FALSE;
163     }
164   counter++;
165   g_static_private_set (&mutex->counter, GUINT_TO_POINTER (counter), NULL);
166   return TRUE;
167 }
168
169 void
170 g_static_rec_mutex_unlock (GStaticRecMutex* mutex)
171 {
172   guint counter = GPOINTER_TO_UINT (g_static_private_get (&mutex->counter));
173   if (counter == 1)
174     {
175       g_static_mutex_unlock (&mutex->mutex);
176     }
177   counter--;
178   g_static_private_set (&mutex->counter, GUINT_TO_POINTER (counter), NULL);
179 }
180 #endif /* g_static_rec_mutex_lock */
181
182 gpointer
183 g_static_private_get (GStaticPrivate *private_key)
184 {
185   return g_static_private_get_for_thread (private_key, g_thread_self ());
186 }
187
188 gpointer
189 g_static_private_get_for_thread (GStaticPrivate *private_key,
190                                  GThread        *thread)
191 {
192   GArray *array;
193   GRealThread *self = (GRealThread*) thread;
194
195   g_return_val_if_fail (thread, NULL);
196
197   array = self->private_data;
198   if (!array)
199     return NULL;
200
201   if (!private_key->index)
202     return NULL;
203   else if (private_key->index <= array->len)
204     return g_array_index (array, GStaticPrivateNode, private_key->index - 1).data;
205   else
206     return NULL;
207 }
208
209 void
210 g_static_private_set (GStaticPrivate *private_key, 
211                       gpointer        data,
212                       GDestroyNotify  notify)
213 {
214   g_static_private_set_for_thread (private_key, g_thread_self (), 
215                                    data, notify);
216 }
217
218 void
219 g_static_private_set_for_thread (GStaticPrivate *private_key, 
220                                  GThread        *thread,
221                                  gpointer        data,
222                                  GDestroyNotify  notify)
223 {
224   GArray *array;
225   GRealThread *self =(GRealThread*) thread;
226   static guint next_index = 0;
227   GStaticPrivateNode *node;
228
229   g_return_if_fail (thread);
230   
231   array = self->private_data;
232   if (!array)
233     {
234       array = g_array_new (FALSE, TRUE, sizeof (GStaticPrivateNode));
235       self->private_data = array;
236     }
237
238   if (!private_key->index)
239     {
240       g_mutex_lock (g_thread_specific_mutex);
241
242       if (!private_key->index)
243         private_key->index = ++next_index;
244
245       g_mutex_unlock (g_thread_specific_mutex);
246     }
247
248   if (private_key->index > array->len)
249     g_array_set_size (array, private_key->index);
250
251   node = &g_array_index (array, GStaticPrivateNode, private_key->index - 1);
252   if (node->destroy)
253     {
254       gpointer ddata = node->data;
255       GDestroyNotify ddestroy = node->destroy;
256
257       node->data = data;
258       node->destroy = notify;
259
260       ddestroy (ddata);
261     }
262   else
263     {
264       node->data = data;
265       node->destroy = notify;
266     }
267 }
268
269 static void
270 g_thread_cleanup (gpointer data)
271 {
272   if (data)
273     {
274       GRealThread* thread = data;
275       if (thread->private_data)
276         {
277           GArray* array = thread->private_data;
278           guint i;
279           
280           for (i = 0; i < array->len; i++ )
281             {
282               GStaticPrivateNode *node = 
283                 &g_array_index (array, GStaticPrivateNode, i);
284               if (node->destroy)
285                 node->destroy (node->data);
286             }
287           g_array_free (array, TRUE);
288         }
289       /* We only free the thread structure, if it isn't joinable. If
290          it is, the structure is freed in g_thread_join */
291       if (!thread->thread.joinable)
292         {
293           /* Just to make sure, this isn't used any more */
294           thread->system_thread = NULL;
295           g_free (thread);
296         }
297     }
298 }
299
300 static void
301 g_thread_fail (void)
302 {
303   g_error ("The thread system is not yet initialized.");
304 }
305
306 G_LOCK_DEFINE_STATIC (g_thread_create);
307
308 static void 
309 g_thread_create_proxy (gpointer data)
310 {
311   GRealThread* thread = data;
312
313   g_assert (data);
314
315   /* the lock makes sure, that thread->system_thread is written,
316      before thread->func is called. See g_thread_create */
317
318   G_LOCK (g_thread_create);
319   g_private_set (g_thread_specific_private, data);
320   G_UNLOCK (g_thread_create);
321
322   thread->func (thread->arg);
323 }
324
325 GThread* 
326 g_thread_create (GThreadFunc             thread_func,
327                  gpointer                arg,
328                  gulong                  stack_size,
329                  gboolean                joinable,
330                  gboolean                bound,
331                  GThreadPriority         priority)
332 {
333   GRealThread* result = g_new0 (GRealThread,1);
334
335   g_return_val_if_fail (thread_func, NULL);
336   
337   result->thread.joinable = joinable;
338   result->thread.bound = bound;
339   result->thread.priority = priority;
340   result->func = thread_func;
341   result->arg = arg;
342   G_LOCK (g_thread_create);
343   result->system_thread = G_THREAD_UF (thread_create, (g_thread_create_proxy, 
344                                                        result, stack_size, 
345                                                        joinable, bound, 
346                                                        priority));
347   G_UNLOCK (g_thread_create);
348   return (GThread*) result;
349 }
350
351 void 
352 g_thread_join (GThread* thread)
353 {
354   GRealThread* real = (GRealThread*) thread;
355
356   g_return_if_fail (thread);
357   g_return_if_fail (thread->joinable);
358   g_return_if_fail (real->system_thread);
359
360   G_THREAD_UF (thread_join, (real->system_thread));
361
362   /* Just to make sure, this isn't used any more */
363   thread->joinable = 0;
364   real->system_thread = NULL;
365
366   /* the thread structure for non-joinable threads is freed upon
367      thread end. We free the memory here. This will leave loose end,
368      if a joinable thread is not joined. */
369
370   g_free (thread);
371 }
372
373 void
374 g_thread_set_priority (GThread* thread, 
375                        GThreadPriority priority)
376 {
377   GRealThread* real = (GRealThread*) thread;
378
379   g_return_if_fail (thread);
380   g_return_if_fail (real->system_thread);
381
382   thread->priority = priority;
383   G_THREAD_CF (thread_set_priority, (void)0, (real->system_thread, priority));
384 }
385
386 GThread*
387 g_thread_self()
388 {
389   GRealThread* thread = g_private_get (g_thread_specific_private);
390
391   if (!thread)
392     {  
393       /* If no thread data is available, provide and set one.  This
394          can happen for the main thread and for threads, that are not
395          created by glib. */
396       thread = g_new (GRealThread,1);
397       thread->thread.joinable = FALSE; /* This is a save guess */
398       thread->thread.bound = TRUE; /* This isn't important at all */
399       thread->thread.priority = G_THREAD_PRIORITY_NORMAL; /* This is
400                                                              just a guess */
401       thread->func = NULL;
402       thread->arg = NULL;
403       thread->system_thread = NULL;
404       thread->private_data = NULL;
405       g_private_set (g_thread_specific_private, thread);
406     }
407      
408   if (g_thread_supported () && !thread->system_thread)
409     {
410       thread->system_thread = g_thread_functions_for_glib_use.thread_self();
411     }
412
413   return (GThread*)thread;
414 }
415
416 static void inline g_static_rw_lock_wait (GCond** cond, GStaticMutex* mutex)
417 {
418   if (!*cond)
419       *cond = g_cond_new ();
420   g_cond_wait (*cond, g_static_mutex_get_mutex (mutex));
421 }
422
423 static void inline g_static_rw_lock_signal (GStaticRWLock* lock)
424 {
425   if (lock->want_to_write && lock->write_cond)
426     g_cond_signal (lock->write_cond);
427   else if (lock->read_cond)
428     g_cond_signal (lock->read_cond);
429 }
430
431 void g_static_rw_lock_reader_lock (GStaticRWLock* lock)
432 {
433   g_return_if_fail (lock);
434
435   if (!g_threads_got_initialized)
436     return;
437
438   g_static_mutex_lock (&lock->mutex);
439   while (lock->write || lock->want_to_write) 
440     g_static_rw_lock_wait (&lock->read_cond, &lock->mutex);
441   lock->read_counter++;
442   g_static_mutex_unlock (&lock->mutex);
443 }
444
445 gboolean g_static_rw_lock_reader_trylock (GStaticRWLock* lock)
446 {
447   gboolean ret_val = FALSE;
448
449   g_return_val_if_fail (lock, FALSE);
450
451   if (!g_threads_got_initialized)
452     return TRUE;
453
454   g_static_mutex_lock (&lock->mutex);
455   if (!lock->write && !lock->want_to_write)
456     {
457       lock->read_counter++;
458       ret_val = TRUE;
459     }
460   g_static_mutex_unlock (&lock->mutex);
461   return ret_val;
462 }
463
464 void g_static_rw_lock_reader_unlock  (GStaticRWLock* lock)
465 {
466   g_return_if_fail (lock);
467
468   if (!g_threads_got_initialized)
469     return;
470
471   g_static_mutex_lock (&lock->mutex);
472   lock->read_counter--;
473   g_static_rw_lock_signal (lock);
474   g_static_mutex_unlock (&lock->mutex);
475 }
476
477 void g_static_rw_lock_writer_lock (GStaticRWLock* lock)
478 {
479   g_return_if_fail (lock);
480
481   if (!g_threads_got_initialized)
482     return;
483
484   g_static_mutex_lock (&lock->mutex);
485   lock->want_to_write++;
486   while (lock->write || lock->read_counter)
487     g_static_rw_lock_wait (&lock->write_cond, &lock->mutex);
488   lock->want_to_write--;
489   lock->write = TRUE;
490   g_static_mutex_unlock (&lock->mutex);
491 }
492
493 gboolean g_static_rw_lock_writer_trylock (GStaticRWLock* lock)
494 {
495   gboolean ret_val = FALSE;
496
497   g_return_val_if_fail (lock, FALSE);
498   
499   if (!g_threads_got_initialized)
500     return TRUE;
501
502   g_static_mutex_lock (&lock->mutex);
503   if (!lock->write && !lock->read_counter)
504     {
505       lock->write = TRUE;
506       ret_val = TRUE;
507     }
508   g_static_mutex_unlock (&lock->mutex);
509   return ret_val;
510 }
511
512 void g_static_rw_lock_writer_unlock (GStaticRWLock* lock)
513 {
514   g_return_if_fail (lock);
515   
516   if (!g_threads_got_initialized)
517     return;
518
519   g_static_mutex_lock (&lock->mutex);
520   lock->write = FALSE; 
521   g_static_rw_lock_signal (lock);
522   g_static_mutex_unlock (&lock->mutex);
523 }
524
525 void g_static_rw_lock_free (GStaticRWLock* lock)
526 {
527   g_return_if_fail (lock);
528   
529   if (lock->read_cond)
530     g_cond_free (lock->read_cond);
531   if (lock->write_cond)
532     g_cond_free (lock->write_cond);
533   
534 }
535