|
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 * Portions copyright (c) 2006-2009 Nokia Corporation. All rights reserved. |
|
7 * |
|
8 * This library is free software; you can redistribute it and/or |
|
9 * modify it under the terms of the GNU Lesser General Public |
|
10 * License as published by the Free Software Foundation; either |
|
11 * version 2 of the License, or (at your option) any later version. |
|
12 * |
|
13 * This library is distributed in the hope that it will be useful, |
|
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
16 * Lesser General Public License for more details. |
|
17 * |
|
18 * You should have received a copy of the GNU Lesser General Public |
|
19 * License along with this library; if not, write to the |
|
20 * Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
|
21 * Boston, MA 02111-1307, USA. |
|
22 */ |
|
23 |
|
24 /* |
|
25 * Modified by the GLib Team and others 1997-2000. See the AUTHORS |
|
26 * file for a list of people on the GLib Team. See the ChangeLog |
|
27 * files for a list of changes. These files are distributed with |
|
28 * GLib at ftp://ftp.gtk.org/pub/gtk/. |
|
29 */ |
|
30 |
|
31 /* |
|
32 * MT safe |
|
33 */ |
|
34 |
|
35 #include "config.h" |
|
36 |
|
37 #include "glib.h" |
|
38 #include "gthreadprivate.h" |
|
39 |
|
40 #ifdef __SYMBIAN32__ |
|
41 #include <string.h> |
|
42 #endif//__SYMBIAN32__ |
|
43 |
|
44 #ifdef __SYMBIAN32__ |
|
45 #include <glib_global.h> |
|
46 #include "gthread_wsd.h" |
|
47 #endif /* __SYMBIAN32__ */ |
|
48 |
|
49 #ifdef G_THREADS_ENABLED |
|
50 #if EMULATOR |
|
51 PLS(zero_thread,gthread_impl,GSystemThread) |
|
52 PLS(thread_system_already_initialized,gthread_impl,gboolean) |
|
53 PLS_ARRAY(g_thread_priority_map,gthread_impl,gint) |
|
54 |
|
55 #define zero_thread (*FUNCTION_NAME(zero_thread,gthread_impl)()) |
|
56 #define thread_system_already_initialized (*FUNCTION_NAME(thread_system_already_initialized,gthread_impl)()) |
|
57 #define g_thread_priority_map (FUNCTION_NAME(g_thread_priority_map,gthread_impl)()) |
|
58 #else |
|
59 static GSystemThread zero_thread; /* This is initialized to all zero */ |
|
60 static gboolean thread_system_already_initialized = FALSE; |
|
61 static gint g_thread_priority_map [G_THREAD_PRIORITY_URGENT + 1]; |
|
62 |
|
63 #endif /* EMULATOR */ |
|
64 |
|
65 #include G_THREAD_SOURCE |
|
66 |
|
67 #ifndef PRIORITY_LOW_VALUE |
|
68 # define PRIORITY_LOW_VALUE 0 |
|
69 #endif |
|
70 |
|
71 #ifndef PRIORITY_URGENT_VALUE |
|
72 # define PRIORITY_URGENT_VALUE 0 |
|
73 #endif |
|
74 |
|
75 #ifndef PRIORITY_NORMAL_VALUE |
|
76 # define PRIORITY_NORMAL_VALUE \ |
|
77 ((PRIORITY_LOW_VALUE * 6 + PRIORITY_URGENT_VALUE * 4) / 10) |
|
78 #endif /* PRIORITY_NORMAL_VALUE */ |
|
79 |
|
80 #ifndef PRIORITY_HIGH_VALUE |
|
81 # define PRIORITY_HIGH_VALUE \ |
|
82 ((PRIORITY_NORMAL_VALUE + PRIORITY_URGENT_VALUE * 2) / 3) |
|
83 #endif /* PRIORITY_HIGH_VALUE */ |
|
84 |
|
85 void g_mutex_init (void); |
|
86 void g_mem_init (void); |
|
87 void g_messages_init (void); |
|
88 void g_convert_init (void); |
|
89 void g_rand_init (void); |
|
90 void g_main_thread_init (void); |
|
91 |
|
92 typedef struct _GMutexDebugInfo GMutexDebugInfo; |
|
93 struct _GMutexDebugInfo |
|
94 { |
|
95 gchar *location; |
|
96 GSystemThread owner; |
|
97 }; |
|
98 |
|
99 #define G_MUTEX_DEBUG_INFO(mutex) \ |
|
100 (((GMutexDebugInfo*)(((char*)mutex)+G_MUTEX_SIZE))) |
|
101 |
|
102 static GMutex * |
|
103 g_mutex_new_errorcheck_impl (void) |
|
104 { |
|
105 GMutex *retval = g_thread_functions_for_glib_use_default.mutex_new (); |
|
106 GMutexDebugInfo *info; |
|
107 retval = g_realloc (retval, G_MUTEX_SIZE + sizeof (GMutexDebugInfo)); |
|
108 |
|
109 info = G_MUTEX_DEBUG_INFO (retval); |
|
110 g_system_thread_assign (info->owner, zero_thread); |
|
111 info->location = "invalid"; |
|
112 |
|
113 return retval; |
|
114 } |
|
115 |
|
116 static void |
|
117 g_mutex_lock_errorcheck_impl (GMutex *mutex, |
|
118 const gulong magic, |
|
119 gchar * const location) |
|
120 { |
|
121 GMutexDebugInfo *info = G_MUTEX_DEBUG_INFO (mutex); |
|
122 gchar *loc = (magic == G_MUTEX_DEBUG_MAGIC) ? location : "unknown"; |
|
123 |
|
124 GSystemThread self; |
|
125 g_thread_functions_for_glib_use.thread_self (&self); |
|
126 |
|
127 if (g_system_thread_equal (info->owner, self)) |
|
128 g_error ("Trying to recursivly lock a mutex at '%s', " |
|
129 "previously locked at '%s'", |
|
130 loc, info->location); |
|
131 |
|
132 g_thread_functions_for_glib_use_default.mutex_lock (mutex); |
|
133 |
|
134 g_system_thread_assign (info->owner, self); |
|
135 info->location = loc; |
|
136 } |
|
137 |
|
138 static gboolean |
|
139 g_mutex_trylock_errorcheck_impl (GMutex *mutex, |
|
140 const gulong magic, |
|
141 gchar * const location) |
|
142 { |
|
143 GMutexDebugInfo *info = G_MUTEX_DEBUG_INFO (mutex); |
|
144 gchar *loc = (magic == G_MUTEX_DEBUG_MAGIC) ? location : "unknown"; |
|
145 |
|
146 GSystemThread self; |
|
147 g_thread_functions_for_glib_use.thread_self (&self); |
|
148 |
|
149 if (g_system_thread_equal (info->owner, self)) |
|
150 g_error ("Trying to recursivly lock a mutex at '%s', " |
|
151 "previously locked at '%s'", |
|
152 loc, info->location); |
|
153 |
|
154 if (!g_thread_functions_for_glib_use_default.mutex_trylock (mutex)) |
|
155 return FALSE; |
|
156 |
|
157 g_system_thread_assign (info->owner, self); |
|
158 info->location = loc; |
|
159 |
|
160 return TRUE; |
|
161 } |
|
162 |
|
163 static void |
|
164 g_mutex_unlock_errorcheck_impl (GMutex *mutex, |
|
165 const gulong magic, |
|
166 gchar * const location) |
|
167 { |
|
168 GMutexDebugInfo *info = G_MUTEX_DEBUG_INFO (mutex); |
|
169 gchar *loc = (magic == G_MUTEX_DEBUG_MAGIC) ? location : "unknown"; |
|
170 |
|
171 GSystemThread self; |
|
172 g_thread_functions_for_glib_use.thread_self (&self); |
|
173 |
|
174 if (g_system_thread_equal (info->owner, zero_thread)) |
|
175 g_error ("Trying to unlock an unlocked mutex at '%s'", loc); |
|
176 |
|
177 if (!g_system_thread_equal (info->owner, self)) |
|
178 g_warning ("Trying to unlock a mutex at '%s', " |
|
179 "previously locked by a different thread at '%s'", |
|
180 loc, info->location); |
|
181 |
|
182 g_system_thread_assign (info->owner, zero_thread); |
|
183 info->location = NULL; |
|
184 |
|
185 g_thread_functions_for_glib_use_default.mutex_unlock (mutex); |
|
186 } |
|
187 |
|
188 static void |
|
189 g_mutex_free_errorcheck_impl (GMutex *mutex, |
|
190 const gulong magic, |
|
191 gchar * const location) |
|
192 { |
|
193 GMutexDebugInfo *info = G_MUTEX_DEBUG_INFO (mutex); |
|
194 gchar *loc = (magic == G_MUTEX_DEBUG_MAGIC) ? location : "unknown"; |
|
195 |
|
196 if (info && !g_system_thread_equal (info->owner, zero_thread)) |
|
197 g_error ("Trying to free a locked mutex at '%s', " |
|
198 "which was previously locked at '%s'", |
|
199 loc, info->location); |
|
200 |
|
201 g_thread_functions_for_glib_use_default.mutex_free (mutex); |
|
202 } |
|
203 |
|
204 static void |
|
205 g_cond_wait_errorcheck_impl (GCond *cond, |
|
206 GMutex *mutex, |
|
207 const gulong magic, |
|
208 gchar * const location) |
|
209 { |
|
210 GMutexDebugInfo *info = G_MUTEX_DEBUG_INFO (mutex); |
|
211 gchar *loc = (magic == G_MUTEX_DEBUG_MAGIC) ? location : "unknown"; |
|
212 |
|
213 GSystemThread self; |
|
214 g_thread_functions_for_glib_use.thread_self (&self); |
|
215 |
|
216 if (g_system_thread_equal (info->owner, zero_thread)) |
|
217 g_error ("Trying to use an unlocked mutex in g_cond_wait() at '%s'", loc); |
|
218 |
|
219 if (!g_system_thread_equal (info->owner, self)) |
|
220 g_error ("Trying to use a mutex locked by another thread in " |
|
221 "g_cond_wait() at '%s'", loc); |
|
222 |
|
223 g_system_thread_assign (info->owner, zero_thread); |
|
224 loc = info->location; |
|
225 |
|
226 g_thread_functions_for_glib_use_default.cond_wait (cond, mutex); |
|
227 |
|
228 g_system_thread_assign (info->owner, self); |
|
229 info->location = loc; |
|
230 } |
|
231 |
|
232 |
|
233 static gboolean |
|
234 g_cond_timed_wait_errorcheck_impl (GCond *cond, |
|
235 GMutex *mutex, |
|
236 GTimeVal *end_time, |
|
237 const gulong magic, |
|
238 gchar * const location) |
|
239 { |
|
240 GMutexDebugInfo *info = G_MUTEX_DEBUG_INFO (mutex); |
|
241 gchar *loc = (magic == G_MUTEX_DEBUG_MAGIC) ? location : "unknown"; |
|
242 gboolean retval; |
|
243 |
|
244 GSystemThread self; |
|
245 g_thread_functions_for_glib_use.thread_self (&self); |
|
246 |
|
247 if (g_system_thread_equal (info->owner, zero_thread)) |
|
248 g_error ("Trying to use an unlocked mutex in g_cond_timed_wait() at '%s'", |
|
249 loc); |
|
250 |
|
251 if (!g_system_thread_equal (info->owner, self)) |
|
252 g_error ("Trying to use a mutex locked by another thread in " |
|
253 "g_cond_timed_wait() at '%s'", loc); |
|
254 |
|
255 g_system_thread_assign (info->owner, zero_thread); |
|
256 loc = info->location; |
|
257 |
|
258 retval = g_thread_functions_for_glib_use_default.cond_timed_wait (cond, |
|
259 mutex, |
|
260 end_time); |
|
261 |
|
262 g_system_thread_assign (info->owner, self); |
|
263 info->location = loc; |
|
264 |
|
265 return retval; |
|
266 } |
|
267 |
|
268 |
|
269 /* unshadow function declaration. See gthread.h */ |
|
270 #undef g_thread_init |
|
271 |
|
272 EXPORT_C |
|
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 EXPORT_C |
|
313 void |
|
314 g_thread_init (GThreadFunctions* init) |
|
315 { |
|
316 gboolean supported; |
|
317 |
|
318 if (thread_system_already_initialized) |
|
319 g_error ("GThread system may only be initialized once."); |
|
320 |
|
321 thread_system_already_initialized = TRUE; |
|
322 |
|
323 if (init == NULL) |
|
324 { |
|
325 #ifdef HAVE_G_THREAD_IMPL_INIT |
|
326 /* now do any initialization stuff required by the |
|
327 * implementation, but only if called with a NULL argument, of |
|
328 * course. Otherwise it's up to the user to do so. */ |
|
329 g_thread_impl_init(); |
|
330 #endif /* HAVE_G_THREAD_IMPL_INIT */ |
|
331 #ifdef __SYMBIAN32__ |
|
332 memcpy(&g_thread_functions_for_glib_use_default, &g_thread_functions_for_glib_use_default_temp, sizeof(GThreadFunctions)); |
|
333 #endif//__SYMBIAN32__ |
|
334 init = &g_thread_functions_for_glib_use_default; |
|
335 } |
|
336 else |
|
337 g_thread_use_default_impl = FALSE; |
|
338 |
|
339 g_thread_functions_for_glib_use = *init; |
|
340 if (g_thread_gettime_impl) |
|
341 g_thread_gettime = g_thread_gettime_impl; |
|
342 |
|
343 supported = (init->mutex_new && |
|
344 init->mutex_lock && |
|
345 init->mutex_trylock && |
|
346 init->mutex_unlock && |
|
347 init->mutex_free && |
|
348 init->cond_new && |
|
349 init->cond_signal && |
|
350 init->cond_broadcast && |
|
351 init->cond_wait && |
|
352 init->cond_timed_wait && |
|
353 init->cond_free && |
|
354 init->private_new && |
|
355 init->private_get && |
|
356 init->private_set && |
|
357 init->thread_create && |
|
358 init->thread_yield && |
|
359 init->thread_join && |
|
360 init->thread_exit && |
|
361 init->thread_set_priority && |
|
362 init->thread_self); |
|
363 |
|
364 /* if somebody is calling g_thread_init (), it means that he wants to |
|
365 * have thread support, so check this |
|
366 */ |
|
367 if (!supported) |
|
368 { |
|
369 if (g_thread_use_default_impl) |
|
370 g_error ("Threads are not supported on this platform."); |
|
371 else |
|
372 g_error ("The supplied thread function vector is invalid."); |
|
373 } |
|
374 |
|
375 g_thread_priority_map [G_THREAD_PRIORITY_LOW] = PRIORITY_LOW_VALUE; |
|
376 g_thread_priority_map [G_THREAD_PRIORITY_NORMAL] = PRIORITY_NORMAL_VALUE; |
|
377 g_thread_priority_map [G_THREAD_PRIORITY_HIGH] = PRIORITY_HIGH_VALUE; |
|
378 g_thread_priority_map [G_THREAD_PRIORITY_URGENT] = PRIORITY_URGENT_VALUE; |
|
379 |
|
380 g_thread_init_glib (); |
|
381 } |
|
382 |
|
383 #else /* !G_THREADS_ENABLED */ |
|
384 |
|
385 void |
|
386 g_thread_init (GThreadFunctions* init) |
|
387 { |
|
388 g_error ("GLib thread support is disabled."); |
|
389 } |
|
390 |
|
391 void |
|
392 g_thread_init_with_errorcheck_mutexes (GThreadFunctions* init) |
|
393 { |
|
394 g_error ("GLib thread support is disabled."); |
|
395 } |
|
396 |
|
397 #endif /* !G_THREADS_ENABLED */ |