Move docs around
[platform/upstream/glib.git] / glib / gthread-posix.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: posix thread system implementation
5  * Copyright 1998 Sebastian Wilhelmi; University of Karlsruhe
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 /*
24  * Modified by the GLib Team and others 1997-2000.  See the AUTHORS
25  * file for a list of people on the GLib Team.  See the ChangeLog
26  * files for a list of changes.  These files are distributed with
27  * GLib at ftp://ftp.gtk.org/pub/gtk/.
28  */
29
30 /* The GMutex, GCond and GPrivate implementations in this file are some
31  * of the lowest-level code in GLib.  All other parts of GLib (messages,
32  * memory, slices, etc) assume that they can freely use these facilities
33  * without risking recursion.
34  *
35  * As such, these functions are NOT permitted to call any other part of
36  * GLib.
37  *
38  * The thread manipulation functions (create, exit, join, etc.) have
39  * more freedom -- they can do as they please.
40  */
41
42 #include "config.h"
43
44 #include "gthread.h"
45 #include "gthreadprivate.h"
46
47 #include <pthread.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include <errno.h>
51 #include <stdio.h>
52
53 static void
54 g_thread_abort (gint         status,
55                 const gchar *function)
56 {
57   fprintf (stderr, "GLib (gthread-posix.c): Unexpected error from C library during '%s': %s.  Aborting.\n",
58            strerror (status), function);
59   abort ();
60 }
61
62 /* {{{1 GMutex */
63
64 /**
65  * g_mutex_init:
66  * @mutex: an uninitialized #GMutex
67  *
68  * Initializes a #GMutex so that it can be used.
69  *
70  * This function is useful to initialize a mutex that has been
71  * allocated on the stack, or as part of a larger structure.
72  * It is not necessary to initialize a mutex that has been
73  * created with g_mutex_new(). Also see #G_MUTEX_INITIALIZER
74  * for an alternative way to initialize statically allocated mutexes.
75  *
76  * |[
77  *   typedef struct {
78  *     GMutex m;
79  *     /&ast; ... &ast;/
80  *   } Blob;
81  *
82  * Blob *b;
83  *
84  * b = g_new (Blob, 1);
85  * g_mutex_init (&b->m);
86  * /&ast; ... &ast;/
87  * ]|
88  *
89  * To undo the effect of g_mutex_init() when a mutex is no longer
90  * needed, use g_mutex_clear().
91  *
92  * Since: 2.32
93  */
94 void
95 g_mutex_init (GMutex *mutex)
96 {
97   gint status;
98
99   if G_UNLIKELY ((status = pthread_mutex_init (&mutex->impl, NULL)) != 0)
100     g_thread_abort (status, "pthread_mutex_init");
101 }
102
103 /**
104  * g_mutex_clear:
105  * @mutex: an initialized #GMutex
106  *
107  * Frees the resources allocated to a mutex with g_mutex_init().
108  *
109  * #GMutexes that have have been created with g_mutex_new() should
110  * be freed with g_mutex_free() instead.
111  *
112  * Sine: 2.32
113  */
114 void
115 g_mutex_clear (GMutex *mutex)
116 {
117   gint status;
118
119   if G_UNLIKELY ((status = pthread_mutex_destroy (&mutex->impl)) != 0)
120     g_thread_abort (status, "pthread_mutex_destroy");
121 }
122
123 /**
124  * g_mutex_lock:
125  * @mutex: a #GMutex
126  *
127  * Locks @mutex. If @mutex is already locked by another thread, the
128  * current thread will block until @mutex is unlocked by the other
129  * thread.
130  *
131  * This function can be used even if g_thread_init() has not yet been
132  * called, and, in that case, will do nothing.
133  *
134  * <note>#GMutex is neither guaranteed to be recursive nor to be
135  * non-recursive, i.e. a thread could deadlock while calling
136  * g_mutex_lock(), if it already has locked @mutex. Use
137  * #GStaticRecMutex, if you need recursive mutexes.</note>
138  */
139 void
140 g_mutex_lock (GMutex *mutex)
141 {
142   gint status;
143
144   if G_UNLIKELY ((status = pthread_mutex_lock (&mutex->impl)) != 0)
145     g_thread_abort (status, "pthread_mutex_lock");
146 }
147
148 /**
149  * g_mutex_unlock:
150  * @mutex: a #GMutex
151  *
152  * Unlocks @mutex. If another thread is blocked in a g_mutex_lock()
153  * call for @mutex, it will be woken and can lock @mutex itself.
154  *
155  * This function can be used even if g_thread_init() has not yet been
156  * called, and, in that case, will do nothing.
157  */
158 void
159 g_mutex_unlock (GMutex *mutex)
160 {
161   gint status;
162
163   if G_UNLIKELY ((status = pthread_mutex_unlock (&mutex->impl)) != 0)
164     g_thread_abort (status, "pthread_mutex_lock");
165 }
166
167 /**
168  * g_mutex_trylock:
169  * @mutex: a #GMutex
170  *
171  * Tries to lock @mutex. If @mutex is already locked by another thread,
172  * it immediately returns %FALSE. Otherwise it locks @mutex and returns
173  * %TRUE.
174  *
175  * This function can be used even if g_thread_init() has not yet been
176  * called, and, in that case, will immediately return %TRUE.
177  *
178  * <note>#GMutex is neither guaranteed to be recursive nor to be
179  * non-recursive, i.e. the return value of g_mutex_trylock() could be
180  * both %FALSE or %TRUE, if the current thread already has locked
181  * @mutex. Use #GStaticRecMutex, if you need recursive
182  * mutexes.</note>
183
184  * Returns: %TRUE, if @mutex could be locked
185  */
186 gboolean
187 g_mutex_trylock (GMutex *mutex)
188 {
189   gint status;
190
191   if G_LIKELY ((status = pthread_mutex_trylock (&mutex->impl)) == 0)
192     return TRUE;
193
194   if G_UNLIKELY (status != EBUSY)
195     g_thread_abort (status, "pthread_mutex_trylock");
196
197   return FALSE;
198 }
199
200 /* {{{1 GCond */
201
202 /**
203  * g_cond_init:
204  * @cond: an uninitialized #GCond
205  *
206  * Initialized a #GCond so that it can be used.
207  *
208  * This function is useful to initialize a #GCond that has been
209  * allocated on the stack, or as part of a larger structure.
210  * It is not necessary to initialize a #GCond that has been
211  * created with g_cond_new(). Also see #G_COND_INITIALIZER
212  * for an alternative way to initialize statically allocated
213  * #GConds.
214  *
215  * Since: 2.32
216  */
217 void
218 g_cond_init (GCond *cond)
219 {
220   gint status;
221
222   if G_UNLIKELY ((status = pthread_cond_init (&cond->impl, NULL)) != 0)
223     g_thread_abort (status, "pthread_cond_init");
224 }
225
226 /**
227  * g_cond_clear:
228  * @cond: an initialized #GCond
229  *
230  * Frees the resources allocated ot a #GCond with g_cond_init().
231  *
232  * #GConds that have been created with g_cond_new() should
233  * be freed with g_cond_free() instead.
234  *
235  * Since: 2.32
236  */
237 void
238 g_cond_clear (GCond *cond)
239 {
240   gint status;
241
242   if G_UNLIKELY ((status = pthread_cond_destroy (&cond->impl)) != 0)
243     g_thread_abort (status, "pthread_cond_destroy");
244 }
245
246 /**
247  * g_cond_wait:
248  * @cond: a #GCond
249  * @mutex: a #GMutex that is currently locked
250  *
251  * Waits until this thread is woken up on @cond.
252  * The @mutex is unlocked before falling asleep
253  * and locked again before resuming.
254  *
255  * This function can be used even if g_thread_init() has not yet been
256  * called, and, in that case, will immediately return.
257  */
258 void
259 g_cond_wait (GCond  *cond,
260              GMutex *mutex)
261 {
262   gint status;
263
264   if G_UNLIKELY ((status = pthread_cond_wait (&cond->impl, &mutex->impl)) != 0)
265     g_thread_abort (status, "pthread_cond_wait");
266 }
267
268 /**
269  * g_cond_signal:
270  * @cond: a #GCond
271  *
272  * If threads are waiting for @cond, exactly one of them is woken up.
273  * It is good practice to hold the same lock as the waiting thread
274  * while calling this function, though not required.
275  *
276  * This function can be used even if g_thread_init() has not yet been
277  * called, and, in that case, will do nothing.
278  */
279 void
280 g_cond_signal (GCond *cond)
281 {
282   gint status;
283
284   if G_UNLIKELY ((status = pthread_cond_signal (&cond->impl)) != 0)
285     g_thread_abort (status, "pthread_cond_signal");
286 }
287
288 /**
289  * g_cond_broadcast:
290  * @cond: a #GCond
291  *
292  * If threads are waiting for @cond, all of them are woken up.
293  * It is good practice to lock the same mutex as the waiting threads
294  * while calling this function, though not required.
295  *
296  * This function can be used even if g_thread_init() has not yet been
297  * called, and, in that case, will do nothing.
298  */
299 void
300 g_cond_broadcast (GCond *cond)
301 {
302   gint status;
303
304   if G_UNLIKELY ((status = pthread_cond_broadcast (&cond->impl)) != 0)
305     g_thread_abort (status, "pthread_cond_broadcast");
306 }
307
308 /**
309  * g_cond_timed_wait:
310  * @cond: a #GCond
311  * @mutex: a #GMutex that is currently locked
312  * @abs_time: a #GTimeVal, determining the final time
313  *
314  * Waits until this thread is woken up on @cond, but not longer than
315  * until the time specified by @abs_time. The @mutex is unlocked before
316  * falling asleep and locked again before resuming.
317  *
318  * If @abs_time is %NULL, g_cond_timed_wait() acts like g_cond_wait().
319  *
320  * This function can be used even if g_thread_init() has not yet been
321  * called, and, in that case, will immediately return %TRUE.
322  *
323  * To easily calculate @abs_time a combination of g_get_current_time()
324  * and g_time_val_add() can be used.
325  *
326  * Returns: %TRUE if @cond was signalled, or %FALSE on timeout
327  */
328 gboolean
329 g_cond_timed_wait (GCond    *cond,
330                    GMutex   *mutex,
331                    GTimeVal *abs_time)
332 {
333   struct timespec end_time;
334   gint status;
335
336   if (abs_time == NULL)
337     {
338       g_cond_wait (cond, mutex);
339       return TRUE;
340     }
341
342   end_time.tv_sec = abs_time->tv_sec;
343   end_time.tv_nsec = abs_time->tv_usec * 1000;
344
345   if ((status = pthread_cond_timedwait (&cond->impl, &mutex->impl, &end_time)) == 0)
346     return TRUE;
347
348   if G_UNLIKELY (status != ETIMEDOUT)
349     g_thread_abort (status, "pthread_cond_timedwait");
350
351   return FALSE;
352 }
353
354 /**
355  * g_cond_timedwait:
356  * @cond: a #GCond
357  * @mutex: a #GMutex that is currently locked
358  * @abs_time: the final time, in microseconds
359  *
360  * A variant of g_cond_timed_wait() that takes @abs_time
361  * as a #gint64 instead of a #GTimeVal.
362  * See g_cond_timed_wait() for details.
363  *
364  * Returns: %TRUE if @cond was signalled, or %FALSE on timeout
365  *
366  * Since: 2.32
367  */
368 gboolean
369 g_cond_timedwait (GCond  *cond,
370                   GMutex *mutex,
371                   gint64  abs_time)
372 {
373   struct timespec end_time;
374   gint status;
375
376   end_time.tv_sec = abs_time / 1000000;
377   end_time.tv_nsec = (abs_time % 1000000) * 1000;
378
379   if ((status = pthread_cond_timedwait (&cond->impl, &mutex->impl, &end_time)) == 0)
380     return TRUE;
381
382   if G_UNLIKELY (status != ETIMEDOUT)
383     g_thread_abort (status, "pthread_cond_timedwait");
384
385   return FALSE;
386 }
387
388 /* {{{1 GPrivate */
389
390 /**
391  * g_private_new:
392  * @destructor: a function to destroy the data keyed to
393  *     the #GPrivate when a thread ends
394  *
395  * Creates a new #GPrivate. If @destructor is non-%NULL, it is a
396  * pointer to a destructor function. Whenever a thread ends and the
397  * corresponding pointer keyed to this instance of #GPrivate is
398  * non-%NULL, the destructor is called with this pointer as the
399  * argument.
400  *
401  * <note><para>
402  * #GStaticPrivate is a better choice for most uses.
403  * </para></note>
404  *
405  * <note><para>@destructor is used quite differently from @notify in
406  * g_static_private_set().</para></note>
407  *
408  * <note><para>A #GPrivate cannot be freed. Reuse it instead, if you
409  * can, to avoid shortage, or use #GStaticPrivate.</para></note>
410  *
411  * <note><para>This function will abort if g_thread_init() has not been
412  * called yet.</para></note>
413  *
414  * Returns: a newly allocated #GPrivate
415  */
416 GPrivate *
417 g_private_new (GDestroyNotify notify)
418 {
419   GPrivate *key;
420
421   key = malloc (sizeof (GPrivate));
422   if G_UNLIKELY (key == NULL)
423     g_thread_abort (errno, "malloc");
424   g_private_init (key, notify);
425
426   return key;
427 }
428
429 void
430 g_private_init (GPrivate       *key,
431                 GDestroyNotify  notify)
432 {
433   pthread_key_create (&key->key, notify);
434   key->ready = TRUE;
435 }
436
437 /**
438  * g_private_get:
439  * @private_key: a #GPrivate
440  *
441  * Returns the pointer keyed to @private_key for the current thread. If
442  * g_private_set() hasn't been called for the current @private_key and
443  * thread yet, this pointer will be %NULL.
444  *
445  * This function can be used even if g_thread_init() has not yet been
446  * called, and, in that case, will return the value of @private_key
447  * casted to #gpointer. Note however, that private data set
448  * <emphasis>before</emphasis> g_thread_init() will
449  * <emphasis>not</emphasis> be retained <emphasis>after</emphasis> the
450  * call. Instead, %NULL will be returned in all threads directly after
451  * g_thread_init(), regardless of any g_private_set() calls issued
452  * before threading system initialization.
453  *
454  * Returns: the corresponding pointer
455  */
456 gpointer
457 g_private_get (GPrivate *key)
458 {
459   if (!key->ready)
460     return key->single_value;
461
462   /* quote POSIX: No errors are returned from pthread_getspecific(). */
463   return pthread_getspecific (key->key);
464 }
465
466 /**
467  * g_private_set:
468  * @private_key: a #GPrivate
469  * @data: the new pointer
470  *
471  * Sets the pointer keyed to @private_key for the current thread.
472  *
473  * This function can be used even if g_thread_init() has not yet been
474  * called, and, in that case, will set @private_key to @data casted to
475  * #GPrivate*. See g_private_get() for resulting caveats.
476  */
477 void
478 g_private_set (GPrivate *key,
479                gpointer  value)
480 {
481   gint status;
482
483   if (!key->ready)
484     {
485       key->single_value = value;
486       return;
487     }
488
489   if G_UNLIKELY ((status = pthread_setspecific (key->key, value)) != 0)
490     g_thread_abort (status, "pthread_setspecific");
491 }
492
493 /* {{{1 GThread */
494
495 #include "glib.h"
496 #include "gthreadprivate.h"
497
498 #include <pthread.h>
499 #include <errno.h>
500 #include <stdlib.h>
501 #ifdef HAVE_SYS_TIME_H
502 # include <sys/time.h>
503 #endif
504 #ifdef HAVE_UNISTD_H
505 # include <unistd.h>
506 #endif
507
508 #ifdef HAVE_SCHED_H
509 #include <sched.h>
510 #endif
511
512 #define posix_check_err(err, name) G_STMT_START{                        \
513   int error = (err);                                                    \
514   if (error)                                                            \
515     g_error ("file %s: line %d (%s): error '%s' during '%s'",           \
516            __FILE__, __LINE__, G_STRFUNC,                               \
517            g_strerror (error), name);                                   \
518   }G_STMT_END
519
520 #define posix_check_cmd(cmd) posix_check_err (cmd, #cmd)
521
522 #ifdef G_ENABLE_DEBUG
523 static gboolean posix_check_cmd_prio_warned = FALSE;
524 # define posix_check_cmd_prio(cmd) G_STMT_START{                        \
525     int err = (cmd);                                                    \
526     if (err == EPERM)                                                   \
527       {                                                                 \
528         if (!posix_check_cmd_prio_warned)                               \
529           {                                                             \
530             posix_check_cmd_prio_warned = TRUE;                         \
531             g_warning ("Priorities can only be changed "                \
532                         "(resp. increased) by root.");                  \
533           }                                                             \
534       }                                                                 \
535     else                                                                \
536       posix_check_err (err, #cmd);                                      \
537      }G_STMT_END
538 #else /* G_ENABLE_DEBUG */
539 # define posix_check_cmd_prio(cmd) G_STMT_START{                        \
540     int err = (cmd);                                                    \
541     if (err != EPERM)                                                   \
542       posix_check_err (err, #cmd);                                      \
543      }G_STMT_END
544 #endif /* G_ENABLE_DEBUG */
545
546 #if defined (POSIX_MIN_PRIORITY) && defined (POSIX_MAX_PRIORITY)
547 # define HAVE_PRIORITIES 1
548 static gint priority_normal_value;
549 # ifdef __FreeBSD__
550    /* FreeBSD threads use different priority values from the POSIX_
551     * defines so we just set them here. The corresponding macros
552     * PTHREAD_MIN_PRIORITY and PTHREAD_MAX_PRIORITY are implied to be
553     * exported by the docs, but they aren't.
554     */
555 #  define PRIORITY_LOW_VALUE      0
556 #  define PRIORITY_URGENT_VALUE   31
557 # else /* !__FreeBSD__ */
558 #  define PRIORITY_LOW_VALUE      POSIX_MIN_PRIORITY
559 #  define PRIORITY_URGENT_VALUE   POSIX_MAX_PRIORITY
560 # endif /* !__FreeBSD__ */
561 # define PRIORITY_NORMAL_VALUE    priority_normal_value
562
563 # define PRIORITY_HIGH_VALUE \
564     ((PRIORITY_NORMAL_VALUE + PRIORITY_URGENT_VALUE * 2) / 3)
565
566 static gint
567 g_thread_priority_map (GThreadPriority priority)
568 {
569   switch (priority)
570     {
571     case G_THREAD_PRIORITY_LOW:
572       return PRIORITY_LOW_VALUE;
573
574     case G_THREAD_PRIORITY_NORMAL:
575       return PRIORITY_NORMAL_VALUE;
576
577     case G_THREAD_PRIORITY_HIGH:
578       return PRIORITY_HIGH_VALUE;
579
580     case G_THREAD_PRIORITY_URGENT:
581       return PRIORITY_URGENT_VALUE;
582
583     default:
584       g_assert_not_reached ();
585     }
586 }
587
588 #endif /* POSIX_MIN_PRIORITY && POSIX_MAX_PRIORITY */
589
590 static gulong g_thread_min_stack_size = 0;
591
592 #define G_MUTEX_SIZE (sizeof (pthread_mutex_t))
593
594 void
595 _g_thread_impl_init(void)
596 {
597 #ifdef _SC_THREAD_STACK_MIN
598   g_thread_min_stack_size = MAX (sysconf (_SC_THREAD_STACK_MIN), 0);
599 #endif /* _SC_THREAD_STACK_MIN */
600 #ifdef HAVE_PRIORITIES
601   {
602     struct sched_param sched;
603     int policy;
604     posix_check_cmd (pthread_getschedparam (pthread_self(), &policy, &sched));
605     priority_normal_value = sched.sched_priority;
606   }
607 #endif /* HAVE_PRIORITIES */
608 }
609
610 static void
611 g_thread_create_posix_impl (GThreadFunc thread_func,
612                             gpointer arg,
613                             gulong stack_size,
614                             gboolean joinable,
615                             gboolean bound,
616                             GThreadPriority priority,
617                             gpointer thread,
618                             GError **error)
619 {
620   pthread_attr_t attr;
621   gint ret;
622
623   g_return_if_fail (thread_func);
624   g_return_if_fail (priority >= G_THREAD_PRIORITY_LOW);
625   g_return_if_fail (priority <= G_THREAD_PRIORITY_URGENT);
626
627   posix_check_cmd (pthread_attr_init (&attr));
628
629 #ifdef HAVE_PTHREAD_ATTR_SETSTACKSIZE
630   if (stack_size)
631     {
632       stack_size = MAX (g_thread_min_stack_size, stack_size);
633       /* No error check here, because some systems can't do it and
634        * we simply don't want threads to fail because of that. */
635       pthread_attr_setstacksize (&attr, stack_size);
636     }
637 #endif /* HAVE_PTHREAD_ATTR_SETSTACKSIZE */
638
639 #ifdef PTHREAD_SCOPE_SYSTEM
640   if (bound)
641     /* No error check here, because some systems can't do it and we
642      * simply don't want threads to fail because of that. */
643     pthread_attr_setscope (&attr, PTHREAD_SCOPE_SYSTEM);
644 #endif /* PTHREAD_SCOPE_SYSTEM */
645
646   posix_check_cmd (pthread_attr_setdetachstate (&attr,
647           joinable ? PTHREAD_CREATE_JOINABLE : PTHREAD_CREATE_DETACHED));
648
649 #ifdef HAVE_PRIORITIES
650   {
651     struct sched_param sched;
652     posix_check_cmd (pthread_attr_getschedparam (&attr, &sched));
653     sched.sched_priority = g_thread_priority_map (priority);
654     posix_check_cmd_prio (pthread_attr_setschedparam (&attr, &sched));
655   }
656 #endif /* HAVE_PRIORITIES */
657   ret = pthread_create (thread, &attr, (void* (*)(void*))thread_func, arg);
658
659   posix_check_cmd (pthread_attr_destroy (&attr));
660
661   if (ret == EAGAIN)
662     {
663       g_set_error (error, G_THREAD_ERROR, G_THREAD_ERROR_AGAIN, 
664                    "Error creating thread: %s", g_strerror (ret));
665       return;
666     }
667
668   posix_check_err (ret, "pthread_create");
669 }
670
671 static void
672 g_thread_yield_posix_impl (void)
673 {
674   sched_yield ();
675 }
676
677 static void
678 g_thread_join_posix_impl (gpointer thread)
679 {
680   gpointer ignore;
681   posix_check_cmd (pthread_join (*(pthread_t*)thread, &ignore));
682 }
683
684 static void
685 g_thread_exit_posix_impl (void)
686 {
687   pthread_exit (NULL);
688 }
689
690 static void
691 g_thread_set_priority_posix_impl (gpointer thread, GThreadPriority priority)
692 {
693   g_return_if_fail (priority >= G_THREAD_PRIORITY_LOW);
694   g_return_if_fail (priority <= G_THREAD_PRIORITY_URGENT);
695 #ifdef HAVE_PRIORITIES
696   {
697     struct sched_param sched;
698     int policy;
699     posix_check_cmd (pthread_getschedparam (*(pthread_t*)thread, &policy,
700                                             &sched));
701     sched.sched_priority = g_thread_priority_map (priority);
702     posix_check_cmd_prio (pthread_setschedparam (*(pthread_t*)thread, policy,
703                                                  &sched));
704   }
705 #endif /* HAVE_PRIORITIES */
706 }
707
708 static void
709 g_thread_self_posix_impl (gpointer thread)
710 {
711   *(pthread_t*)thread = pthread_self();
712 }
713
714 static gboolean
715 g_thread_equal_posix_impl (gpointer thread1, gpointer thread2)
716 {
717   return (pthread_equal (*(pthread_t*)thread1, *(pthread_t*)thread2) != 0);
718 }
719
720 /* {{{1 Epilogue */
721 GThreadFunctions g_thread_functions_for_glib_use =
722 {
723   g_mutex_new,
724   g_mutex_lock,
725   g_mutex_trylock,
726   g_mutex_unlock,
727   g_mutex_free,
728   g_cond_new,
729   g_cond_signal,
730   g_cond_broadcast,
731   g_cond_wait,
732   g_cond_timed_wait,
733   g_cond_free,
734   g_private_new,
735   g_private_get,
736   g_private_set,
737   g_thread_create_posix_impl,
738   g_thread_yield_posix_impl,
739   g_thread_join_posix_impl,
740   g_thread_exit_posix_impl,
741   g_thread_set_priority_posix_impl,
742   g_thread_self_posix_impl,
743   g_thread_equal_posix_impl
744 };
745
746 /* vim:set foldmethod=marker: */