gthread-posix.c revision 77ccad4d2fe1dde7927a194fc53fa520cb20d059
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 Library 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 * Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library 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 * MT safe
25 */
26
27#include <pthread.h>
28#include <errno.h>
29#include <stdlib.h>
30#include <sys/time.h>
31
32#define posix_print_error( name, num )                          \
33  g_error( "file %s: line %d (%s): error %s during %s",         \
34           __FILE__, __LINE__, G_GNUC_PRETTY_FUNCTION,          \
35           g_strerror((num)), #name )
36
37#define posix_check_for_error( what ) G_STMT_START{             \
38  int error = (what);                                           \
39  if( error ) { posix_print_error( what, error ); }             \
40  }G_STMT_END
41
42static GMutex *
43g_mutex_new_posix_impl (void)
44{
45  GMutex *result = (GMutex *) g_new (pthread_mutex_t, 1);
46  posix_check_for_error (pthread_mutex_init ((pthread_mutex_t *) result, NULL));
47  return result;
48}
49
50static void
51g_mutex_free_posix_impl (GMutex * mutex)
52{
53  posix_check_for_error (pthread_mutex_destroy ((pthread_mutex_t *) mutex));
54  g_free (mutex);
55}
56
57/* NOTE: the functions g_mutex_lock and g_mutex_unlock may not use
58   functions from gmem.c and gmessages.c; */
59
60/* pthread_mutex_lock, pthread_mutex_unlock can be taken directly, as
61   signature and semantic are right, but without error check then!!!!,
62   we might want to change this therefore. */
63
64static gboolean
65g_mutex_trylock_posix_impl (GMutex * mutex)
66{
67  int result;
68
69  result = pthread_mutex_trylock ((pthread_mutex_t *) mutex);
70  if (result != EBUSY)
71    return FALSE;
72
73  posix_check_for_error (result);
74  return TRUE;
75}
76
77static GCond *
78g_cond_new_posix_impl (void)
79{
80  GCond *result = (GCond *) g_new (pthread_cond_t, 1);
81  posix_check_for_error (pthread_cond_init ((pthread_cond_t *) result, NULL));
82  return result;
83}
84
85/* pthread_cond_signal, pthread_cond_broadcast and pthread_cond_wait
86   can be taken directly, as signature and semantic are right, but
87   without error check then!!!!, we might want to change this
88   therfore. */
89
90#define G_MICROSEC 1000000
91#define G_NANOSEC 1000000000
92
93static gboolean
94g_cond_timed_wait_posix_impl (GCond * cond,
95			      GMutex * entered_mutex,
96			      GTimeVal * abs_time)
97{
98  int result;
99  struct timespec end_time;
100  gboolean timed_out;
101
102  g_return_val_if_fail (cond != NULL, FALSE);
103  g_return_val_if_fail (entered_mutex != NULL, FALSE);
104
105  if (!abs_time)
106    {
107      g_cond_wait (cond, entered_mutex);
108      return TRUE;
109    }
110
111  end_time.tv_sec = abs_time->tv_sec;
112  end_time.tv_nsec = abs_time->tv_usec * (G_NANOSEC / G_MICROSEC);
113  g_assert (end_time.tv_nsec < G_NANOSEC);
114  result = pthread_cond_timedwait ((pthread_cond_t *) cond,
115				   (pthread_mutex_t *) entered_mutex,
116				   &end_time);
117  timed_out = (result == ETIMEDOUT);
118  if (!timed_out)
119    posix_check_for_error (result);
120  return !timed_out;
121}
122
123static void
124g_cond_free_posix_impl (GCond * cond)
125{
126  posix_check_for_error (pthread_cond_destroy ((pthread_cond_t *) cond));
127  g_free (cond);
128}
129
130static GPrivate *
131g_private_new_posix_impl (GDestroyNotify destructor)
132{
133  GPrivate *result = (GPrivate *) g_new (pthread_key_t, 1);
134  posix_check_for_error (pthread_key_create ((pthread_key_t *) result,
135					     destructor));
136  return result;
137}
138
139/* NOTE: the functions g_private_get and g_private_set may not use
140   functions from gmem.c and gmessages.c */
141
142static void
143g_private_set_posix_impl (GPrivate * private_key, gpointer value)
144{
145  if (!private_key)
146    return;
147
148  pthread_setspecific (*(pthread_key_t *) private_key, value);
149}
150
151static gpointer
152g_private_get_posix_impl (GPrivate * private_key)
153{
154  if (!private_key)
155    return NULL;
156
157  return pthread_getspecific (*(pthread_key_t *) private_key);
158}
159
160static GThreadFunctions g_thread_functions_for_glib_use_default =
161{
162  g_mutex_new_posix_impl,
163  (void (*)(GMutex *)) pthread_mutex_lock,
164  g_mutex_trylock_posix_impl,
165  (void (*)(GMutex *)) pthread_mutex_unlock,
166  g_mutex_free_posix_impl,
167  g_cond_new_posix_impl,
168  (void (*)(GCond *)) pthread_cond_signal,
169  (void (*)(GCond *)) pthread_cond_broadcast,
170  (void (*)(GCond *, GMutex *)) pthread_cond_wait,
171  g_cond_timed_wait_posix_impl,
172  g_cond_free_posix_impl,
173  g_private_new_posix_impl,
174  g_private_get_posix_impl,
175  g_private_set_posix_impl
176};
177