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