updated [and finally fixed my script to produce ready to go de-in(ed)
[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  * gthread.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 HAVE_UNISTD_H
38 #include <unistd.h>
39 #endif
40
41 #include <string.h>
42
43 #include "galias.h"
44 #include "glib.h"
45 #include "gthreadinit.h"
46
47 #if GLIB_SIZEOF_SYSTEM_THREAD == SIZEOF_VOID_P
48 # define g_system_thread_equal_simple(thread1, thread2)                 \
49    ((thread1).dummy_pointer == (thread2).dummy_pointer)
50 # define g_system_thread_assign(dest, src)                              \
51    ((dest).dummy_pointer = (src).dummy_pointer)
52 #else /* GLIB_SIZEOF_SYSTEM_THREAD != SIZEOF_VOID_P */
53 # define g_system_thread_equal_simple(thread1, thread2)                 \
54    (memcmp (&(thread1), &(thread2), GLIB_SIZEOF_SYSTEM_THREAD) == 0)
55 # define g_system_thread_assign(dest, src)                              \
56    (memcpy (&(dest), &(src), GLIB_SIZEOF_SYSTEM_THREAD))
57 #endif /* GLIB_SIZEOF_SYSTEM_THREAD == SIZEOF_VOID_P */
58
59 #define g_system_thread_equal(thread1, thread2)                         \
60   (g_thread_functions_for_glib_use.thread_equal ?                       \
61    g_thread_functions_for_glib_use.thread_equal (&(thread1), &(thread2)) :\
62    g_system_thread_equal_simple((thread1), (thread2)))
63
64 GQuark 
65 g_thread_error_quark (void)
66 {
67   static GQuark quark;
68   if (!quark)
69     quark = g_quark_from_static_string ("g_thread_error");
70   return quark;
71 }
72
73 /* Keep this in sync with GRealThread in gmain.c! */
74 typedef struct _GRealThread GRealThread;
75 struct  _GRealThread
76 {
77   GThread thread;
78   gpointer private_data;
79   gpointer retval;
80   GSystemThread system_thread;
81 };
82
83 typedef struct _GStaticPrivateNode GStaticPrivateNode;
84 struct _GStaticPrivateNode
85 {
86   gpointer       data;
87   GDestroyNotify destroy;
88 };
89
90 static void g_thread_cleanup (gpointer data);
91 static void g_thread_fail (void);
92
93 /* Global variables */
94
95 static GSystemThread zero_thread; /* This is initialized to all zero */
96 gboolean g_thread_use_default_impl = TRUE;
97 gboolean g_threads_got_initialized = FALSE;
98
99 GThreadFunctions g_thread_functions_for_glib_use = {
100   (GMutex*(*)())g_thread_fail,                 /* mutex_new */
101   NULL,                                        /* mutex_lock */
102   NULL,                                        /* mutex_trylock */
103   NULL,                                        /* mutex_unlock */
104   NULL,                                        /* mutex_free */
105   (GCond*(*)())g_thread_fail,                  /* cond_new */
106   NULL,                                        /* cond_signal */
107   NULL,                                        /* cond_broadcast */
108   NULL,                                        /* cond_wait */
109   NULL,                                        /* cond_timed_wait  */
110   NULL,                                        /* cond_free */
111   (GPrivate*(*)(GDestroyNotify))g_thread_fail, /* private_new */
112   NULL,                                        /* private_get */
113   NULL,                                        /* private_set */
114   (void(*)(GThreadFunc, gpointer, gulong, 
115            gboolean, gboolean, GThreadPriority, 
116            gpointer, GError**))g_thread_fail,  /* thread_create */
117   NULL,                                        /* thread_yield */
118   NULL,                                        /* thread_join */
119   NULL,                                        /* thread_exit */
120   NULL,                                        /* thread_set_priority */
121   NULL                                         /* thread_self */
122 }; 
123
124 /* Local data */
125
126 static GMutex   *g_once_mutex = NULL;
127 static GCond    *g_once_cond = NULL;
128 static GPrivate *g_thread_specific_private = NULL;
129 static GSList   *g_thread_all_threads = NULL;
130 static GSList   *g_thread_free_indeces = NULL;
131
132 G_LOCK_DEFINE_STATIC (g_thread);
133
134 #ifdef G_THREADS_ENABLED
135 /* This must be called only once, before any threads are created.
136  * It will only be called from g_thread_init() in -lgthread.
137  */
138 void 
139 g_thread_init_glib (void)
140 {
141   /* We let the main thread (the one that calls g_thread_init) inherit
142    * the static_private data set before calling g_thread_init
143    */
144   GRealThread* main_thread = (GRealThread*) g_thread_self ();
145
146   g_once_mutex = g_mutex_new ();
147   g_once_cond = g_cond_new ();
148
149   _g_convert_thread_init ();
150   _g_rand_thread_init ();
151   _g_main_thread_init ();
152   _g_mem_thread_init ();
153   _g_messages_thread_init ();
154   _g_atomic_thread_init ();
155 #ifdef G_OS_WIN32
156   _g_win32_thread_init ();
157 #endif
158
159   g_threads_got_initialized = TRUE;
160
161   g_thread_specific_private = g_private_new (g_thread_cleanup);
162   g_private_set (g_thread_specific_private, main_thread);
163   G_THREAD_UF (thread_self, (&main_thread->system_thread));
164
165   _g_mem_thread_private_init ();
166   _g_messages_thread_private_init ();
167
168 }
169 #endif /* G_THREADS_ENABLED */
170
171 gpointer 
172 g_once_impl (GOnce       *once, 
173              GThreadFunc  func, 
174              gpointer     arg)
175 {
176   g_mutex_lock (g_once_mutex);
177
178   while (once->status == G_ONCE_STATUS_PROGRESS)
179     g_cond_wait (g_once_cond, g_once_mutex);
180   
181   if (once->status != G_ONCE_STATUS_READY)
182     {
183       once->status = G_ONCE_STATUS_PROGRESS;
184       g_mutex_unlock (g_once_mutex);
185   
186       once->retval = func (arg);
187
188       g_mutex_lock (g_once_mutex);
189       once->status = G_ONCE_STATUS_READY;
190       g_cond_broadcast (g_once_cond);
191     }
192   
193   g_mutex_unlock (g_once_mutex);
194   
195   return once->retval;
196 }
197
198 void 
199 g_static_mutex_init (GStaticMutex *mutex)
200 {
201   static GStaticMutex init_mutex = G_STATIC_MUTEX_INIT;
202
203   g_return_if_fail (mutex);
204
205   *mutex = init_mutex;
206 }
207
208 GMutex *
209 g_static_mutex_get_mutex_impl (GMutex** mutex)
210 {
211   if (!g_thread_supported ())
212     return NULL;
213
214   g_assert (g_once_mutex);
215
216   g_mutex_lock (g_once_mutex);
217
218   if (!(*mutex)) 
219     {
220       GMutex *new_mutex = g_mutex_new (); 
221       
222       /* The following is a memory barrier to avoid the write 
223        * to *new_mutex being reordered to after writing *mutex */
224       g_mutex_lock (new_mutex);
225       g_mutex_unlock (new_mutex);
226       
227       *mutex = new_mutex;
228     }
229
230   g_mutex_unlock (g_once_mutex);
231   
232   return *mutex;
233 }
234
235 void
236 g_static_mutex_free (GStaticMutex* mutex)
237 {
238   GMutex **runtime_mutex;
239   
240   g_return_if_fail (mutex);
241
242   /* The runtime_mutex is the first (or only) member of GStaticMutex,
243    * see both versions (of glibconfig.h) in configure.in */
244   runtime_mutex = ((GMutex**)mutex);
245   
246   if (*runtime_mutex)
247     g_mutex_free (*runtime_mutex);
248
249   *runtime_mutex = NULL;
250 }
251
252 void     
253 g_static_rec_mutex_init (GStaticRecMutex *mutex)
254 {
255   static GStaticRecMutex init_mutex = G_STATIC_REC_MUTEX_INIT;
256   
257   g_return_if_fail (mutex);
258
259   *mutex = init_mutex;
260 }
261
262 void
263 g_static_rec_mutex_lock (GStaticRecMutex* mutex)
264 {
265   GSystemThread self;
266
267   g_return_if_fail (mutex);
268
269   if (!g_thread_supported ())
270     return;
271
272   G_THREAD_UF (thread_self, (&self));
273
274   if (g_system_thread_equal (self, mutex->owner))
275     {
276       mutex->depth++;
277       return;
278     }
279   g_static_mutex_lock (&mutex->mutex);
280   g_system_thread_assign (mutex->owner, self);
281   mutex->depth = 1;
282 }
283
284 gboolean
285 g_static_rec_mutex_trylock (GStaticRecMutex* mutex)
286 {
287   GSystemThread self;
288
289   g_return_val_if_fail (mutex, FALSE);
290
291   if (!g_thread_supported ())
292     return TRUE;
293
294   G_THREAD_UF (thread_self, (&self));
295
296   if (g_system_thread_equal (self, mutex->owner))
297     {
298       mutex->depth++;
299       return TRUE;
300     }
301
302   if (!g_static_mutex_trylock (&mutex->mutex))
303     return FALSE;
304
305   g_system_thread_assign (mutex->owner, self);
306   mutex->depth = 1;
307   return TRUE;
308 }
309
310 void
311 g_static_rec_mutex_unlock (GStaticRecMutex* mutex)
312 {
313   g_return_if_fail (mutex);
314
315   if (!g_thread_supported ())
316     return;
317
318   if (mutex->depth > 1)
319     {
320       mutex->depth--;
321       return;
322     }
323   g_system_thread_assign (mutex->owner, zero_thread);
324   g_static_mutex_unlock (&mutex->mutex);  
325 }
326
327 void
328 g_static_rec_mutex_lock_full   (GStaticRecMutex *mutex,
329                                 guint            depth)
330 {
331   GSystemThread self;
332   g_return_if_fail (mutex);
333
334   if (!g_thread_supported ())
335     return;
336
337   G_THREAD_UF (thread_self, (&self));
338
339   if (g_system_thread_equal (self, mutex->owner))
340     {
341       mutex->depth += depth;
342       return;
343     }
344   g_static_mutex_lock (&mutex->mutex);
345   g_system_thread_assign (mutex->owner, self);
346   mutex->depth = depth;
347 }
348
349 guint    
350 g_static_rec_mutex_unlock_full (GStaticRecMutex *mutex)
351 {
352   guint depth;
353
354   g_return_val_if_fail (mutex, 0);
355
356   if (!g_thread_supported ())
357     return 1;
358
359   depth = mutex->depth;
360
361   g_system_thread_assign (mutex->owner, zero_thread);
362   mutex->depth = 0;
363   g_static_mutex_unlock (&mutex->mutex);
364
365   return depth;
366 }
367
368 void
369 g_static_rec_mutex_free (GStaticRecMutex *mutex)
370 {
371   g_return_if_fail (mutex);
372
373   g_static_mutex_free (&mutex->mutex);
374 }
375
376 void     
377 g_static_private_init (GStaticPrivate *private_key)
378 {
379   private_key->index = 0;
380 }
381
382 gpointer
383 g_static_private_get (GStaticPrivate *private_key)
384 {
385   GRealThread *self = (GRealThread*) g_thread_self ();
386   GArray *array;
387
388   array = self->private_data;
389   if (!array)
390     return NULL;
391
392   if (!private_key->index)
393     return NULL;
394   else if (private_key->index <= array->len)
395     return g_array_index (array, GStaticPrivateNode, 
396                           private_key->index - 1).data;
397   else
398     return NULL;
399 }
400
401 void
402 g_static_private_set (GStaticPrivate *private_key, 
403                       gpointer        data,
404                       GDestroyNotify  notify)
405 {
406   GRealThread *self = (GRealThread*) g_thread_self ();
407   GArray *array;
408   static guint next_index = 0;
409   GStaticPrivateNode *node;
410
411   array = self->private_data;
412   if (!array)
413     {
414       array = g_array_new (FALSE, TRUE, sizeof (GStaticPrivateNode));
415       self->private_data = array;
416     }
417
418   if (!private_key->index)
419     {
420       G_LOCK (g_thread);
421
422       if (!private_key->index)
423         {
424           if (g_thread_free_indeces)
425             {
426               private_key->index = 
427                 GPOINTER_TO_UINT (g_thread_free_indeces->data);
428               g_thread_free_indeces = 
429                 g_slist_delete_link (g_thread_free_indeces,
430                                      g_thread_free_indeces);
431             }
432           else
433             private_key->index = ++next_index;
434         }
435
436       G_UNLOCK (g_thread);
437     }
438
439   if (private_key->index > array->len)
440     g_array_set_size (array, private_key->index);
441
442   node = &g_array_index (array, GStaticPrivateNode, private_key->index - 1);
443   if (node->destroy)
444     {
445       gpointer ddata = node->data;
446       GDestroyNotify ddestroy = node->destroy;
447
448       node->data = data;
449       node->destroy = notify;
450
451       ddestroy (ddata);
452     }
453   else
454     {
455       node->data = data;
456       node->destroy = notify;
457     }
458 }
459
460 void     
461 g_static_private_free (GStaticPrivate *private_key)
462 {
463   guint index = private_key->index;
464   GSList *list;
465
466   if (!index)
467     return;
468   
469   private_key->index = 0;
470
471   G_LOCK (g_thread);
472   list =  g_thread_all_threads;
473   while (list)
474     {
475       GRealThread *thread = list->data;
476       GArray *array = thread->private_data;
477       list = list->next;
478
479       if (array && index <= array->len)
480         {
481           GStaticPrivateNode *node = &g_array_index (array, 
482                                                      GStaticPrivateNode, 
483                                                      index - 1);
484           gpointer ddata = node->data;
485           GDestroyNotify ddestroy = node->destroy;
486
487           node->data = NULL;
488           node->destroy = NULL;
489
490           if (ddestroy) 
491             {
492               G_UNLOCK (g_thread);
493               ddestroy (ddata);
494               G_LOCK (g_thread);
495               }
496         }
497     }
498   g_thread_free_indeces = g_slist_prepend (g_thread_free_indeces, 
499                                            GUINT_TO_POINTER (index));
500   G_UNLOCK (g_thread);
501 }
502
503 static void
504 g_thread_cleanup (gpointer data)
505 {
506   if (data)
507     {
508       GRealThread* thread = data;
509       if (thread->private_data)
510         {
511           GArray* array = thread->private_data;
512           guint i;
513           
514           for (i = 0; i < array->len; i++ )
515             {
516               GStaticPrivateNode *node = 
517                 &g_array_index (array, GStaticPrivateNode, i);
518               if (node->destroy)
519                 node->destroy (node->data);
520             }
521           g_array_free (array, TRUE);
522         }
523
524       /* We only free the thread structure, if it isn't joinable. If
525          it is, the structure is freed in g_thread_join */
526       if (!thread->thread.joinable)
527         {
528           G_LOCK (g_thread);
529           g_thread_all_threads = g_slist_remove (g_thread_all_threads, data);
530           G_UNLOCK (g_thread);
531           
532           /* Just to make sure, this isn't used any more */
533           g_system_thread_assign (thread->system_thread, zero_thread);
534           g_free (thread);
535         }
536     }
537 }
538
539 static void
540 g_thread_fail (void)
541 {
542   g_error ("The thread system is not yet initialized.");
543 }
544
545 static gpointer
546 g_thread_create_proxy (gpointer data)
547 {
548   GRealThread* thread = data;
549
550   g_assert (data);
551
552   /* This has to happen before G_LOCK, as that might call g_thread_self */
553   g_private_set (g_thread_specific_private, data);
554
555   /* the lock makes sure, that thread->system_thread is written,
556      before thread->thread.func is called. See g_thread_create. */
557   G_LOCK (g_thread);
558   G_UNLOCK (g_thread);
559  
560   thread->retval = thread->thread.func (thread->thread.data);
561
562   return NULL;
563 }
564
565 GThread* 
566 g_thread_create_full (GThreadFunc                func,
567                       gpointer           data,
568                       gulong             stack_size,
569                       gboolean           joinable,
570                       gboolean           bound,
571                       GThreadPriority    priority,
572                       GError                **error)
573 {
574   GRealThread* result;
575   GError *local_error = NULL;
576   g_return_val_if_fail (func, NULL);
577   g_return_val_if_fail (priority >= G_THREAD_PRIORITY_LOW, NULL);
578   g_return_val_if_fail (priority <= G_THREAD_PRIORITY_URGENT, NULL);
579   
580   result = g_new (GRealThread, 1);
581
582   result->thread.joinable = joinable;
583   result->thread.priority = priority;
584   result->thread.func = func;
585   result->thread.data = data;
586   result->private_data = NULL; 
587   G_LOCK (g_thread);
588   G_THREAD_UF (thread_create, (g_thread_create_proxy, result, 
589                                stack_size, joinable, bound, priority,
590                                &result->system_thread, &local_error));
591   g_thread_all_threads = g_slist_prepend (g_thread_all_threads, result);
592   G_UNLOCK (g_thread);
593
594   if (local_error)
595     {
596       g_propagate_error (error, local_error);
597       g_free (result);
598       return NULL;
599     }
600
601   return (GThread*) result;
602 }
603
604 void
605 g_thread_exit (gpointer retval)
606 {
607   GRealThread* real = (GRealThread*) g_thread_self ();
608   real->retval = retval;
609   G_THREAD_CF (thread_exit, (void)0, ());
610 }
611
612 gpointer
613 g_thread_join (GThread* thread)
614 {
615   GRealThread* real = (GRealThread*) thread;
616   gpointer retval;
617
618   g_return_val_if_fail (thread, NULL);
619   g_return_val_if_fail (thread->joinable, NULL);
620   g_return_val_if_fail (!g_system_thread_equal (real->system_thread, 
621                                                 zero_thread), NULL);
622
623   G_THREAD_UF (thread_join, (&real->system_thread));
624
625   retval = real->retval;
626
627   G_LOCK (g_thread);
628   g_thread_all_threads = g_slist_remove (g_thread_all_threads, thread);
629   G_UNLOCK (g_thread);
630
631   /* Just to make sure, this isn't used any more */
632   thread->joinable = 0;
633   g_system_thread_assign (real->system_thread, zero_thread);
634
635   /* the thread structure for non-joinable threads is freed upon
636      thread end. We free the memory here. This will leave a loose end,
637      if a joinable thread is not joined. */
638
639   g_free (thread);
640
641   return retval;
642 }
643
644 void
645 g_thread_set_priority (GThread* thread, 
646                        GThreadPriority priority)
647 {
648   GRealThread* real = (GRealThread*) thread;
649
650   g_return_if_fail (thread);
651   g_return_if_fail (!g_system_thread_equal (real->system_thread, zero_thread));
652   g_return_if_fail (priority >= G_THREAD_PRIORITY_LOW);
653   g_return_if_fail (priority <= G_THREAD_PRIORITY_URGENT);
654
655   thread->priority = priority;
656
657   G_THREAD_CF (thread_set_priority, (void)0, 
658                (&real->system_thread, priority));
659 }
660
661 GThread*
662 g_thread_self (void)
663 {
664   GRealThread* thread = g_private_get (g_thread_specific_private);
665
666   if (!thread)
667     {  
668       /* If no thread data is available, provide and set one.  This
669          can happen for the main thread and for threads, that are not
670          created by GLib. */
671       thread = g_new (GRealThread, 1);
672       thread->thread.joinable = FALSE; /* This is a save guess */
673       thread->thread.priority = G_THREAD_PRIORITY_NORMAL; /* This is
674                                                              just a guess */
675       thread->thread.func = NULL;
676       thread->thread.data = NULL;
677       thread->private_data = NULL;
678
679       if (g_thread_supported ())
680         G_THREAD_UF (thread_self, (&thread->system_thread));
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->have_writer || 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->have_writer && !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->have_writer || lock->read_counter)
782     g_static_rw_lock_wait (&lock->write_cond, &lock->mutex);
783   lock->want_to_write--;
784   lock->have_writer = 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->have_writer && !lock->read_counter)
800     {
801       lock->have_writer = 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->have_writer = 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 }