2 * timed-thread.c: Implementation of timed thread joining
5 * Dick Porter (dick@ximian.com)
7 * (C) 2002 Ximian, Inc.
12 #include <mono/os/gc_wrapper.h>
15 #include "timed-thread.h"
17 #include "mono-mutex.h"
22 * Implementation of timed thread joining from the P1003.1d/D14 (July 1999)
23 * draft spec, figure B-6.
26 static pthread_key_t timed_thread_key;
27 static mono_once_t timed_thread_once = MONO_ONCE_INIT;
29 static void timed_thread_init(void)
31 pthread_key_create(&timed_thread_key, NULL);
34 void _wapi_timed_thread_exit(guint32 exitstatus)
39 if((specific = pthread_getspecific(timed_thread_key)) == NULL) {
40 /* Handle cases which won't happen with correct usage.
45 thread=(TimedThread *)specific;
47 mono_mutex_lock(&thread->join_mutex);
49 /* Tell a joiner that we're exiting.
52 g_message(G_GNUC_PRETTY_FUNCTION
53 ": Setting thread %p id %ld exit status to %d",
54 thread, thread->id, exitstatus);
57 thread->exitstatus=exitstatus;
60 if(thread->exit_routine!=NULL) {
61 thread->exit_routine(exitstatus, thread->exit_userdata);
64 pthread_cond_signal(&thread->exit_cond);
65 mono_mutex_unlock(&thread->join_mutex);
67 /* Call pthread_exit() to call destructors and really exit the
73 /* Routine to establish thread specific data value and run the actual
74 * thread start routine which was supplied to timed_thread_create()
76 static void *timed_thread_start_routine(gpointer args) G_GNUC_NORETURN;
77 static void *timed_thread_start_routine(gpointer args)
79 TimedThread *thread = (TimedThread *)args;
81 mono_once(&timed_thread_once, timed_thread_init);
82 pthread_setspecific(timed_thread_key, (void *)thread);
83 pthread_detach(thread->id);
84 _wapi_timed_thread_exit(thread->start_routine(thread->arg));
87 /* Allocate a thread which can be used with timed_thread_join().
89 int _wapi_timed_thread_create(TimedThread **threadp,
90 const pthread_attr_t *attr,
91 guint32 (*start_routine)(gpointer),
92 void (*exit_routine)(guint32, gpointer),
93 gpointer arg, gpointer exit_userdata)
98 thread=(TimedThread *)g_new0(TimedThread, 1);
100 mono_mutex_init(&thread->join_mutex, NULL);
101 pthread_cond_init(&thread->exit_cond, NULL);
102 thread->start_routine = start_routine;
103 thread->exit_routine = exit_routine;
105 thread->exit_userdata = exit_userdata;
106 thread->exitstatus = 0;
107 thread->exiting = FALSE;
111 if((result = pthread_create(&thread->id, attr,
112 timed_thread_start_routine,
113 (void *)thread)) != 0) {
121 int _wapi_timed_thread_join(TimedThread *thread, struct timespec *timeout,
126 mono_mutex_lock(&thread->join_mutex);
129 /* Wait until the thread announces that it's exiting, or until
132 while(result == 0 && !thread->exiting) {
133 if(timeout == NULL) {
134 result = pthread_cond_wait(&thread->exit_cond,
135 &thread->join_mutex);
137 result = pthread_cond_timedwait(&thread->exit_cond,
143 mono_mutex_unlock(&thread->join_mutex);
144 if(result == 0 && thread->exiting) {
145 if(exitstatus!=NULL) {
146 *exitstatus = thread->exitstatus;
152 void _wapi_timed_thread_destroy (TimedThread *thread)
154 mono_mutex_destroy (&thread->join_mutex);
155 pthread_cond_destroy (&thread->exit_cond);