source: trunk/third/glib2/glib/gthread.c @ 20721

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