Add a surrogate for thread priorities using PID niceness for systems with
[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 static gboolean thread_system_already_initialized = FALSE;
41 static gint g_thread_priority_map [G_THREAD_PRIORITY_URGENT];
42
43 #include G_THREAD_SOURCE
44
45 #ifndef PRIORITY_LOW_VALUE
46 # define PRIORITY_LOW_VALUE 0
47 #endif
48
49 #ifndef PRIORITY_URGENT_VALUE
50 # define PRIORITY_URGENT_VALUE 0
51 #endif
52
53 #ifndef PRIORITY_NORMAL_VALUE
54 # define PRIORITY_NORMAL_VALUE                                          \
55   PRIORITY_LOW_VALUE + (PRIORITY_URGENT_VALUE - PRIORITY_LOW_VALUE) * 40 / 100 
56 #endif /* PRIORITY_NORMAL_VALUE */
57
58 #ifndef PRIORITY_HIGH_VALUE
59 # define PRIORITY_HIGH_VALUE                                            \
60   PRIORITY_LOW_VALUE + (PRIORITY_URGENT_VALUE - PRIORITY_LOW_VALUE) * 80 / 100 
61 #endif /* PRIORITY_HIGH_VALUE */
62
63 void g_mutex_init (void);
64 void g_mem_init (void);
65 void g_messages_init (void);
66
67 #define G_MUTEX_DEBUG_INFO(mutex) (*((gpointer*)(((char*)mutex)+G_MUTEX_SIZE)))
68
69 typedef struct _ErrorCheckInfo ErrorCheckInfo;
70 struct _ErrorCheckInfo
71 {
72   gchar *name;
73   gchar *location;
74   GThread *owner;
75 };
76
77 static GMutex *
78 g_mutex_new_errorcheck_impl (void)
79 {
80   GMutex *retval = g_thread_functions_for_glib_use_default.mutex_new ();
81   retval = g_realloc (retval, G_MUTEX_SIZE + sizeof (gpointer));
82   G_MUTEX_DEBUG_INFO (retval) = NULL;
83   return retval;
84 }
85
86 static inline void
87 fill_info (ErrorCheckInfo *info,
88            GThread *self,
89            gulong magic, 
90            gchar *name, 
91            gchar *location)
92 {
93   info->owner = self;
94   if (magic == G_MUTEX_DEBUG_MAGIC)
95     {
96       /* We are used with special instrumented calls, where name and
97        * location is provided as well, so use them */
98       info->name = name;
99       info->location = location;
100     }
101   else
102     info->name = info->location = "unknown";
103 }
104
105 static void
106 g_mutex_lock_errorcheck_impl (GMutex *mutex, 
107                               gulong magic, 
108                               gchar *name, 
109                               gchar *location)
110 {
111   ErrorCheckInfo *info;
112   GThread *self = g_thread_self ();
113   if (G_MUTEX_DEBUG_INFO (mutex) == NULL)
114     {
115       /* if the debug info is NULL, we have not yet locked that mutex,
116        * so we do it now */
117       g_thread_functions_for_glib_use_default.mutex_lock (mutex);
118       /* Now we have to check again, because anothe thread might mave
119        * locked the mutex at the same time, we did. This technique is
120        * not 100% save on systems without decent cache coherence,
121        * but we have no choice */ 
122       if (G_MUTEX_DEBUG_INFO (mutex) == NULL)
123         {
124           info = G_MUTEX_DEBUG_INFO (mutex) = g_new0 (ErrorCheckInfo, 1);
125         }
126       g_thread_functions_for_glib_use_default.mutex_unlock (mutex);
127     }
128   
129   info = G_MUTEX_DEBUG_INFO (mutex);
130   if (info->owner == self)
131     g_error ("Trying to recursivly lock the mutex '%s' at '%s', "
132              "previously locked by name '%s' at '%s'", 
133              name, location, info->name, info->location);
134
135   g_thread_functions_for_glib_use_default.mutex_lock (mutex);
136
137   fill_info (info, self, magic, name, location);
138 }
139
140 static gboolean
141 g_mutex_trylock_errorcheck_impl (GMutex *mutex, 
142                                  gulong magic, 
143                                  gchar *name, 
144                                  gchar *location)
145 {
146   ErrorCheckInfo *info = G_MUTEX_DEBUG_INFO (mutex);
147   GThread *self = g_thread_self ();
148   if (!info)
149     {
150       /* This mutex has not yet been used, so simply lock and return TRUE */
151       g_mutex_lock_errorcheck_impl (mutex, magic, name, location);
152       return TRUE;
153     }
154   if (info->owner == self)
155     g_error ("Trying to recursivly lock the mutex '%s' at '%s', "
156              "previously locked by name '%s' at '%s'", 
157              name, location, info->name, info->location);
158   
159   if (!g_thread_functions_for_glib_use_default.mutex_trylock (mutex))
160     return FALSE;
161
162   fill_info (info, self, magic, name, location);
163   return TRUE;
164 }
165
166 static void
167 g_mutex_unlock_errorcheck_impl (GMutex *mutex, 
168                                 gulong magic, 
169                                 gchar *name, 
170                                 gchar *location)
171 {
172   ErrorCheckInfo *info = G_MUTEX_DEBUG_INFO (mutex);
173   GThread *self = g_thread_self ();
174   if (magic != G_MUTEX_DEBUG_MAGIC)
175     name = location = "unknown";
176   if (!info || info->owner != self)
177     g_error ("Trying to unlock the unlocked mutex '%s' at '%s'",
178              name, location);
179   info->owner = NULL;
180   info->name = info->location = NULL;
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 {
187   g_free (G_MUTEX_DEBUG_INFO (mutex));
188   g_thread_functions_for_glib_use_default.mutex_free (mutex);  
189 }
190
191 /* unshadow function declaration. See glib.h */
192 #undef g_thread_init
193
194 void 
195 g_thread_init_with_errorcheck_mutexes (GThreadFunctions* init)
196 {
197   GThreadFunctions errorcheck_functions;
198   if (init)
199     g_error ("Errorcheck mutexes can only be used for native " 
200              "thread implementations. Sorry." );
201   errorcheck_functions = g_thread_functions_for_glib_use_default;
202   errorcheck_functions.mutex_new = g_mutex_new_errorcheck_impl;
203   errorcheck_functions.mutex_lock = 
204     (void (*)(GMutex *)) g_mutex_lock_errorcheck_impl;
205   errorcheck_functions.mutex_trylock = 
206     (gboolean (*)(GMutex *)) g_mutex_trylock_errorcheck_impl;
207   errorcheck_functions.mutex_unlock = 
208     (void (*)(GMutex *)) g_mutex_unlock_errorcheck_impl;
209   errorcheck_functions.mutex_free = g_mutex_free_errorcheck_impl;
210     
211   g_thread_init (&errorcheck_functions);
212 }
213
214 void
215 g_thread_init (GThreadFunctions* init)
216 {
217   gboolean supported;
218
219 #ifndef G_THREADS_ENABLED
220   g_error ("GLib thread support is disabled.");
221 #endif  /* !G_THREADS_ENABLED */
222
223   if (thread_system_already_initialized)
224     g_error ("GThread system may only be initialized once.");
225     
226   thread_system_already_initialized = TRUE;
227
228   if (init == NULL)
229     init = &g_thread_functions_for_glib_use_default;
230   else
231     g_thread_use_default_impl = FALSE;
232
233 #if defined (G_OS_WIN32) && defined (__GNUC__)
234   memcpy(&g_thread_functions_for_glib_use, init, sizeof (*init));
235 #else
236   g_thread_functions_for_glib_use = *init;
237 #endif
238   /* It is important, that g_threads_got_initialized is not set before the
239    * thread initialization functions of the different modules are called
240    */
241
242   supported = (init->mutex_new &&  
243                init->mutex_lock && 
244                init->mutex_trylock && 
245                init->mutex_unlock && 
246                init->mutex_free && 
247                init->cond_new && 
248                init->cond_signal && 
249                init->cond_broadcast && 
250                init->cond_wait && 
251                init->cond_timed_wait &&
252                init->cond_free &&
253                init->private_new &&
254                init->private_get &&
255                init->private_get);
256
257   /* if somebody is calling g_thread_init (), it means that he wants to
258    * have thread support, so check this
259    */
260   if (!supported)
261     {
262       if (g_thread_use_default_impl)
263         g_error ("Threads are not supported on this platform.");
264       else
265         g_error ("The supplied thread function vector is invalid.");
266     }
267
268   /* now do any initialization stuff required by the implementation,
269    * but only if called with a NULL argument, of course. Otherwise
270    * it's up to the user to do so. */
271
272 #ifdef HAVE_G_THREAD_IMPL_INIT
273   if (g_thread_use_default_impl)
274     g_thread_impl_init();
275 #endif
276
277   g_thread_priority_map [G_THREAD_PRIORITY_LOW] = PRIORITY_LOW_VALUE;
278   g_thread_priority_map [G_THREAD_PRIORITY_NORMAL] = PRIORITY_NORMAL_VALUE;
279   g_thread_priority_map [G_THREAD_PRIORITY_HIGH] = PRIORITY_HIGH_VALUE;
280   g_thread_priority_map [G_THREAD_PRIORITY_URGENT] = PRIORITY_URGENT_VALUE;
281
282   /* now call the thread initialization functions of the different
283    * glib modules. order does matter, g_mutex_init MUST come first.
284    */
285   g_mutex_init ();
286   g_mem_init ();
287   g_messages_init ();
288
289   /* now we can set g_threads_got_initialized and thus enable
290    * all the thread functions
291    */
292   g_threads_got_initialized = TRUE;
293
294   /* we want the main thread to run with normal priority */
295   g_thread_set_priority (g_thread_self(), G_THREAD_PRIORITY_NORMAL);
296 }