Fix candidate for PR c++/43206
[gcc.git] / libobjc / thr-posix.c
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)
6
7 This file is part of GCC.
8
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.
12
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
16 details.
17
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.
21
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/>. */
26
27
28 #include "objc/thr.h"
29 #include "objc/runtime.h"
30 #include <pthread.h>
31
32 /* Key structure for maintaining thread specific storage */
33 static pthread_key_t _objc_thread_storage;
34 static pthread_attr_t _objc_thread_attribs;
35
36 /* Backend initialization functions */
37
38 /* Initialize the threads subsystem. */
39 int
40 __objc_init_thread_system(void)
41 {
42 /* Initialize the thread storage key */
43 if (pthread_key_create(&_objc_thread_storage, NULL) == 0)
44 {
45 /*
46 * The normal default detach state for threads is PTHREAD_CREATE_JOINABLE
47 * which causes threads to not die when you think they should.
48 */
49 if (pthread_attr_init(&_objc_thread_attribs) == 0)
50 {
51 if (pthread_attr_setdetachstate(&_objc_thread_attribs,
52 PTHREAD_CREATE_DETACHED) == 0)
53 return 0;
54 }
55 }
56
57 return -1;
58 }
59
60 /* Close the threads subsystem. */
61 int
62 __objc_close_thread_system(void)
63 {
64 if (pthread_key_delete(_objc_thread_storage) == 0)
65 {
66 if (pthread_attr_destroy(&_objc_thread_attribs) == 0)
67 return 0;
68 }
69
70 return -1;
71 }
72
73 /* Backend thread functions */
74
75 /* Create a new thread of execution. */
76 objc_thread_t
77 __objc_thread_detach(void (*func)(void *arg), void *arg)
78 {
79 objc_thread_t thread_id;
80 pthread_t new_thread_handle;
81
82 if (!(pthread_create(&new_thread_handle, &_objc_thread_attribs,
83 (void *)func, arg)))
84 thread_id = *(objc_thread_t *)&new_thread_handle;
85 else
86 thread_id = NULL;
87
88 return thread_id;
89 }
90
91 /* Set the current thread's priority.
92 *
93 * Be aware that the default schedpolicy often disallows thread priorities.
94 */
95 int
96 __objc_thread_set_priority(int priority)
97 {
98 pthread_t thread_id = pthread_self();
99 int policy;
100 struct sched_param params;
101 int priority_min, priority_max;
102
103 if (pthread_getschedparam(thread_id, &policy, &params) == 0)
104 {
105 if ((priority_max = sched_get_priority_max(policy)) != 0)
106 return -1;
107
108 if ((priority_min = sched_get_priority_min(policy)) != 0)
109 return -1;
110
111 if (priority > priority_max)
112 priority = priority_max;
113 else if (priority < priority_min)
114 priority = priority_min;
115 params.sched_priority = priority;
116
117 /*
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
120 * at odds with this.
121 */
122 if (pthread_setschedparam(thread_id, policy, &params) == 0)
123 return 0;
124 }
125 return -1;
126 }
127
128 /* Return the current thread's priority. */
129 int
130 __objc_thread_get_priority(void)
131 {
132 int policy;
133 struct sched_param params;
134
135 if (pthread_getschedparam(pthread_self(), &policy, &params) == 0)
136 return params.sched_priority;
137 else
138 return -1;
139 }
140
141 /* Yield our process time to another thread. */
142 void
143 __objc_thread_yield(void)
144 {
145 sched_yield();
146 }
147
148 /* Terminate the current thread. */
149 int
150 __objc_thread_exit(void)
151 {
152 /* exit the thread */
153 pthread_exit(&__objc_thread_exit_status);
154
155 /* Failed if we reached here */
156 return -1;
157 }
158
159 /* Returns an integer value which uniquely describes a thread. */
160 objc_thread_t
161 __objc_thread_id(void)
162 {
163 pthread_t self = pthread_self();
164
165 return *(objc_thread_t *)&self;
166 }
167
168 /* Sets the thread's local storage pointer. */
169 int
170 __objc_thread_set_data(void *value)
171 {
172 if (pthread_setspecific(_objc_thread_storage, value) == 0)
173 return 0;
174 else
175 return -1;
176 }
177
178 /* Returns the thread's local storage pointer. */
179 void *
180 __objc_thread_get_data(void)
181 {
182 return pthread_getspecific(_objc_thread_storage);
183 }
184
185 /* Backend mutex functions */
186
187 /* Allocate a mutex. */
188 int
189 __objc_mutex_allocate(objc_mutex_t mutex)
190 {
191 mutex->backend = objc_malloc(sizeof(pthread_mutex_t));
192
193 if (pthread_mutex_init((pthread_mutex_t *)mutex->backend, NULL))
194 {
195 objc_free(mutex->backend);
196 mutex->backend = NULL;
197 return -1;
198 }
199
200 return 0;
201 }
202
203 /* Deallocate a mutex. */
204 int
205 __objc_mutex_deallocate(objc_mutex_t mutex)
206 {
207 int count = 1;
208
209 /*
210 * Posix Threads specifically require that the thread be unlocked for
211 * pthread_mutex_destroy to work.
212 */
213
214 while (count)
215 {
216 if ((count = pthread_mutex_unlock((pthread_mutex_t*)mutex->backend)) < 0)
217 return -1;
218 }
219
220 if (pthread_mutex_destroy((pthread_mutex_t *)mutex->backend))
221 return -1;
222
223 objc_free(mutex->backend);
224 mutex->backend = NULL;
225 return 0;
226 }
227
228 /* Grab a lock on a mutex. */
229 int
230 __objc_mutex_lock(objc_mutex_t mutex)
231 {
232 if (pthread_mutex_lock((pthread_mutex_t *)mutex->backend) == 0)
233 return 0;
234 else
235 return -1;
236 }
237
238 /* Try to grab a lock on a mutex. */
239 int
240 __objc_mutex_trylock(objc_mutex_t mutex)
241 {
242 if (pthread_mutex_trylock((pthread_mutex_t *)mutex->backend) == 0)
243 return 0;
244 else
245 return -1;
246 }
247
248 /* Unlock the mutex */
249 int
250 __objc_mutex_unlock(objc_mutex_t mutex)
251 {
252 if (pthread_mutex_unlock((pthread_mutex_t *)mutex->backend) == 0)
253 return 0;
254 else
255 return -1;
256 }
257
258 /* Backend condition mutex functions */
259
260 /* Allocate a condition. */
261 int
262 __objc_condition_allocate(objc_condition_t condition)
263 {
264 condition->backend = objc_malloc(sizeof(pthread_cond_t));
265
266 if (pthread_cond_init((pthread_cond_t *)condition->backend, NULL))
267 {
268 objc_free(condition->backend);
269 condition->backend = NULL;
270 return -1;
271 }
272
273 return 0;
274 }
275
276 /* Deallocate a condition. */
277 int
278 __objc_condition_deallocate(objc_condition_t condition)
279 {
280 if (pthread_cond_destroy((pthread_cond_t *)condition->backend))
281 return -1;
282
283 objc_free(condition->backend);
284 condition->backend = NULL;
285 return 0;
286 }
287
288 /* Wait on the condition */
289 int
290 __objc_condition_wait(objc_condition_t condition, objc_mutex_t mutex)
291 {
292 if (pthread_cond_wait((pthread_cond_t *)condition->backend,
293 (pthread_mutex_t *)mutex->backend) == 0)
294 return 0;
295 else
296 return -1;
297 }
298
299 /* Wake up all threads waiting on this condition. */
300 int
301 __objc_condition_broadcast(objc_condition_t condition)
302 {
303 if (pthread_cond_broadcast((pthread_cond_t *)condition->backend) == 0)
304 return 0;
305 else
306 return -1;
307 }
308
309 /* Wake up one thread waiting on this condition. */
310 int
311 __objc_condition_signal(objc_condition_t condition)
312 {
313 if (pthread_cond_signal((pthread_cond_t *)condition->backend) == 0)
314 return 0;
315 else
316 return -1;
317 }