1 /* GNU Objective C Runtime Thread Interface for POSIX compliant threads
2 Copyright (C) 1996, 1997, 2009 Free Software Foundation, Inc.
3 Contributed by Galen C. Hunt (gchunt@cs.rochester.edu)
4 Modified for Linux/Pthreads by Kai-Uwe Sattler (kus@iti.cs.uni-magdeburg.de)
5 Modified for posix compliance by Chris Ball (cball@fmco.com)
7 This file is part of GCC.
9 GCC is free software; you can redistribute it and/or modify it under the
10 terms of the GNU General Public License as published by the Free Software
11 Foundation; either version 3, or (at your option) any later version.
13 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
14 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
18 Under Section 7 of GPL version 3, you are granted additional
19 permissions described in the GCC Runtime Library Exception, version
20 3.1, as published by the Free Software Foundation.
22 You should have received a copy of the GNU General Public License and
23 a copy of the GCC Runtime Library Exception along with this program;
24 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
25 <http://www.gnu.org/licenses/>. */
29 #include "objc/runtime.h"
32 /* Key structure for maintaining thread specific storage */
33 static pthread_key_t _objc_thread_storage
;
34 static pthread_attr_t _objc_thread_attribs
;
36 /* Backend initialization functions */
38 /* Initialize the threads subsystem. */
40 __objc_init_thread_system(void)
42 /* Initialize the thread storage key */
43 if (pthread_key_create(&_objc_thread_storage
, NULL
) == 0)
46 * The normal default detach state for threads is PTHREAD_CREATE_JOINABLE
47 * which causes threads to not die when you think they should.
49 if (pthread_attr_init(&_objc_thread_attribs
) == 0)
51 if (pthread_attr_setdetachstate(&_objc_thread_attribs
,
52 PTHREAD_CREATE_DETACHED
) == 0)
60 /* Close the threads subsystem. */
62 __objc_close_thread_system(void)
64 if (pthread_key_delete(_objc_thread_storage
) == 0)
66 if (pthread_attr_destroy(&_objc_thread_attribs
) == 0)
73 /* Backend thread functions */
75 /* Create a new thread of execution. */
77 __objc_thread_detach(void (*func
)(void *arg
), void *arg
)
79 objc_thread_t thread_id
;
80 pthread_t new_thread_handle
;
82 if (!(pthread_create(&new_thread_handle
, &_objc_thread_attribs
,
84 thread_id
= *(objc_thread_t
*)&new_thread_handle
;
91 /* Set the current thread's priority.
93 * Be aware that the default schedpolicy often disallows thread priorities.
96 __objc_thread_set_priority(int priority
)
98 pthread_t thread_id
= pthread_self();
100 struct sched_param params
;
101 int priority_min
, priority_max
;
103 if (pthread_getschedparam(thread_id
, &policy
, ¶ms
) == 0)
105 if ((priority_max
= sched_get_priority_max(policy
)) != 0)
108 if ((priority_min
= sched_get_priority_min(policy
)) != 0)
111 if (priority
> priority_max
)
112 priority
= priority_max
;
113 else if (priority
< priority_min
)
114 priority
= priority_min
;
115 params
.sched_priority
= priority
;
118 * The solaris 7 and several other man pages incorrectly state that
119 * this should be a pointer to policy but pthread.h is universally
122 if (pthread_setschedparam(thread_id
, policy
, ¶ms
) == 0)
128 /* Return the current thread's priority. */
130 __objc_thread_get_priority(void)
133 struct sched_param params
;
135 if (pthread_getschedparam(pthread_self(), &policy
, ¶ms
) == 0)
136 return params
.sched_priority
;
141 /* Yield our process time to another thread. */
143 __objc_thread_yield(void)
148 /* Terminate the current thread. */
150 __objc_thread_exit(void)
152 /* exit the thread */
153 pthread_exit(&__objc_thread_exit_status
);
155 /* Failed if we reached here */
159 /* Returns an integer value which uniquely describes a thread. */
161 __objc_thread_id(void)
163 pthread_t self
= pthread_self();
165 return *(objc_thread_t
*)&self
;
168 /* Sets the thread's local storage pointer. */
170 __objc_thread_set_data(void *value
)
172 if (pthread_setspecific(_objc_thread_storage
, value
) == 0)
178 /* Returns the thread's local storage pointer. */
180 __objc_thread_get_data(void)
182 return pthread_getspecific(_objc_thread_storage
);
185 /* Backend mutex functions */
187 /* Allocate a mutex. */
189 __objc_mutex_allocate(objc_mutex_t mutex
)
191 mutex
->backend
= objc_malloc(sizeof(pthread_mutex_t
));
193 if (pthread_mutex_init((pthread_mutex_t
*)mutex
->backend
, NULL
))
195 objc_free(mutex
->backend
);
196 mutex
->backend
= NULL
;
203 /* Deallocate a mutex. */
205 __objc_mutex_deallocate(objc_mutex_t mutex
)
210 * Posix Threads specifically require that the thread be unlocked for
211 * pthread_mutex_destroy to work.
216 if ((count
= pthread_mutex_unlock((pthread_mutex_t
*)mutex
->backend
)) < 0)
220 if (pthread_mutex_destroy((pthread_mutex_t
*)mutex
->backend
))
223 objc_free(mutex
->backend
);
224 mutex
->backend
= NULL
;
228 /* Grab a lock on a mutex. */
230 __objc_mutex_lock(objc_mutex_t mutex
)
232 if (pthread_mutex_lock((pthread_mutex_t
*)mutex
->backend
) == 0)
238 /* Try to grab a lock on a mutex. */
240 __objc_mutex_trylock(objc_mutex_t mutex
)
242 if (pthread_mutex_trylock((pthread_mutex_t
*)mutex
->backend
) == 0)
248 /* Unlock the mutex */
250 __objc_mutex_unlock(objc_mutex_t mutex
)
252 if (pthread_mutex_unlock((pthread_mutex_t
*)mutex
->backend
) == 0)
258 /* Backend condition mutex functions */
260 /* Allocate a condition. */
262 __objc_condition_allocate(objc_condition_t condition
)
264 condition
->backend
= objc_malloc(sizeof(pthread_cond_t
));
266 if (pthread_cond_init((pthread_cond_t
*)condition
->backend
, NULL
))
268 objc_free(condition
->backend
);
269 condition
->backend
= NULL
;
276 /* Deallocate a condition. */
278 __objc_condition_deallocate(objc_condition_t condition
)
280 if (pthread_cond_destroy((pthread_cond_t
*)condition
->backend
))
283 objc_free(condition
->backend
);
284 condition
->backend
= NULL
;
288 /* Wait on the condition */
290 __objc_condition_wait(objc_condition_t condition
, objc_mutex_t mutex
)
292 if (pthread_cond_wait((pthread_cond_t
*)condition
->backend
,
293 (pthread_mutex_t
*)mutex
->backend
) == 0)
299 /* Wake up all threads waiting on this condition. */
301 __objc_condition_broadcast(objc_condition_t condition
)
303 if (pthread_cond_broadcast((pthread_cond_t
*)condition
->backend
) == 0)
309 /* Wake up one thread waiting on this condition. */
311 __objc_condition_signal(objc_condition_t condition
)
313 if (pthread_cond_signal((pthread_cond_t
*)condition
->backend
) == 0)