]> git.saurik.com Git - apple/libc.git/blob - pthreads/pthread_cancelable.c
Libc-498.1.1.tar.gz
[apple/libc.git] / pthreads / pthread_cancelable.c
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
66 extern int __unix_conforming;
67 extern void __posix_join_cleanup(void *arg);
68 extern pthread_lock_t _pthread_list_lock;
69 extern void _pthread_testcancel(pthread_t thread, int isconforming);
70 extern int _pthread_reap_thread(pthread_t th, mach_port_t kernel_thread, void **value_ptr, int conforming);
71 extern int _pthread_cond_wait(pthread_cond_t *cond,
72 pthread_mutex_t *mutex,
73 const struct timespec *abstime,
74 int isRelative,
75 int isconforming);
76 extern int __sigwait(const sigset_t *set, int *sig);
77
78 /*
79 * Wait for a thread to terminate and obtain its exit value.
80 */
81 int
82 pthread_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
230 int
231 pthread_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
251 int
252 pthread_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
273 int
274 sigwait(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 }