Set the normal PID surrogate priority according to getpid() to avoid
[platform/upstream/glib.git] / gthread / gthread-impl.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: thread related functions
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 /* 
31  * MT safe
32  */
33
34 #ifdef HAVE_CONFIG_H
35 #include <config.h>
36 #endif
37
38 #include <glib.h>
39
40 #ifdef G_THREADS_ENABLED
41
42 static gboolean thread_system_already_initialized = FALSE;
43 static gint g_thread_priority_map [G_THREAD_PRIORITY_URGENT + 1];
44
45 #include G_THREAD_SOURCE
46
47 #ifndef PRIORITY_LOW_VALUE
48 # define PRIORITY_LOW_VALUE 0
49 #endif
50
51 #ifndef PRIORITY_URGENT_VALUE
52 # define PRIORITY_URGENT_VALUE 0
53 #endif
54
55 #ifndef PRIORITY_NORMAL_VALUE
56 # define PRIORITY_NORMAL_VALUE                                          \
57   ((PRIORITY_LOW_VALUE * 6 + PRIORITY_URGENT_VALUE * 4) / 10)
58 #endif /* PRIORITY_NORMAL_VALUE */
59
60 #ifndef PRIORITY_HIGH_VALUE
61 # define PRIORITY_HIGH_VALUE                                            \
62   ((PRIORITY_NORMAL_VALUE + PRIORITY_URGENT_VALUE * 2) / 3)
63 #endif /* PRIORITY_HIGH_VALUE */
64
65 void g_mutex_init (void);
66 void g_mem_init (void);
67 void g_messages_init (void);
68 void g_convert_init (void);
69
70 #define G_MUTEX_DEBUG_INFO(mutex) (*((gpointer*)(((char*)mutex)+G_MUTEX_SIZE)))
71
72 typedef struct _ErrorCheckInfo ErrorCheckInfo;
73 struct _ErrorCheckInfo
74 {
75   gchar *location;
76   GThread *owner;
77 };
78
79 static GMutex *
80 g_mutex_new_errorcheck_impl (void)
81 {
82   GMutex *retval = g_thread_functions_for_glib_use_default.mutex_new ();
83   retval = g_realloc (retval, G_MUTEX_SIZE + sizeof (gpointer));
84   G_MUTEX_DEBUG_INFO (retval) = NULL;
85   return retval;
86 }
87
88 static void
89 g_mutex_lock_errorcheck_impl (GMutex *mutex, 
90                               gulong magic,
91                               gchar *location)
92 {
93   ErrorCheckInfo *info;
94   GThread *self = g_thread_self ();
95
96   if (magic != G_MUTEX_DEBUG_MAGIC)
97     location = "unknown";
98
99   if (G_MUTEX_DEBUG_INFO (mutex) == NULL)
100     {
101       /* if the debug info is NULL, we have not yet locked that mutex,
102        * so we do it now */
103       g_thread_functions_for_glib_use_default.mutex_lock (mutex);
104       /* Now we have to check again, because another thread might have
105        * tried to lock the mutex at the same time we did. This
106        * technique is not 100% save on systems without decent cache
107        * coherence, but we have no choice */
108       if (G_MUTEX_DEBUG_INFO (mutex) == NULL)
109         {
110           info = G_MUTEX_DEBUG_INFO (mutex) = g_new0 (ErrorCheckInfo, 1);
111         }
112       g_thread_functions_for_glib_use_default.mutex_unlock (mutex);
113     }
114   
115   info = G_MUTEX_DEBUG_INFO (mutex);
116   if (info->owner == self)
117     g_error ("Trying to recursivly lock a mutex at '%s', "
118              "previously locked at '%s'", 
119              location, info->location);
120
121   g_thread_functions_for_glib_use_default.mutex_lock (mutex);
122
123   info->owner = self;
124   info->location = location;
125 }
126
127 static gboolean
128 g_mutex_trylock_errorcheck_impl (GMutex *mutex, 
129                                  gulong magic, 
130                                  gchar *location)
131 {
132   ErrorCheckInfo *info = G_MUTEX_DEBUG_INFO (mutex);
133   GThread *self = g_thread_self ();
134
135   if (magic != G_MUTEX_DEBUG_MAGIC)
136     location = "unknown";
137
138   if (!info)
139     {
140       /* This mutex has not yet been used, so simply lock and return TRUE */
141       g_mutex_lock_errorcheck_impl (mutex, magic, location);
142       return TRUE;
143     }
144
145   if (info->owner == self)
146     g_error ("Trying to recursivly lock a mutex at '%s', "
147              "previously locked at '%s'", 
148              location, info->location);
149   
150   if (!g_thread_functions_for_glib_use_default.mutex_trylock (mutex))
151     return FALSE;
152
153   info->owner = self;
154   info->location = location;
155
156   return TRUE;
157 }
158
159 static void
160 g_mutex_unlock_errorcheck_impl (GMutex *mutex, 
161                                 gulong magic, 
162                                 gchar *location)
163 {
164   ErrorCheckInfo *info = G_MUTEX_DEBUG_INFO (mutex);
165   GThread *self = g_thread_self ();
166
167   if (magic != G_MUTEX_DEBUG_MAGIC)
168     location = "unknown";
169
170   if (!info || info->owner == NULL)
171     g_error ("Trying to unlock an unlocked mutex at '%s'", location);
172
173   if (info->owner != self)
174     g_warning ("Trying to unlock a mutex at '%s', "
175                "previously locked by a different thread at '%s'",
176                location, info->location);
177
178   info->owner = NULL;
179   info->location = NULL;
180
181   g_thread_functions_for_glib_use_default.mutex_unlock (mutex);
182 }
183
184 static void
185 g_mutex_free_errorcheck_impl (GMutex *mutex, 
186                               gulong magic, 
187                               gchar *location)
188 {
189   ErrorCheckInfo *info = G_MUTEX_DEBUG_INFO (mutex);
190   
191   if (magic != G_MUTEX_DEBUG_MAGIC)
192     location = "unknown";
193
194   if (info && info->owner != NULL)
195     g_error ("Trying to free a locked mutex at '%s', "
196              "which was previously locked at '%s'", 
197              location, info->location);
198
199   g_free (G_MUTEX_DEBUG_INFO (mutex));
200   g_thread_functions_for_glib_use_default.mutex_free (mutex);  
201 }
202
203 static void     
204 g_cond_wait_errorcheck_impl (GCond *cond,
205                              GMutex *mutex, 
206                              gulong magic, 
207                              gchar *location)
208 {
209   
210   ErrorCheckInfo *info = G_MUTEX_DEBUG_INFO (mutex);
211   GThread *self = g_thread_self ();
212
213   if (magic != G_MUTEX_DEBUG_MAGIC)
214     location = "unknown";
215
216   if (!info || info->owner == NULL)
217     g_error ("Trying to use an unlocked mutex in g_cond_wait() at '%s'",
218              location);
219
220   if (info->owner != self)
221     g_error ("Trying to use a mutex locked by another thread in "
222              "g_cond_wait() at '%s'", location);
223
224   info->owner = NULL;
225   location = info->location;
226
227   g_thread_functions_for_glib_use_default.cond_wait (cond, mutex);
228
229   info->owner = self;
230   info->location = location;
231 }
232     
233
234 static gboolean 
235 g_cond_timed_wait_errorcheck_impl (GCond *cond,
236                                    GMutex *mutex,
237                                    GTimeVal *end_time, 
238                                    gulong magic, 
239                                    gchar *location)
240 {
241   ErrorCheckInfo *info = G_MUTEX_DEBUG_INFO (mutex);
242   GThread *self = g_thread_self ();
243   gboolean retval;
244
245   if (magic != G_MUTEX_DEBUG_MAGIC)
246     location = "unknown";
247
248   if (!info || info->owner == NULL)
249     g_error ("Trying to use an unlocked mutex in g_cond_timed_wait() at '%s'",
250              location);
251
252   if (info->owner != self)
253     g_error ("Trying to use a mutex locked by another thread in "
254              "g_cond_timed_wait() at '%s'", location);
255
256   info->owner = NULL;
257   location = info->location;
258   
259   retval = g_thread_functions_for_glib_use_default.cond_timed_wait (cond, 
260                                                                     mutex, 
261                                                                     end_time);
262
263   info->owner = self;
264   info->location = location;
265
266   return retval;
267 }
268
269
270 /* unshadow function declaration. See gthread.h */
271 #undef g_thread_init
272
273 void 
274 g_thread_init_with_errorcheck_mutexes (GThreadFunctions* init)
275 {
276   GThreadFunctions errorcheck_functions;
277   if (init)
278     g_error ("Errorcheck mutexes can only be used for native " 
279              "thread implementations. Sorry." );
280
281 #ifdef HAVE_G_THREAD_IMPL_INIT
282   /* This isn't called in g_thread_init, as it doesn't think to get
283    * the default implementation, so we have to call it on our own.
284    *
285    * We must call this before copying
286    * g_thread_functions_for_glib_use_default as the
287    * implementation-specific init function might modify the contents
288    * of g_thread_functions_for_glib_use_default based on operating
289    * system version, C library version, or whatever. */
290   g_thread_impl_init();
291 #endif /* HAVE_G_THREAD_IMPL_INIT */
292
293   errorcheck_functions = g_thread_functions_for_glib_use_default;
294   errorcheck_functions.mutex_new = g_mutex_new_errorcheck_impl;
295   errorcheck_functions.mutex_lock = 
296     (void (*)(GMutex *)) g_mutex_lock_errorcheck_impl;
297   errorcheck_functions.mutex_trylock = 
298     (gboolean (*)(GMutex *)) g_mutex_trylock_errorcheck_impl;
299   errorcheck_functions.mutex_unlock = 
300     (void (*)(GMutex *)) g_mutex_unlock_errorcheck_impl;
301   errorcheck_functions.mutex_free = 
302     (void (*)(GMutex *)) g_mutex_free_errorcheck_impl;
303   errorcheck_functions.cond_wait = 
304     (void (*)(GCond *, GMutex *)) g_cond_wait_errorcheck_impl;
305   errorcheck_functions.cond_timed_wait = 
306     (gboolean (*)(GCond *, GMutex *, GTimeVal *)) 
307     g_cond_timed_wait_errorcheck_impl;
308     
309   g_thread_init (&errorcheck_functions);
310 }
311
312 void
313 g_thread_init (GThreadFunctions* init)
314 {
315   gboolean supported;
316
317   if (thread_system_already_initialized)
318     g_error ("GThread system may only be initialized once.");
319     
320   thread_system_already_initialized = TRUE;
321
322   if (init == NULL)
323     {
324 #ifdef HAVE_G_THREAD_IMPL_INIT
325       /* now do any initialization stuff required by the
326        * implementation, but only if called with a NULL argument, of
327        * course. Otherwise it's up to the user to do so. */
328       g_thread_impl_init();
329 #endif /* HAVE_G_THREAD_IMPL_INIT */
330       init = &g_thread_functions_for_glib_use_default;
331     }
332   else
333     g_thread_use_default_impl = FALSE;
334
335   g_thread_functions_for_glib_use = *init;
336
337   /* It is important, that g_threads_got_initialized is not set before the
338    * thread initialization functions of the different modules are called
339    */
340   supported = (init->mutex_new &&  
341                init->mutex_lock && 
342                init->mutex_trylock && 
343                init->mutex_unlock && 
344                init->mutex_free && 
345                init->cond_new && 
346                init->cond_signal && 
347                init->cond_broadcast && 
348                init->cond_wait && 
349                init->cond_timed_wait &&
350                init->cond_free &&
351                init->private_new &&
352                init->private_get &&
353                init->private_set &&
354                init->thread_create &&
355                init->thread_yield &&
356                init->thread_join &&
357                init->thread_exit &&
358                init->thread_set_priority &&
359                init->thread_self);
360
361   /* if somebody is calling g_thread_init (), it means that he wants to
362    * have thread support, so check this
363    */
364   if (!supported)
365     {
366       if (g_thread_use_default_impl)
367         g_error ("Threads are not supported on this platform.");
368       else
369         g_error ("The supplied thread function vector is invalid.");
370     }
371
372   g_thread_priority_map [G_THREAD_PRIORITY_LOW] = PRIORITY_LOW_VALUE;
373   g_thread_priority_map [G_THREAD_PRIORITY_NORMAL] = PRIORITY_NORMAL_VALUE;
374   g_thread_priority_map [G_THREAD_PRIORITY_HIGH] = PRIORITY_HIGH_VALUE;
375   g_thread_priority_map [G_THREAD_PRIORITY_URGENT] = PRIORITY_URGENT_VALUE;
376
377   /* now call the thread initialization functions of the different
378    * glib modules. order does matter, g_mutex_init MUST come first.
379    */
380   g_mutex_init ();
381   g_mem_init ();
382   g_messages_init ();
383   g_convert_init ();
384
385   /* now we can set g_threads_got_initialized and thus enable
386    * all the thread functions
387    */
388   g_threads_got_initialized = TRUE;
389 }
390
391 #else /* !G_THREADS_ENABLED */
392
393 void
394 g_thread_init (GThreadFunctions* init)
395 {
396   g_error ("GLib thread support is disabled.");
397 }
398
399 #endif /* !G_THREADS_ENABLED */