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