1 /* GLIB - Library of useful routines for C programming
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
4 * gmutex.c: MT safety related functions
5 * Copyright 1998 Sebastian Wilhelmi; University of Karlsruhe
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library 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.
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 * Library General Public License for more details.
18 * You should have received a copy of the GNU Library 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.
25 * Modified by the GLib Team and others 1997-1999. 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/.
42 #if GLIB_SIZEOF_SYSTEM_THREAD == SIZEOF_VOID_P
43 # define g_system_thread_equal(thread1, thread2) \
44 (thread1.dummy_pointer == thread2.dummy_pointer)
45 # define g_system_thread_assign(dest, src) \
46 (dest.dummy_pointer = src.dummy_pointer)
47 #else /* GLIB_SIZEOF_SYSTEM_THREAD != SIZEOF_VOID_P */
48 # define g_system_thread_equal(thread1, thread2) \
49 (memcmp (&thread1, &thread2, GLIB_SIZEOF_SYSTEM_THREAD) == 0)
50 # define g_system_thread_assign(dest, src) \
51 (memcpy (&dest, &src, GLIB_SIZEOF_SYSTEM_THREAD))
52 #endif /* GLIB_SIZEOF_SYSTEM_THREAD == SIZEOF_VOID_P */
54 typedef struct _GRealThread GRealThread
;
60 gpointer private_data
;
61 GSystemThread system_thread
;
64 typedef struct _GStaticPrivateNode GStaticPrivateNode
;
65 struct _GStaticPrivateNode
68 GDestroyNotify destroy
;
71 static void g_thread_cleanup (gpointer data
);
72 static void g_thread_fail (void);
74 /* Global variables */
76 static GSystemThread zero_thread
; /* This is initialized to all zero */
77 gboolean g_thread_use_default_impl
= TRUE
;
78 gboolean g_threads_got_initialized
= FALSE
;
80 #if defined(G_OS_WIN32) && defined(__GNUC__)
83 GThreadFunctions g_thread_functions_for_glib_use
= {
84 (GMutex
*(*)())g_thread_fail
, /* mutex_new */
85 NULL
, /* mutex_lock */
86 NULL
, /* mutex_trylock */
87 NULL
, /* mutex_unlock */
88 NULL
, /* mutex_free */
89 (GCond
*(*)())g_thread_fail
, /* cond_new */
90 NULL
, /* cond_signal */
91 NULL
, /* cond_broadcast */
93 NULL
, /* cond_timed_wait */
95 (GPrivate
*(*)(GDestroyNotify
))g_thread_fail
, /* private_new */
96 NULL
, /* private_get */
97 NULL
, /* private_set */
98 (void(*)(GThreadFunc
, gpointer
, gulong
,
99 gboolean
, gboolean
, GThreadPriority
,
100 gpointer
))g_thread_fail
, /* thread_create */
101 NULL
, /* thread_yield */
102 NULL
, /* thread_join */
103 NULL
, /* thread_exit */
104 NULL
, /* thread_set_priority */
105 NULL
/* thread_self */
110 static GMutex
*g_mutex_protect_static_mutex_allocation
= NULL
;
111 static GMutex
*g_thread_specific_mutex
= NULL
;
112 static GPrivate
*g_thread_specific_private
= NULL
;
114 /* This must be called only once, before any threads are created.
115 * It will only be called from g_thread_init() in -lgthread.
120 GRealThread
* main_thread
;
122 /* We let the main thread (the one that calls g_thread_init) inherit
123 * the data, that it set before calling g_thread_init
125 main_thread
= (GRealThread
*) g_thread_self ();
127 g_thread_specific_private
= g_private_new (g_thread_cleanup
);
128 G_THREAD_UF (private_set
, (g_thread_specific_private
, main_thread
));
129 G_THREAD_UF (thread_self
, (&main_thread
->system_thread
));
131 g_mutex_protect_static_mutex_allocation
= g_mutex_new();
132 g_thread_specific_mutex
= g_mutex_new();
136 g_static_mutex_get_mutex_impl (GMutex
** mutex
)
138 if (!g_thread_supported ())
141 g_assert (g_mutex_protect_static_mutex_allocation
);
143 g_mutex_lock (g_mutex_protect_static_mutex_allocation
);
146 *mutex
= g_mutex_new();
148 g_mutex_unlock (g_mutex_protect_static_mutex_allocation
);
154 g_static_rec_mutex_lock (GStaticRecMutex
* mutex
)
158 g_return_if_fail (mutex
);
160 G_THREAD_UF (thread_self
, (&self
));
162 if (g_system_thread_equal (self
, mutex
->owner
))
167 g_static_mutex_lock (&mutex
->mutex
);
168 g_system_thread_assign (mutex
->owner
, self
);
173 g_static_rec_mutex_trylock (GStaticRecMutex
* mutex
)
177 g_return_val_if_fail (mutex
, FALSE
);
179 G_THREAD_UF (thread_self
, (&self
));
181 if (g_system_thread_equal (self
, mutex
->owner
))
187 if (!g_static_mutex_trylock (&mutex
->mutex
))
190 g_system_thread_assign (mutex
->owner
, self
);
196 g_static_rec_mutex_unlock (GStaticRecMutex
* mutex
)
198 g_return_if_fail (mutex
);
200 if (mutex
->depth
> 1)
205 g_system_thread_assign (mutex
->owner
, zero_thread
);
206 g_static_mutex_unlock (&mutex
->mutex
);
210 g_static_rec_mutex_lock_full (GStaticRecMutex
*mutex
,
213 g_return_if_fail (mutex
);
215 g_static_mutex_lock (&mutex
->mutex
);
216 G_THREAD_UF (thread_self
, (&mutex
->owner
));
217 mutex
->depth
= depth
;
221 g_static_rec_mutex_unlock_full (GStaticRecMutex
*mutex
)
223 gint depth
= mutex
->depth
;
225 g_return_val_if_fail (mutex
, 0);
227 g_system_thread_assign (mutex
->owner
, zero_thread
);
229 g_static_mutex_unlock (&mutex
->mutex
);
236 g_static_private_get (GStaticPrivate
*private_key
)
238 return g_static_private_get_for_thread (private_key
, g_thread_self ());
242 g_static_private_get_for_thread (GStaticPrivate
*private_key
,
246 GRealThread
*self
= (GRealThread
*) thread
;
248 g_return_val_if_fail (thread
, NULL
);
250 array
= self
->private_data
;
254 if (!private_key
->index
)
256 else if (private_key
->index
<= array
->len
)
257 return g_array_index (array
, GStaticPrivateNode
, private_key
->index
- 1).data
;
263 g_static_private_set (GStaticPrivate
*private_key
,
265 GDestroyNotify notify
)
267 g_static_private_set_for_thread (private_key
, g_thread_self (),
272 g_static_private_set_for_thread (GStaticPrivate
*private_key
,
275 GDestroyNotify notify
)
278 GRealThread
*self
=(GRealThread
*) thread
;
279 static guint next_index
= 0;
280 GStaticPrivateNode
*node
;
282 g_return_if_fail (thread
);
284 array
= self
->private_data
;
287 array
= g_array_new (FALSE
, TRUE
, sizeof (GStaticPrivateNode
));
288 self
->private_data
= array
;
291 if (!private_key
->index
)
293 g_mutex_lock (g_thread_specific_mutex
);
295 if (!private_key
->index
)
296 private_key
->index
= ++next_index
;
298 g_mutex_unlock (g_thread_specific_mutex
);
301 if (private_key
->index
> array
->len
)
302 g_array_set_size (array
, private_key
->index
);
304 node
= &g_array_index (array
, GStaticPrivateNode
, private_key
->index
- 1);
307 gpointer ddata
= node
->data
;
308 GDestroyNotify ddestroy
= node
->destroy
;
311 node
->destroy
= notify
;
318 node
->destroy
= notify
;
323 g_thread_cleanup (gpointer data
)
327 GRealThread
* thread
= data
;
328 if (thread
->private_data
)
330 GArray
* array
= thread
->private_data
;
333 for (i
= 0; i
< array
->len
; i
++ )
335 GStaticPrivateNode
*node
=
336 &g_array_index (array
, GStaticPrivateNode
, i
);
338 node
->destroy (node
->data
);
340 g_array_free (array
, TRUE
);
342 /* We only free the thread structure, if it isn't joinable. If
343 it is, the structure is freed in g_thread_join */
344 if (!thread
->thread
.joinable
)
346 /* Just to make sure, this isn't used any more */
347 g_system_thread_assign (thread
->system_thread
, zero_thread
);
356 g_error ("The thread system is not yet initialized.");
359 G_LOCK_DEFINE_STATIC (g_thread_create
);
362 g_thread_create_proxy (gpointer data
)
364 GRealThread
* thread
= data
;
368 /* the lock makes sure, that thread->system_thread is written,
369 before thread->func is called. See g_thread_create */
371 G_LOCK (g_thread_create
);
372 g_private_set (g_thread_specific_private
, data
);
373 G_UNLOCK (g_thread_create
);
375 thread
->func (thread
->arg
);
379 g_thread_create (GThreadFunc thread_func
,
384 GThreadPriority priority
)
386 GRealThread
* result
= g_new (GRealThread
, 1);
388 g_return_val_if_fail (thread_func
, NULL
);
390 result
->thread
.joinable
= joinable
;
391 result
->thread
.bound
= bound
;
392 result
->thread
.priority
= priority
;
393 result
->func
= thread_func
;
395 result
->private_data
= NULL
;
396 G_LOCK (g_thread_create
);
397 G_THREAD_UF (thread_create
, (g_thread_create_proxy
, result
, stack_size
,
398 joinable
, bound
, priority
,
399 &result
->system_thread
));
400 G_UNLOCK (g_thread_create
);
401 return (GThread
*) result
;
405 g_thread_join (GThread
* thread
)
407 GRealThread
* real
= (GRealThread
*) thread
;
410 g_return_if_fail (thread
);
411 g_return_if_fail (thread
->joinable
);
412 g_return_if_fail (!g_system_thread_equal (real
->system_thread
, zero_thread
));
414 G_THREAD_UF (thread_join
, (&real
->system_thread
));
416 /* Just to make sure, this isn't used any more */
417 thread
->joinable
= 0;
418 g_system_thread_assign (real
->system_thread
, zero_thread
);
420 /* the thread structure for non-joinable threads is freed upon
421 thread end. We free the memory here. This will leave loose end,
422 if a joinable thread is not joined. */
428 g_thread_set_priority (GThread
* thread
,
429 GThreadPriority priority
)
431 GRealThread
* real
= (GRealThread
*) thread
;
433 g_return_if_fail (thread
);
434 g_return_if_fail (!g_system_thread_equal (real
->system_thread
, zero_thread
));
436 thread
->priority
= priority
;
437 G_THREAD_CF (thread_set_priority
, (void)0, (&real
->system_thread
, priority
));
443 GRealThread
* thread
= g_private_get (g_thread_specific_private
);
447 /* If no thread data is available, provide and set one. This
448 can happen for the main thread and for threads, that are not
450 thread
= g_new (GRealThread
, 1);
451 thread
->thread
.joinable
= FALSE
; /* This is a save guess */
452 thread
->thread
.bound
= TRUE
; /* This isn't important at all */
453 thread
->thread
.priority
= G_THREAD_PRIORITY_NORMAL
; /* This is
457 thread
->private_data
= NULL
;
459 if (g_thread_supported ())
460 G_THREAD_UF (thread_self
, (&thread
->system_thread
));
462 g_private_set (g_thread_specific_private
, thread
);
465 return (GThread
*)thread
;
468 static void inline g_static_rw_lock_wait (GCond
** cond
, GStaticMutex
* mutex
)
471 *cond
= g_cond_new ();
472 g_cond_wait (*cond
, g_static_mutex_get_mutex (mutex
));
475 static void inline g_static_rw_lock_signal (GStaticRWLock
* lock
)
477 if (lock
->want_to_write
&& lock
->write_cond
)
478 g_cond_signal (lock
->write_cond
);
479 else if (lock
->read_cond
)
480 g_cond_signal (lock
->read_cond
);
483 void g_static_rw_lock_reader_lock (GStaticRWLock
* lock
)
485 g_return_if_fail (lock
);
487 if (!g_threads_got_initialized
)
490 g_static_mutex_lock (&lock
->mutex
);
491 while (lock
->write
|| lock
->want_to_write
)
492 g_static_rw_lock_wait (&lock
->read_cond
, &lock
->mutex
);
493 lock
->read_counter
++;
494 g_static_mutex_unlock (&lock
->mutex
);
497 gboolean
g_static_rw_lock_reader_trylock (GStaticRWLock
* lock
)
499 gboolean ret_val
= FALSE
;
501 g_return_val_if_fail (lock
, FALSE
);
503 if (!g_threads_got_initialized
)
506 g_static_mutex_lock (&lock
->mutex
);
507 if (!lock
->write
&& !lock
->want_to_write
)
509 lock
->read_counter
++;
512 g_static_mutex_unlock (&lock
->mutex
);
516 void g_static_rw_lock_reader_unlock (GStaticRWLock
* lock
)
518 g_return_if_fail (lock
);
520 if (!g_threads_got_initialized
)
523 g_static_mutex_lock (&lock
->mutex
);
524 lock
->read_counter
--;
525 g_static_rw_lock_signal (lock
);
526 g_static_mutex_unlock (&lock
->mutex
);
529 void g_static_rw_lock_writer_lock (GStaticRWLock
* lock
)
531 g_return_if_fail (lock
);
533 if (!g_threads_got_initialized
)
536 g_static_mutex_lock (&lock
->mutex
);
537 lock
->want_to_write
++;
538 while (lock
->write
|| lock
->read_counter
)
539 g_static_rw_lock_wait (&lock
->write_cond
, &lock
->mutex
);
540 lock
->want_to_write
--;
542 g_static_mutex_unlock (&lock
->mutex
);
545 gboolean
g_static_rw_lock_writer_trylock (GStaticRWLock
* lock
)
547 gboolean ret_val
= FALSE
;
549 g_return_val_if_fail (lock
, FALSE
);
551 if (!g_threads_got_initialized
)
554 g_static_mutex_lock (&lock
->mutex
);
555 if (!lock
->write
&& !lock
->read_counter
)
560 g_static_mutex_unlock (&lock
->mutex
);
564 void g_static_rw_lock_writer_unlock (GStaticRWLock
* lock
)
566 g_return_if_fail (lock
);
568 if (!g_threads_got_initialized
)
571 g_static_mutex_lock (&lock
->mutex
);
573 g_static_rw_lock_signal (lock
);
574 g_static_mutex_unlock (&lock
->mutex
);
577 void g_static_rw_lock_free (GStaticRWLock
* lock
)
579 g_return_if_fail (lock
);
582 g_cond_free (lock
->read_cond
);
583 if (lock
->write_cond
)
584 g_cond_free (lock
->write_cond
);