]> git.saurik.com Git - apple/libc.git/blame - pthreads/pthread_cancelable.c
Libc-825.24.tar.gz
[apple/libc.git] / pthreads / pthread_cancelable.c
CommitLineData
224c7076 1/*
34e8f829 2 * Copyright (c) 2000-2008 Apple Inc. All rights reserved.
224c7076
A
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23/*
24 * Copyright 1996 1995 by Open Software Foundation, Inc. 1997 1996 1995 1994 1993 1992 1991
25 * All Rights Reserved
26 *
27 * Permission to use, copy, modify, and distribute this software and
28 * its documentation for any purpose and without fee is hereby granted,
29 * provided that the above copyright notice appears in all copies and
30 * that both the copyright notice and this permission notice appear in
31 * supporting documentation.
32 *
33 * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
34 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
35 * FOR A PARTICULAR PURPOSE.
36 *
37 * IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
38 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
39 * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
40 * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
41 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
42 *
43 */
44/*
45 * MkLinux
46 */
47
48/*
49 * POSIX Pthread Library
50 */
51
52#include "pthread_internals.h"
53
54#include <assert.h>
55#include <stdio.h> /* For printf(). */
56#include <stdlib.h>
57#include <errno.h> /* For __mach_errno_addr() prototype. */
58#include <signal.h>
59#include <sys/time.h>
60#include <sys/resource.h>
61#include <sys/sysctl.h>
62#include <sys/queue.h>
63#include <machine/vmparam.h>
64#include <mach/vm_statistics.h>
65
66extern int __unix_conforming;
67extern void __posix_join_cleanup(void *arg);
68extern pthread_lock_t _pthread_list_lock;
69extern void _pthread_testcancel(pthread_t thread, int isconforming);
70extern int _pthread_reap_thread(pthread_t th, mach_port_t kernel_thread, void **value_ptr, int conforming);
71extern int _pthread_cond_wait(pthread_cond_t *cond,
72 pthread_mutex_t *mutex,
73 const struct timespec *abstime,
74 int isRelative,
75 int isconforming);
76extern int __sigwait(const sigset_t *set, int *sig);
77
ad3c9f2a
A
78#ifdef VARIANT_CANCELABLE
79extern int __semwait_signal(int cond_sem, int mutex_sem, int timeout, int relative, __int64_t tv_sec, __int32_t tv_nsec);
80#else
81extern int __semwait_signal(int cond_sem, int mutex_sem, int timeout, int relative, __int64_t tv_sec, __int32_t tv_nsec) __asm__("___semwait_signal_nocancel");
82#endif
83
224c7076
A
84/*
85 * Wait for a thread to terminate and obtain its exit value.
86 */
87int
88pthread_join(pthread_t thread,
89 void **value_ptr)
90{
224c7076
A
91 int res = 0;
92 pthread_t self = pthread_self();
224c7076
A
93 mach_port_t kthport;
94 int conforming = 0;
34e8f829
A
95#if !__DARWIN_UNIX03
96 kern_return_t kern_res;
97#endif
224c7076
A
98
99#if __DARWIN_UNIX03
100 if (__unix_conforming == 0)
101 __unix_conforming = 1;
102
103#ifdef VARIANT_CANCELABLE
104 _pthread_testcancel(self, 1);
105#endif /* VARIANT_CANCELABLE */
106#endif /* __DARWIN_UNIX03 */
107
108 if ((res = _pthread_lookup_thread(thread, &kthport, 1)) != 0)
109 return(res);
110
111 if (thread->sig == _PTHREAD_SIG)
112 {
113 if (thread->newstyle == 0) {
114 semaphore_t death = new_sem_from_pool(); /* in case we need it */
115
116 LOCK(thread->lock);
117 if ((thread->detached & PTHREAD_CREATE_JOINABLE) &&
118 thread->death == SEMAPHORE_NULL)
119 {
120
121 assert(thread->joiner == NULL);
122 if (thread != self && (self == NULL || self->joiner != thread))
123 {
124 int already_exited = (thread->detached & _PTHREAD_EXITED);
125
126 thread->death = death;
127 thread->joiner = self;
128 UNLOCK(thread->lock);
129
130 if (!already_exited)
131 {
132#if __DARWIN_UNIX03
133 /* Wait for it to signal... */
134 pthread_cleanup_push(__posix_join_cleanup, (void *)thread);
135 do {
34e8f829 136 res = __semwait_signal(death, 0, 0, 0, (int64_t)0, (int32_t)0);
224c7076
A
137 } while ((res < 0) && (errno == EINTR));
138 pthread_cleanup_pop(0);
139
140#else /* __DARWIN_UNIX03 */
141 /* Wait for it to signal... */
142 do {
143 PTHREAD_MACH_CALL(semaphore_wait(death), kern_res);
144 } while (kern_res != KERN_SUCCESS);
145#endif /* __DARWIN_UNIX03 */
146 }
147
148 LOCK(_pthread_list_lock);
149 TAILQ_REMOVE(&__pthread_head, thread, plist);
150#if WQ_TRACE
151 __kdebug_trace(0x9000010, thread, 0, 0, 16, 0);
152#endif
153 UNLOCK(_pthread_list_lock);
154 /* ... and wait for it to really be dead */
155 while ((res = _pthread_reap_thread(thread,
156 thread->kernel_thread,
157 value_ptr, __unix_conforming)) == EAGAIN)
158 {
159 sched_yield();
160 }
161
162 } else {
163 UNLOCK(thread->lock);
164 res = EDEADLK;
165 }
166 } else {
167 UNLOCK(thread->lock);
168 res = EINVAL;
169 }
170 restore_sem_to_pool(death);
171 return res;
172 } else {
173 /* new style */
174
175 semaphore_t death = SEMAPHORE_NULL; /* in case we need it */
176 semaphore_t joinsem = SEMAPHORE_NULL;
177
34e8f829 178 if (thread->joiner_notify == MACH_PORT_NULL)
224c7076
A
179 death = new_sem_from_pool();
180
181 LOCK(thread->lock);
182 if ((thread->detached & PTHREAD_CREATE_JOINABLE) &&
183 (thread->joiner == NULL))
184 {
185 assert(thread->kernel_thread == kthport);
186 if (thread != self && (self == NULL || self->joiner != thread))
187 {
34e8f829 188 if (thread->joiner_notify == MACH_PORT_NULL) {
224c7076 189 if (death == SEMAPHORE_NULL)
34e8f829 190 LIBC_ABORT("thread %p: death == SEMAPHORE_NULL", thread);
224c7076
A
191 thread->joiner_notify = death;
192 death = SEMAPHORE_NULL;
193 }
194 joinsem = thread->joiner_notify;
195 thread->joiner = self;
196 UNLOCK(thread->lock);
197
198 if (death != SEMAPHORE_NULL) {
199 restore_sem_to_pool(death);
200 death = SEMAPHORE_NULL;
201 }
202#if __DARWIN_UNIX03
203 /* Wait for it to signal... */
204 pthread_cleanup_push(__posix_join_cleanup, (void *)thread);
205 do {
34e8f829 206 res = __semwait_signal(joinsem, 0, 0, 0, (int64_t)0, (int32_t)0);
224c7076
A
207 } while ((res < 0) && (errno == EINTR));
208 pthread_cleanup_pop(0);
209#else /* __DARWIN_UNIX03 */
210 /* Wait for it to signal... */
211 do {
212 PTHREAD_MACH_CALL(semaphore_wait(joinsem), kern_res);
213 } while (kern_res != KERN_SUCCESS);
214#endif /* __DARWIN_UNIX03 */
215
216 restore_sem_to_pool(joinsem);
217 res = _pthread_join_cleanup(thread, value_ptr, conforming);
218 } else {
219 UNLOCK(thread->lock);
220 res = EDEADLK;
221 }
222 } else {
223 UNLOCK(thread->lock);
224 res = EINVAL;
225 }
226 if (death != SEMAPHORE_NULL)
227 restore_sem_to_pool(death);
228 return res;
229 }/* end of new style */
230 }
231 return ESRCH;
232}
233
234int
235pthread_cond_wait(pthread_cond_t *cond,
236 pthread_mutex_t *mutex)
237{
238 int conforming;
239#if __DARWIN_UNIX03
240
241 if (__unix_conforming == 0)
242 __unix_conforming = 1;
243
244#ifdef VARIANT_CANCELABLE
245 conforming = 1;
246#else /* !VARIANT_CANCELABLE */
247 conforming = -1;
248#endif /* VARIANT_CANCELABLE */
249#else /* __DARWIN_UNIX03 */
250 conforming = 0;
251#endif /* __DARWIN_UNIX03 */
252 return (_pthread_cond_wait(cond, mutex, (struct timespec *)NULL, 0, conforming));
253}
254
255int
256pthread_cond_timedwait(pthread_cond_t *cond,
257 pthread_mutex_t *mutex,
258 const struct timespec *abstime)
259{
260 int conforming;
261#if __DARWIN_UNIX03
262 if (__unix_conforming == 0)
263 __unix_conforming = 1;
264
265#ifdef VARIANT_CANCELABLE
266 conforming = 1;
267#else /* !VARIANT_CANCELABLE */
268 conforming = -1;
269#endif /* VARIANT_CANCELABLE */
270#else /* __DARWIN_UNIX03 */
271 conforming = 0;
272#endif /* __DARWIN_UNIX03 */
273
274 return (_pthread_cond_wait(cond, mutex, abstime, 0, conforming));
275}
276
277int
278sigwait(const sigset_t * set, int * sig)
279{
280#if __DARWIN_UNIX03
281 int err = 0;
282
283 if (__unix_conforming == 0)
284 __unix_conforming = 1;
285
286#ifdef VARIANT_CANCELABLE
287 _pthread_testcancel(pthread_self(), 1);
288#endif /* VARIANT_CANCELABLE */
289
290 if (__sigwait(set, sig) == -1) {
291 err = errno;
ad3c9f2a
A
292
293#ifdef VARIANT_CANCELABLE
294 _pthread_testcancel(pthread_self(), 1);
295#endif /* VARIANT_CANCELABLE */
34e8f829
A
296
297 /*
298 * EINTR that isn't a result of pthread_cancel()
299 * is translated to 0.
300 */
301 if (err == EINTR) {
302 err = 0;
303 }
224c7076
A
304 }
305 return(err);
306#else /* __DARWIN_UNIX03 */
34e8f829
A
307 if (__sigwait(set, sig) == -1) {
308 /*
309 * EINTR that isn't a result of pthread_cancel()
310 * is translated to 0.
311 */
312 if (errno != EINTR) {
313 return -1;
314 }
315 }
224c7076 316
34e8f829 317 return 0;
224c7076
A
318#endif /* __DARWIN_UNIX03 */
319}