check for sysconf (_SC_THREAD_STACK_MIN), which returns the minimal stack
[platform/upstream/glib.git] / gthread / 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 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  * Modified by the GLib Team and others 1997-1999.  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 /* 
31  * MT safe
32  */
33
34 #include <pthread.h>
35 #include <errno.h>
36 #include <stdlib.h>
37 #ifdef HAVE_SYS_TIME_H
38 #include <sys/time.h>
39 #endif
40 #ifdef HAVE_UNISTD_H
41 #include <unistd.h>
42 #endif
43
44 #define posix_print_error( name, num )                          \
45   g_error( "file %s: line %d (%s): error %s during %s",         \
46            __FILE__, __LINE__, G_GNUC_PRETTY_FUNCTION,          \
47            g_strerror((num)), #name )
48
49 #if defined(G_THREADS_IMPL_POSIX)
50 # define posix_check_for_error( what ) G_STMT_START{             \
51     int error = (what);                                           \
52     if( error ) { posix_print_error( what, error ); }             \
53     }G_STMT_END
54 # define mutexattr_default NULL
55 # define condattr_default NULL
56 #elif defined(G_THREADS_IMPL_DCE)
57 # define posix_check_for_error( what ) G_STMT_START{             \
58     if( (what) == -1 ) { posix_print_error( what, errno ); }       \
59     }G_STMT_END
60 # define pthread_key_create(a, b) pthread_keycreate (a, b)
61 # define pthread_attr_init(a) pthread_attr_create (a)
62 # define pthread_attr_destroy(a) pthread_attr_delete (a)
63 # define pthread_create(a, b, c, d) pthread_create(a, *b, c, d) 
64 # define mutexattr_default (pthread_mutexattr_default)
65 # define condattr_default (pthread_condattr_default)
66 #else /* neither G_THREADS_IMPL_POSIX nor G_THREADS_IMPL_DCE are defined */
67 # error This should not happen. Contact the GLib team.
68 #endif
69
70 gulong g_thread_min_stack_size = 0;
71
72 #define HAVE_G_THREAD_IMPL_INIT
73 static void 
74 g_thread_impl_init()
75 {
76   g_thread_min_priority = POSIX_MIN_PRIORITY;
77   g_thread_max_priority = POSIX_MAX_PRIORITY;
78 #ifdef _SC_THREAD_STACK_MIN
79   g_thread_min_stack_size = MAX (sysconf (_SC_THREAD_STACK_MIN), 0);
80 #endif /* _SC_THREAD_STACK_MIN */
81 }
82
83 static GMutex *
84 g_mutex_new_posix_impl (void)
85 {
86   GMutex *result = (GMutex *) g_new (pthread_mutex_t, 1);
87   posix_check_for_error (pthread_mutex_init ((pthread_mutex_t *) result, 
88                                              mutexattr_default));
89   return result;
90 }
91
92 static void
93 g_mutex_free_posix_impl (GMutex * mutex)
94 {
95   posix_check_for_error (pthread_mutex_destroy ((pthread_mutex_t *) mutex));
96   g_free (mutex);
97 }
98
99 /* NOTE: the functions g_mutex_lock and g_mutex_unlock may not use
100    functions from gmem.c and gmessages.c; */
101
102 /* pthread_mutex_lock, pthread_mutex_unlock can be taken directly, as
103    signature and semantic are right, but without error check then!!!!,
104    we might want to change this therefore. */
105
106 static gboolean
107 g_mutex_trylock_posix_impl (GMutex * mutex)
108 {
109   int result;
110
111   result = pthread_mutex_trylock ((pthread_mutex_t *) mutex);
112
113 #ifdef G_THREADS_IMPL_POSIX
114   if (result == EBUSY)
115     return FALSE;
116 #else /* G_THREADS_IMPL_DCE */
117   if (result == 0)
118     return FALSE;
119 #endif
120
121   posix_check_for_error (result);
122   return TRUE;
123 }
124
125 static GCond *
126 g_cond_new_posix_impl (void)
127 {
128   GCond *result = (GCond *) g_new (pthread_cond_t, 1);
129   posix_check_for_error (pthread_cond_init ((pthread_cond_t *) result, 
130                                             condattr_default));
131   return result;
132 }
133
134 /* pthread_cond_signal, pthread_cond_broadcast and pthread_cond_wait
135    can be taken directly, as signature and semantic are right, but
136    without error check then!!!!, we might want to change this
137    therfore. */
138
139 #define G_MICROSEC 1000000
140 #define G_NANOSEC 1000000000
141
142 static gboolean
143 g_cond_timed_wait_posix_impl (GCond * cond,
144                               GMutex * entered_mutex,
145                               GTimeVal * abs_time)
146 {
147   int result;
148   struct timespec end_time;
149   gboolean timed_out;
150
151   g_return_val_if_fail (cond != NULL, FALSE);
152   g_return_val_if_fail (entered_mutex != NULL, FALSE);
153
154   if (!abs_time)
155     {
156       g_cond_wait (cond, entered_mutex);
157       return TRUE;
158     }
159
160   end_time.tv_sec = abs_time->tv_sec;
161   end_time.tv_nsec = abs_time->tv_usec * (G_NANOSEC / G_MICROSEC);
162   g_assert (end_time.tv_nsec < G_NANOSEC);
163   result = pthread_cond_timedwait ((pthread_cond_t *) cond,
164                                    (pthread_mutex_t *) entered_mutex,
165                                    &end_time);
166
167 #ifdef G_THREADS_IMPL_POSIX
168   timed_out = (result == ETIMEDOUT);
169 #else /* G_THREADS_IMPL_DCE */
170   timed_out = (result == -1) && (errno = EAGAIN);
171 #endif
172
173   if (!timed_out)
174     posix_check_for_error (result);
175   return !timed_out;
176 }
177
178 static void
179 g_cond_free_posix_impl (GCond * cond)
180 {
181   posix_check_for_error (pthread_cond_destroy ((pthread_cond_t *) cond));
182   g_free (cond);
183 }
184
185 static GPrivate *
186 g_private_new_posix_impl (GDestroyNotify destructor)
187 {
188   GPrivate *result = (GPrivate *) g_new (pthread_key_t, 1);
189   posix_check_for_error (pthread_key_create ((pthread_key_t *) result,
190                                              destructor));
191   return result;
192 }
193
194 /* NOTE: the functions g_private_get and g_private_set may not use
195    functions from gmem.c and gmessages.c */
196
197 static void
198 g_private_set_posix_impl (GPrivate * private_key, gpointer value)
199 {
200   if (!private_key)
201     return;
202   pthread_setspecific (*(pthread_key_t *) private_key, value);
203 }
204
205 static gpointer
206 g_private_get_posix_impl (GPrivate * private_key)
207 {
208   if (!private_key)
209     return NULL;
210 #ifdef G_THREADS_IMPL_POSIX
211   return pthread_getspecific (*(pthread_key_t *) private_key);
212 #else /* G_THREADS_IMPL_DCE */
213   {
214     void* data;
215     posix_check_for_error (pthread_getspecific (*(pthread_key_t *) 
216                                                 private_key, &data));
217     return data;
218   }
219 #endif
220 }
221
222 static void
223 g_thread_create_posix_impl (GThreadFunc thread_func, 
224                             gpointer arg, 
225                             gulong stack_size,
226                             gboolean joinable,
227                             gboolean bound,
228                             GThreadPriority priority,
229                             gpointer thread)
230 {
231   pthread_attr_t attr;
232
233   g_return_if_fail (thread_func);
234
235   posix_check_for_error (pthread_attr_init (&attr));
236   
237 #ifdef HAVE_PTHREAD_ATTR_SETSTACKSIZE
238   if (stack_size)
239     {
240       stack_size = MAX (g_thread_min_stack_size, stack_size);
241       posix_check_for_error (pthread_attr_setstacksize (&attr, stack_size));
242     }
243 #endif /* HAVE_PTHREAD_ATTR_SETSTACKSIZE */
244
245 #ifdef PTHREAD_SCOPE_SYSTEM
246   if (bound)
247      posix_check_for_error (pthread_attr_setscope (&attr, 
248                                                    PTHREAD_SCOPE_SYSTEM));
249 #endif /* PTHREAD_SCOPE_SYSTEM */
250
251 #ifdef G_THREADS_IMPL_POSIX
252   posix_check_for_error (pthread_attr_setdetachstate (&attr,
253           joinable ? PTHREAD_CREATE_JOINABLE : PTHREAD_CREATE_DETACHED));
254 #endif /* G_THREADS_IMPL_POSIX */
255   
256 #ifdef G_THREADS_IMPL_POSIX
257   {
258     struct sched_param sched;
259     posix_check_for_error (pthread_attr_getschedparam (&attr, &sched));
260     sched.sched_priority = g_thread_map_priority (priority);
261     posix_check_for_error (pthread_attr_setschedparam (&attr, &sched));
262   }
263 #else /* G_THREADS_IMPL_DCE */
264   posix_check_for_error 
265     (pthread_attr_setprio (&attr, g_thread_map_priority (priority)));
266 #endif /* G_THREADS_IMPL_DCE */
267
268   posix_check_for_error (pthread_create (thread, &attr, 
269                                          (void* (*)(void*))thread_func,
270                                          arg));
271   
272   posix_check_for_error (pthread_attr_destroy (&attr));
273
274 #ifdef G_THREADS_IMPL_DCE
275   if (!joinable)
276     posix_check_for_error (pthread_detach (thread));
277 #endif /* G_THREADS_IMPL_DCE */
278 }
279
280 static void 
281 g_thread_yield_posix_impl (void)
282 {
283   POSIX_YIELD_FUNC;
284 }
285
286 static void
287 g_thread_join_posix_impl (gpointer thread)
288 {     
289   gpointer ignore;
290   posix_check_for_error (pthread_join (*(pthread_t*)thread, 
291                                        &ignore));
292 }
293
294 static void 
295 g_thread_exit_posix_impl (void) 
296 {
297   pthread_exit (NULL);
298 }
299
300 static void
301 g_thread_set_priority_posix_impl (gpointer thread, GThreadPriority priority)
302 {
303 #ifdef G_THREADS_IMPL_POSIX
304   struct sched_param sched;
305   int policy;
306   posix_check_for_error (pthread_getschedparam (*(pthread_t*)thread, 
307                                                 &policy, &sched));
308   sched.sched_priority = g_thread_map_priority (priority);
309   posix_check_for_error (pthread_setschedparam (*(pthread_t*)thread, 
310                                                 policy, &sched));
311 #else /* G_THREADS_IMPL_DCE */
312   posix_check_for_error (pthread_setprio (*(pthread_t*)thread, 
313                                           g_thread_map_priority (priority)));
314 #endif
315 }
316
317 static void
318 g_thread_self_posix_impl (gpointer thread)
319 {
320   *(pthread_t*)thread = pthread_self();
321 }
322
323 static GThreadFunctions g_thread_functions_for_glib_use_default =
324 {
325   g_mutex_new_posix_impl,
326   (void (*)(GMutex *)) pthread_mutex_lock,
327   g_mutex_trylock_posix_impl,
328   (void (*)(GMutex *)) pthread_mutex_unlock,
329   g_mutex_free_posix_impl,
330   g_cond_new_posix_impl,
331   (void (*)(GCond *)) pthread_cond_signal,
332   (void (*)(GCond *)) pthread_cond_broadcast,
333   (void (*)(GCond *, GMutex *)) pthread_cond_wait,
334   g_cond_timed_wait_posix_impl,
335   g_cond_free_posix_impl,
336   g_private_new_posix_impl,
337   g_private_get_posix_impl,
338   g_private_set_posix_impl,
339   g_thread_create_posix_impl,
340   g_thread_yield_posix_impl,
341   g_thread_join_posix_impl,
342   g_thread_exit_posix_impl,
343   g_thread_set_priority_posix_impl,
344   g_thread_self_posix_impl
345 };