]> git.saurik.com Git - apple/libc.git/blame - pthreads/pthread_cancelable.c
Libc-498.tar.gz
[apple/libc.git] / pthreads / pthread_cancelable.c
CommitLineData
224c7076
A
1/*
2 * Copyright (c) 2000-2007 Apple Inc. All rights reserved.
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
78/*
79 * Wait for a thread to terminate and obtain its exit value.
80 */
81int
82pthread_join(pthread_t thread,
83 void **value_ptr)
84{
85 kern_return_t kern_res;
86 int res = 0;
87 pthread_t self = pthread_self();
88 mach_port_t ignore;
89 mach_port_t kthport;
90 int conforming = 0;
91 task_t tself = mach_task_self();
92
93#if __DARWIN_UNIX03
94 if (__unix_conforming == 0)
95 __unix_conforming = 1;
96
97#ifdef VARIANT_CANCELABLE
98 _pthread_testcancel(self, 1);
99#endif /* VARIANT_CANCELABLE */
100#endif /* __DARWIN_UNIX03 */
101
102 if ((res = _pthread_lookup_thread(thread, &kthport, 1)) != 0)
103 return(res);
104
105 if (thread->sig == _PTHREAD_SIG)
106 {
107 if (thread->newstyle == 0) {
108 semaphore_t death = new_sem_from_pool(); /* in case we need it */
109
110 LOCK(thread->lock);
111 if ((thread->detached & PTHREAD_CREATE_JOINABLE) &&
112 thread->death == SEMAPHORE_NULL)
113 {
114
115 assert(thread->joiner == NULL);
116 if (thread != self && (self == NULL || self->joiner != thread))
117 {
118 int already_exited = (thread->detached & _PTHREAD_EXITED);
119
120 thread->death = death;
121 thread->joiner = self;
122 UNLOCK(thread->lock);
123
124 if (!already_exited)
125 {
126#if __DARWIN_UNIX03
127 /* Wait for it to signal... */
128 pthread_cleanup_push(__posix_join_cleanup, (void *)thread);
129 do {
130 res = __semwait_signal(death, 0, 0, 0, 0, 0);
131 } while ((res < 0) && (errno == EINTR));
132 pthread_cleanup_pop(0);
133
134#else /* __DARWIN_UNIX03 */
135 /* Wait for it to signal... */
136 do {
137 PTHREAD_MACH_CALL(semaphore_wait(death), kern_res);
138 } while (kern_res != KERN_SUCCESS);
139#endif /* __DARWIN_UNIX03 */
140 }
141
142 LOCK(_pthread_list_lock);
143 TAILQ_REMOVE(&__pthread_head, thread, plist);
144#if WQ_TRACE
145 __kdebug_trace(0x9000010, thread, 0, 0, 16, 0);
146#endif
147 UNLOCK(_pthread_list_lock);
148 /* ... and wait for it to really be dead */
149 while ((res = _pthread_reap_thread(thread,
150 thread->kernel_thread,
151 value_ptr, __unix_conforming)) == EAGAIN)
152 {
153 sched_yield();
154 }
155
156 } else {
157 UNLOCK(thread->lock);
158 res = EDEADLK;
159 }
160 } else {
161 UNLOCK(thread->lock);
162 res = EINVAL;
163 }
164 restore_sem_to_pool(death);
165 return res;
166 } else {
167 /* new style */
168
169 semaphore_t death = SEMAPHORE_NULL; /* in case we need it */
170 semaphore_t joinsem = SEMAPHORE_NULL;
171
172 if (thread->joiner_notify == NULL)
173 death = new_sem_from_pool();
174
175 LOCK(thread->lock);
176 if ((thread->detached & PTHREAD_CREATE_JOINABLE) &&
177 (thread->joiner == NULL))
178 {
179 assert(thread->kernel_thread == kthport);
180 if (thread != self && (self == NULL || self->joiner != thread))
181 {
182 int already_exited;
183
184 if (thread->joiner_notify == NULL) {
185 if (death == SEMAPHORE_NULL)
186 abort();
187 thread->joiner_notify = death;
188 death = SEMAPHORE_NULL;
189 }
190 joinsem = thread->joiner_notify;
191 thread->joiner = self;
192 UNLOCK(thread->lock);
193
194 if (death != SEMAPHORE_NULL) {
195 restore_sem_to_pool(death);
196 death = SEMAPHORE_NULL;
197 }
198#if __DARWIN_UNIX03
199 /* Wait for it to signal... */
200 pthread_cleanup_push(__posix_join_cleanup, (void *)thread);
201 do {
202 res = __semwait_signal(joinsem, 0, 0, 0, 0, 0);
203 } while ((res < 0) && (errno == EINTR));
204 pthread_cleanup_pop(0);
205#else /* __DARWIN_UNIX03 */
206 /* Wait for it to signal... */
207 do {
208 PTHREAD_MACH_CALL(semaphore_wait(joinsem), kern_res);
209 } while (kern_res != KERN_SUCCESS);
210#endif /* __DARWIN_UNIX03 */
211
212 restore_sem_to_pool(joinsem);
213 res = _pthread_join_cleanup(thread, value_ptr, conforming);
214 } else {
215 UNLOCK(thread->lock);
216 res = EDEADLK;
217 }
218 } else {
219 UNLOCK(thread->lock);
220 res = EINVAL;
221 }
222 if (death != SEMAPHORE_NULL)
223 restore_sem_to_pool(death);
224 return res;
225 }/* end of new style */
226 }
227 return ESRCH;
228}
229
230int
231pthread_cond_wait(pthread_cond_t *cond,
232 pthread_mutex_t *mutex)
233{
234 int conforming;
235#if __DARWIN_UNIX03
236
237 if (__unix_conforming == 0)
238 __unix_conforming = 1;
239
240#ifdef VARIANT_CANCELABLE
241 conforming = 1;
242#else /* !VARIANT_CANCELABLE */
243 conforming = -1;
244#endif /* VARIANT_CANCELABLE */
245#else /* __DARWIN_UNIX03 */
246 conforming = 0;
247#endif /* __DARWIN_UNIX03 */
248 return (_pthread_cond_wait(cond, mutex, (struct timespec *)NULL, 0, conforming));
249}
250
251int
252pthread_cond_timedwait(pthread_cond_t *cond,
253 pthread_mutex_t *mutex,
254 const struct timespec *abstime)
255{
256 int conforming;
257#if __DARWIN_UNIX03
258 if (__unix_conforming == 0)
259 __unix_conforming = 1;
260
261#ifdef VARIANT_CANCELABLE
262 conforming = 1;
263#else /* !VARIANT_CANCELABLE */
264 conforming = -1;
265#endif /* VARIANT_CANCELABLE */
266#else /* __DARWIN_UNIX03 */
267 conforming = 0;
268#endif /* __DARWIN_UNIX03 */
269
270 return (_pthread_cond_wait(cond, mutex, abstime, 0, conforming));
271}
272
273int
274sigwait(const sigset_t * set, int * sig)
275{
276#if __DARWIN_UNIX03
277 int err = 0;
278
279 if (__unix_conforming == 0)
280 __unix_conforming = 1;
281
282#ifdef VARIANT_CANCELABLE
283 _pthread_testcancel(pthread_self(), 1);
284#endif /* VARIANT_CANCELABLE */
285
286 if (__sigwait(set, sig) == -1) {
287 err = errno;
288 }
289 return(err);
290#else /* __DARWIN_UNIX03 */
291 return(__sigwait(set, sig));
292
293#endif /* __DARWIN_UNIX03 */
294}