Add gprintfint.h and trio.
[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 Lesser 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  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser 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-2000.  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 "config.h"
36
37 #ifdef G_THREAD_USE_PID_SURROGATE
38 #include <sys/types.h>
39 #include <sys/time.h>
40 #include <sys/resource.h>
41 #include <errno.h>
42 #endif /* G_THREAD_USE_PID_SURROGATE */
43
44 #ifdef HAVE_UNISTD_H
45 #include <unistd.h>
46 #endif
47
48 #include <string.h>
49
50 #include "glib.h"
51
52
53 #if GLIB_SIZEOF_SYSTEM_THREAD == SIZEOF_VOID_P
54 # define g_system_thread_equal_simple(thread1, thread2)                 \
55    ((thread1).dummy_pointer == (thread2).dummy_pointer)
56 # define g_system_thread_assign(dest, src)                              \
57    ((dest).dummy_pointer = (src).dummy_pointer)
58 #else /* GLIB_SIZEOF_SYSTEM_THREAD != SIZEOF_VOID_P */
59 # define g_system_thread_equal_simple(thread1, thread2)                 \
60    (memcmp (&(thread1), &(thread2), GLIB_SIZEOF_SYSTEM_THREAD) == 0)
61 # define g_system_thread_assign(dest, src)                              \
62    (memcpy (&(dest), &(src), GLIB_SIZEOF_SYSTEM_THREAD))
63 #endif /* GLIB_SIZEOF_SYSTEM_THREAD == SIZEOF_VOID_P */
64
65 #define g_system_thread_equal(thread1, thread2)                         \
66   (g_thread_functions_for_glib_use.thread_equal ?                       \
67    g_thread_functions_for_glib_use.thread_equal (&(thread1), &(thread2)) :\
68    g_system_thread_equal_simple((thread1), (thread2)))
69
70 GQuark 
71 g_thread_error_quark (void)
72 {
73   static GQuark quark;
74   if (!quark)
75     quark = g_quark_from_static_string ("g_thread_error");
76   return quark;
77 }
78
79 /* Keep this in sync with GRealThread in gmain.c! */
80 typedef struct _GRealThread GRealThread;
81 struct  _GRealThread
82 {
83   GThread thread;
84   gpointer private_data;
85   gpointer retval;
86   GSystemThread system_thread;
87 #ifdef G_THREAD_USE_PID_SURROGATE
88   pid_t pid;
89 #endif /* G_THREAD_USE_PID_SURROGATE */
90 };
91
92 #ifdef G_THREAD_USE_PID_SURROGATE
93 static gint priority_map[4];
94 static gboolean prio_warned = FALSE;
95 # define SET_PRIO(pid, prio) G_STMT_START{                              \
96   gint error = setpriority (PRIO_PROCESS, (pid), priority_map[prio]);   \
97   if (error == -1 && errno == EACCES && !prio_warned)                   \
98     {                                                                   \
99       prio_warned = TRUE;                                               \
100       g_warning ("Priorities can only be increased by root.");          \
101     }                                                                   \
102   }G_STMT_END
103 #endif /* G_THREAD_USE_PID_SURROGATE */
104
105 typedef struct _GStaticPrivateNode GStaticPrivateNode;
106 struct _GStaticPrivateNode
107 {
108   gpointer       data;
109   GDestroyNotify destroy;
110 };
111
112 static void g_thread_cleanup (gpointer data);
113 static void g_thread_fail (void);
114
115 /* Global variables */
116
117 static GSystemThread zero_thread; /* This is initialized to all zero */
118 gboolean g_thread_use_default_impl = TRUE;
119 gboolean g_threads_got_initialized = FALSE;
120
121 #if defined(G_PLATFORM_WIN32) && defined(__GNUC__)
122 __declspec(dllexport)
123 #endif
124 GThreadFunctions g_thread_functions_for_glib_use = {
125   (GMutex*(*)())g_thread_fail,                 /* mutex_new */
126   NULL,                                        /* mutex_lock */
127   NULL,                                        /* mutex_trylock */
128   NULL,                                        /* mutex_unlock */
129   NULL,                                        /* mutex_free */
130   (GCond*(*)())g_thread_fail,                  /* cond_new */
131   NULL,                                        /* cond_signal */
132   NULL,                                        /* cond_broadcast */
133   NULL,                                        /* cond_wait */
134   NULL,                                        /* cond_timed_wait  */
135   NULL,                                        /* cond_free */
136   (GPrivate*(*)(GDestroyNotify))g_thread_fail, /* private_new */
137   NULL,                                        /* private_get */
138   NULL,                                        /* private_set */
139   (void(*)(GThreadFunc, gpointer, gulong, 
140            gboolean, gboolean, GThreadPriority, 
141            gpointer, GError**))g_thread_fail,  /* thread_create */
142   NULL,                                        /* thread_yield */
143   NULL,                                        /* thread_join */
144   NULL,                                        /* thread_exit */
145   NULL,                                        /* thread_set_priority */
146   NULL                                         /* thread_self */
147 }; 
148
149 /* Local data */
150
151 static GMutex   *g_mutex_protect_static_mutex_allocation = NULL;
152 static GPrivate *g_thread_specific_private = NULL;
153 static GSList   *g_thread_all_threads = NULL;
154 static GSList   *g_thread_free_indeces = NULL;
155
156 G_LOCK_DEFINE_STATIC (g_thread);
157
158 /* This must be called only once, before any threads are created.
159  * It will only be called from g_thread_init() in -lgthread.
160  */
161 void
162 g_mutex_init (void)
163 {
164   GRealThread* main_thread;
165  
166   /* We let the main thread (the one that calls g_thread_init) inherit
167    * the data, that it set before calling g_thread_init
168    */
169   main_thread = (GRealThread*) g_thread_self ();
170
171   g_thread_specific_private = g_private_new (g_thread_cleanup);
172   G_THREAD_UF (private_set, (g_thread_specific_private, main_thread));
173   G_THREAD_UF (thread_self, (&main_thread->system_thread));
174
175   g_mutex_protect_static_mutex_allocation = g_mutex_new ();
176
177 #ifdef G_THREAD_USE_PID_SURROGATE
178   priority_map[G_THREAD_PRIORITY_NORMAL] = 
179     getpriority (PRIO_PROCESS, (getpid ()));
180   priority_map[G_THREAD_PRIORITY_LOW] = 
181     MIN (20, priority_map[G_THREAD_PRIORITY_NORMAL] + 10);
182   priority_map[G_THREAD_PRIORITY_HIGH] = 
183     MAX (-20, priority_map[G_THREAD_PRIORITY_NORMAL] - 10);
184   priority_map[G_THREAD_PRIORITY_URGENT] = 
185     MAX (-20, priority_map[G_THREAD_PRIORITY_NORMAL] - 15);
186 #endif /* G_THREAD_USE_PID_SURROGATE */
187 }
188
189 void 
190 g_static_mutex_init (GStaticMutex *mutex)
191 {
192   static GStaticMutex init_mutex = G_STATIC_MUTEX_INIT;
193
194   g_return_if_fail (mutex);
195
196   *mutex = init_mutex;
197 }
198
199 GMutex *
200 g_static_mutex_get_mutex_impl (GMutex** mutex)
201 {
202   if (!g_thread_supported ())
203     return NULL;
204
205   g_assert (g_mutex_protect_static_mutex_allocation);
206
207   g_mutex_lock (g_mutex_protect_static_mutex_allocation);
208
209   if (!(*mutex)) 
210     *mutex = g_mutex_new (); 
211
212   g_mutex_unlock (g_mutex_protect_static_mutex_allocation);
213   
214   return *mutex;
215 }
216
217 void
218 g_static_mutex_free (GStaticMutex* mutex)
219 {
220   GMutex **runtime_mutex;
221   
222   g_return_if_fail (mutex);
223
224   /* The runtime_mutex is the first (or only) member of GStaticMutex,
225    * see both versions (of glibconfig.h) in configure.in */
226   runtime_mutex = ((GMutex**)mutex);
227   
228   if (*runtime_mutex)
229     g_mutex_free (*runtime_mutex);
230
231   *runtime_mutex = NULL;
232 }
233
234 void     
235 g_static_rec_mutex_init (GStaticRecMutex *mutex)
236 {
237   static GStaticRecMutex init_mutex = G_STATIC_REC_MUTEX_INIT;
238   
239   g_return_if_fail (mutex);
240
241   *mutex = init_mutex;
242 }
243
244 void
245 g_static_rec_mutex_lock (GStaticRecMutex* mutex)
246 {
247   GSystemThread self;
248
249   g_return_if_fail (mutex);
250
251   if (!g_thread_supported ())
252     return;
253
254   G_THREAD_UF (thread_self, (&self));
255
256   if (g_system_thread_equal (self, mutex->owner))
257     {
258       mutex->depth++;
259       return;
260     }
261   g_static_mutex_lock (&mutex->mutex);
262   g_system_thread_assign (mutex->owner, self);
263   mutex->depth = 1;
264 }
265
266 gboolean
267 g_static_rec_mutex_trylock (GStaticRecMutex* mutex)
268 {
269   GSystemThread self;
270
271   g_return_val_if_fail (mutex, FALSE);
272
273   if (!g_thread_supported ())
274     return TRUE;
275
276   G_THREAD_UF (thread_self, (&self));
277
278   if (g_system_thread_equal (self, mutex->owner))
279     {
280       mutex->depth++;
281       return TRUE;
282     }
283
284   if (!g_static_mutex_trylock (&mutex->mutex))
285     return FALSE;
286
287   g_system_thread_assign (mutex->owner, self);
288   mutex->depth = 1;
289   return TRUE;
290 }
291
292 void
293 g_static_rec_mutex_unlock (GStaticRecMutex* mutex)
294 {
295   g_return_if_fail (mutex);
296
297   if (!g_thread_supported ())
298     return;
299
300   if (mutex->depth > 1)
301     {
302       mutex->depth--;
303       return;
304     }
305   g_system_thread_assign (mutex->owner, zero_thread);
306   g_static_mutex_unlock (&mutex->mutex);  
307 }
308
309 void
310 g_static_rec_mutex_lock_full   (GStaticRecMutex *mutex,
311                                 guint            depth)
312 {
313   GSystemThread self;
314   g_return_if_fail (mutex);
315
316   if (!g_thread_supported ())
317     return;
318
319   G_THREAD_UF (thread_self, (&self));
320
321   if (g_system_thread_equal (self, mutex->owner))
322     {
323       mutex->depth += depth;
324       return;
325     }
326   g_static_mutex_lock (&mutex->mutex);
327   g_system_thread_assign (mutex->owner, self);
328   mutex->depth = depth;
329 }
330
331 guint    
332 g_static_rec_mutex_unlock_full (GStaticRecMutex *mutex)
333 {
334   guint depth;
335
336   g_return_val_if_fail (mutex, 0);
337
338   if (!g_thread_supported ())
339     return 1;
340
341   depth = mutex->depth;
342
343   g_system_thread_assign (mutex->owner, zero_thread);
344   mutex->depth = 0;
345   g_static_mutex_unlock (&mutex->mutex);
346
347   return depth;
348 }
349
350 void
351 g_static_rec_mutex_free (GStaticRecMutex *mutex)
352 {
353   g_return_if_fail (mutex);
354
355   g_static_mutex_free (&mutex->mutex);
356 }
357
358 void     
359 g_static_private_init (GStaticPrivate *private_key)
360 {
361   private_key->index = 0;
362 }
363
364 gpointer
365 g_static_private_get (GStaticPrivate *private_key)
366 {
367   GRealThread *self = (GRealThread*) g_thread_self ();
368   GArray *array;
369
370   array = self->private_data;
371   if (!array)
372     return NULL;
373
374   if (!private_key->index)
375     return NULL;
376   else if (private_key->index <= array->len)
377     return g_array_index (array, GStaticPrivateNode, 
378                           private_key->index - 1).data;
379   else
380     return NULL;
381 }
382
383 void
384 g_static_private_set (GStaticPrivate *private_key, 
385                       gpointer        data,
386                       GDestroyNotify  notify)
387 {
388   GRealThread *self = (GRealThread*) g_thread_self ();
389   GArray *array;
390   static guint next_index = 0;
391   GStaticPrivateNode *node;
392
393   array = self->private_data;
394   if (!array)
395     {
396       array = g_array_new (FALSE, TRUE, sizeof (GStaticPrivateNode));
397       self->private_data = array;
398     }
399
400   if (!private_key->index)
401     {
402       G_LOCK (g_thread);
403
404       if (!private_key->index)
405         {
406           if (g_thread_free_indeces)
407             {
408               private_key->index = 
409                 GPOINTER_TO_UINT (g_thread_free_indeces->data);
410               g_thread_free_indeces = 
411                 g_slist_delete_link (g_thread_free_indeces,
412                                      g_thread_free_indeces);
413             }
414           else
415             private_key->index = ++next_index;
416         }
417
418       G_UNLOCK (g_thread);
419     }
420
421   if (private_key->index > array->len)
422     g_array_set_size (array, private_key->index);
423
424   node = &g_array_index (array, GStaticPrivateNode, private_key->index - 1);
425   if (node->destroy)
426     {
427       gpointer ddata = node->data;
428       GDestroyNotify ddestroy = node->destroy;
429
430       node->data = data;
431       node->destroy = notify;
432
433       ddestroy (ddata);
434     }
435   else
436     {
437       node->data = data;
438       node->destroy = notify;
439     }
440 }
441
442 void     
443 g_static_private_free (GStaticPrivate *private_key)
444 {
445   guint index = private_key->index;
446   GSList *list;
447
448   if (!index)
449     return;
450   
451   private_key->index = 0;
452
453   G_LOCK (g_thread);
454   list =  g_thread_all_threads;
455   while (list)
456     {
457       GRealThread *thread = list->data;
458       GArray *array = thread->private_data;
459       list = list->next;
460
461       if (array && index <= array->len)
462         {
463           GStaticPrivateNode *node = &g_array_index (array, 
464                                                      GStaticPrivateNode, 
465                                                      index - 1);
466           gpointer ddata = node->data;
467           GDestroyNotify ddestroy = node->destroy;
468
469           node->data = NULL;
470           node->destroy = NULL;
471
472           if (ddestroy) 
473             {
474               G_UNLOCK (g_thread);
475               ddestroy (ddata);
476               G_LOCK (g_thread);
477               }
478         }
479     }
480   g_thread_free_indeces = g_slist_prepend (g_thread_free_indeces, 
481                                            GUINT_TO_POINTER (index));
482   G_UNLOCK (g_thread);
483 }
484
485 static void
486 g_thread_cleanup (gpointer data)
487 {
488   if (data)
489     {
490       GRealThread* thread = data;
491       if (thread->private_data)
492         {
493           GArray* array = thread->private_data;
494           guint i;
495           
496           for (i = 0; i < array->len; i++ )
497             {
498               GStaticPrivateNode *node = 
499                 &g_array_index (array, GStaticPrivateNode, i);
500               if (node->destroy)
501                 node->destroy (node->data);
502             }
503           g_array_free (array, TRUE);
504         }
505
506       /* We only free the thread structure, if it isn't joinable. If
507          it is, the structure is freed in g_thread_join */
508       if (!thread->thread.joinable)
509         {
510           G_LOCK (g_thread);
511           g_thread_all_threads = g_slist_remove (g_thread_all_threads, data);
512           G_UNLOCK (g_thread);
513           
514           /* Just to make sure, this isn't used any more */
515           g_system_thread_assign (thread->system_thread, zero_thread);
516           g_free (thread);
517         }
518     }
519 }
520
521 static void
522 g_thread_fail (void)
523 {
524   g_error ("The thread system is not yet initialized.");
525 }
526
527 static gpointer
528 g_thread_create_proxy (gpointer data)
529 {
530   GRealThread* thread = data;
531
532   g_assert (data);
533
534 #ifdef G_THREAD_USE_PID_SURROGATE
535   thread->pid = getpid ();
536 #endif /* G_THREAD_USE_PID_SURROGATE */
537
538   /* This has to happen before G_LOCK, as that might call g_thread_self */
539   g_private_set (g_thread_specific_private, data);
540
541   /* the lock makes sure, that thread->system_thread is written,
542      before thread->thread.func is called. See g_thread_create. */
543   G_LOCK (g_thread);
544   G_UNLOCK (g_thread);
545  
546 #ifdef G_THREAD_USE_PID_SURROGATE
547   if (g_thread_use_default_impl)
548     SET_PRIO (thread->pid, thread->thread.priority);
549 #endif /* G_THREAD_USE_PID_SURROGATE */
550
551   thread->retval = thread->thread.func (thread->thread.data);
552
553   return NULL;
554 }
555
556 GThread* 
557 g_thread_create_full (GThreadFunc                func,
558                       gpointer           data,
559                       gulong             stack_size,
560                       gboolean           joinable,
561                       gboolean           bound,
562                       GThreadPriority    priority,
563                       GError                **error)
564 {
565   GRealThread* result;
566   GError *local_error = NULL;
567   g_return_val_if_fail (func, NULL);
568   g_return_val_if_fail (priority >= G_THREAD_PRIORITY_LOW, NULL);
569   g_return_val_if_fail (priority <= G_THREAD_PRIORITY_URGENT, NULL);
570   
571   result = g_new (GRealThread, 1);
572
573   result->thread.joinable = joinable;
574   result->thread.priority = priority;
575   result->thread.func = func;
576   result->thread.data = data;
577   result->private_data = NULL; 
578   G_LOCK (g_thread);
579   G_THREAD_UF (thread_create, (g_thread_create_proxy, result, 
580                                stack_size, joinable, bound, priority,
581                                &result->system_thread, &local_error));
582   g_thread_all_threads = g_slist_prepend (g_thread_all_threads, result);
583   G_UNLOCK (g_thread);
584
585   if (local_error)
586     {
587       g_propagate_error (error, local_error);
588       g_free (result);
589       return NULL;
590     }
591
592   return (GThread*) result;
593 }
594
595 void
596 g_thread_exit (gpointer retval)
597 {
598   GRealThread* real = (GRealThread*) g_thread_self ();
599   real->retval = retval;
600   G_THREAD_CF (thread_exit, (void)0, ());
601 }
602
603 gpointer
604 g_thread_join (GThread* thread)
605 {
606   GRealThread* real = (GRealThread*) thread;
607   gpointer retval;
608
609   g_return_val_if_fail (thread, NULL);
610   g_return_val_if_fail (thread->joinable, NULL);
611   g_return_val_if_fail (!g_system_thread_equal (real->system_thread, 
612                                                 zero_thread), NULL);
613
614   G_THREAD_UF (thread_join, (&real->system_thread));
615
616   retval = real->retval;
617
618   G_LOCK (g_thread);
619   g_thread_all_threads = g_slist_remove (g_thread_all_threads, thread);
620   G_UNLOCK (g_thread);
621
622   /* Just to make sure, this isn't used any more */
623   thread->joinable = 0;
624   g_system_thread_assign (real->system_thread, zero_thread);
625
626   /* the thread structure for non-joinable threads is freed upon
627      thread end. We free the memory here. This will leave a loose end,
628      if a joinable thread is not joined. */
629
630   g_free (thread);
631
632   return retval;
633 }
634
635 void
636 g_thread_set_priority (GThread* thread, 
637                        GThreadPriority priority)
638 {
639   GRealThread* real = (GRealThread*) thread;
640
641   g_return_if_fail (thread);
642   g_return_if_fail (!g_system_thread_equal (real->system_thread, zero_thread));
643   g_return_if_fail (priority >= G_THREAD_PRIORITY_LOW);
644   g_return_if_fail (priority <= G_THREAD_PRIORITY_URGENT);
645
646   thread->priority = priority;
647
648 #ifdef G_THREAD_USE_PID_SURROGATE
649   if (g_thread_use_default_impl)
650     SET_PRIO (real->pid, priority);
651   else
652 #endif /* G_THREAD_USE_PID_SURROGATE */
653     G_THREAD_CF (thread_set_priority, (void)0, 
654                  (&real->system_thread, priority));
655 }
656
657 GThread*
658 g_thread_self (void)
659 {
660   GRealThread* thread = g_private_get (g_thread_specific_private);
661
662   if (!thread)
663     {  
664       /* If no thread data is available, provide and set one.  This
665          can happen for the main thread and for threads, that are not
666          created by GLib. */
667       thread = g_new (GRealThread, 1);
668       thread->thread.joinable = FALSE; /* This is a save guess */
669       thread->thread.priority = G_THREAD_PRIORITY_NORMAL; /* This is
670                                                              just a guess */
671       thread->thread.func = NULL;
672       thread->thread.data = NULL;
673       thread->private_data = NULL;
674
675       if (g_thread_supported ())
676         G_THREAD_UF (thread_self, (&thread->system_thread));
677
678 #ifdef G_THREAD_USE_PID_SURROGATE
679       thread->pid = getpid ();
680 #endif /* G_THREAD_USE_PID_SURROGATE */
681       
682       g_private_set (g_thread_specific_private, thread); 
683       
684       G_LOCK (g_thread);
685       g_thread_all_threads = g_slist_prepend (g_thread_all_threads, thread);
686       G_UNLOCK (g_thread);
687     }
688   
689   return (GThread*)thread;
690 }
691
692 void
693 g_static_rw_lock_init (GStaticRWLock* lock)
694 {
695   static GStaticRWLock init_lock = G_STATIC_RW_LOCK_INIT;
696
697   g_return_if_fail (lock);
698
699   *lock = init_lock;
700 }
701
702 static void inline 
703 g_static_rw_lock_wait (GCond** cond, GStaticMutex* mutex)
704 {
705   if (!*cond)
706       *cond = g_cond_new ();
707   g_cond_wait (*cond, g_static_mutex_get_mutex (mutex));
708 }
709
710 static void inline 
711 g_static_rw_lock_signal (GStaticRWLock* lock)
712 {
713   if (lock->want_to_write && lock->write_cond)
714     g_cond_signal (lock->write_cond);
715   else if (lock->want_to_read && lock->read_cond)
716     g_cond_broadcast (lock->read_cond);
717 }
718
719 void 
720 g_static_rw_lock_reader_lock (GStaticRWLock* lock)
721 {
722   g_return_if_fail (lock);
723
724   if (!g_threads_got_initialized)
725     return;
726
727   g_static_mutex_lock (&lock->mutex);
728   lock->want_to_read++;
729   while (lock->write || lock->want_to_write) 
730     g_static_rw_lock_wait (&lock->read_cond, &lock->mutex);
731   lock->want_to_read--;
732   lock->read_counter++;
733   g_static_mutex_unlock (&lock->mutex);
734 }
735
736 gboolean 
737 g_static_rw_lock_reader_trylock (GStaticRWLock* lock)
738 {
739   gboolean ret_val = FALSE;
740
741   g_return_val_if_fail (lock, FALSE);
742
743   if (!g_threads_got_initialized)
744     return TRUE;
745
746   g_static_mutex_lock (&lock->mutex);
747   if (!lock->write && !lock->want_to_write)
748     {
749       lock->read_counter++;
750       ret_val = TRUE;
751     }
752   g_static_mutex_unlock (&lock->mutex);
753   return ret_val;
754 }
755
756 void 
757 g_static_rw_lock_reader_unlock  (GStaticRWLock* lock)
758 {
759   g_return_if_fail (lock);
760
761   if (!g_threads_got_initialized)
762     return;
763
764   g_static_mutex_lock (&lock->mutex);
765   lock->read_counter--;
766   if (lock->read_counter == 0)
767     g_static_rw_lock_signal (lock);
768   g_static_mutex_unlock (&lock->mutex);
769 }
770
771 void 
772 g_static_rw_lock_writer_lock (GStaticRWLock* lock)
773 {
774   g_return_if_fail (lock);
775
776   if (!g_threads_got_initialized)
777     return;
778
779   g_static_mutex_lock (&lock->mutex);
780   lock->want_to_write++;
781   while (lock->write || lock->read_counter)
782     g_static_rw_lock_wait (&lock->write_cond, &lock->mutex);
783   lock->want_to_write--;
784   lock->write = TRUE;
785   g_static_mutex_unlock (&lock->mutex);
786 }
787
788 gboolean 
789 g_static_rw_lock_writer_trylock (GStaticRWLock* lock)
790 {
791   gboolean ret_val = FALSE;
792
793   g_return_val_if_fail (lock, FALSE);
794   
795   if (!g_threads_got_initialized)
796     return TRUE;
797
798   g_static_mutex_lock (&lock->mutex);
799   if (!lock->write && !lock->read_counter)
800     {
801       lock->write = TRUE;
802       ret_val = TRUE;
803     }
804   g_static_mutex_unlock (&lock->mutex);
805   return ret_val;
806 }
807
808 void 
809 g_static_rw_lock_writer_unlock (GStaticRWLock* lock)
810 {
811   g_return_if_fail (lock);
812   
813   if (!g_threads_got_initialized)
814     return;
815
816   g_static_mutex_lock (&lock->mutex);
817   lock->write = FALSE; 
818   g_static_rw_lock_signal (lock);
819   g_static_mutex_unlock (&lock->mutex);
820 }
821
822 void 
823 g_static_rw_lock_free (GStaticRWLock* lock)
824 {
825   g_return_if_fail (lock);
826   
827   if (lock->read_cond)
828     {
829       g_cond_free (lock->read_cond);
830       lock->read_cond = NULL;
831     }
832   if (lock->write_cond)
833     {
834       g_cond_free (lock->write_cond);
835       lock->write_cond = NULL;
836     }
837   g_static_mutex_free (&lock->mutex);
838 }