]> git.saurik.com Git - apple/libpthread.git/blob - src/pthread_cancelable.c
f2096722c632d01439d6e0f96481801d21de60b4
[apple/libpthread.git] / src / pthread_cancelable.c
1 /*
2 * Copyright (c) 2000-2013 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 "resolver.h"
53 #include "internal.h"
54
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 <sys/ulock.h>
64 #include <machine/vmparam.h>
65 #include <mach/vm_statistics.h>
66
67 extern int _pthread_cond_wait(pthread_cond_t *cond,
68 pthread_mutex_t *mutex,
69 const struct timespec *abstime,
70 int isRelative,
71 int isconforming);
72 extern int __sigwait(const sigset_t *set, int *sig);
73 extern int __pthread_sigmask(int, const sigset_t *, sigset_t *);
74 extern int __pthread_markcancel(mach_port_t);
75 extern int __pthread_canceled(int);
76 extern int __semwait_signal_nocancel(int, int, int, int, __int64_t, __int32_t);
77
78
79 PTHREAD_NOEXPORT
80 int _pthread_join(pthread_t thread, void **value_ptr, int conforming);
81
82 static inline int
83 _pthread_conformance(void)
84 {
85 #if __DARWIN_UNIX03
86 if (__unix_conforming == 0)
87 __unix_conforming = 1;
88 #ifdef VARIANT_CANCELABLE
89 return PTHREAD_CONFORM_UNIX03_CANCELABLE;
90 #else /* !VARIANT_CANCELABLE */
91 return PTHREAD_CONFORM_UNIX03_NOCANCEL;
92 #endif
93 #else /* __DARWIN_UNIX03 */
94 return PTHREAD_CONFORM_DARWIN_LEGACY;
95 #endif /* __DARWIN_UNIX03 */
96 }
97
98 #ifndef VARIANT_CANCELABLE
99
100 PTHREAD_ALWAYS_INLINE
101 static inline int
102 _pthread_update_cancel_state(pthread_t thread, int mask, int state)
103 {
104 int oldstate, newstate;
105 os_atomic_rmw_loop2o(thread, cancel_state, oldstate, newstate, seq_cst, {
106 newstate = oldstate;
107 newstate &= ~mask;
108 newstate |= state;
109 });
110 return oldstate;
111 }
112
113 /*
114 * Cancel a thread
115 */
116 PTHREAD_NOEXPORT_VARIANT
117 int
118 pthread_cancel(pthread_t thread)
119 {
120 #if __DARWIN_UNIX03
121 if (__unix_conforming == 0)
122 __unix_conforming = 1;
123 #endif /* __DARWIN_UNIX03 */
124
125 if (!_pthread_is_valid(thread, NULL)) {
126 return(ESRCH);
127 }
128
129 /* if the thread is a workqueue thread, then return error */
130 if (thread->wqthread != 0) {
131 return(ENOTSUP);
132 }
133 #if __DARWIN_UNIX03
134 int state = os_atomic_or2o(thread, cancel_state, _PTHREAD_CANCEL_PENDING, relaxed);
135 if (state & PTHREAD_CANCEL_ENABLE) {
136 mach_port_t kport = _pthread_kernel_thread(thread);
137 if (kport) __pthread_markcancel(kport);
138 }
139 #else /* __DARWIN_UNIX03 */
140 thread->cancel_state |= _PTHREAD_CANCEL_PENDING;
141 #endif /* __DARWIN_UNIX03 */
142 return (0);
143 }
144
145
146 void
147 pthread_testcancel(void)
148 {
149 _pthread_testcancel(_pthread_conformance());
150 }
151
152 #ifndef BUILDING_VARIANT /* [ */
153
154 PTHREAD_NOEXPORT_VARIANT
155 void
156 _pthread_exit_if_canceled(int error)
157 {
158 if (((error & 0xff) == EINTR) && __unix_conforming && (__pthread_canceled(0) == 0)) {
159 pthread_t self = pthread_self();
160
161 _pthread_validate_signature(self);
162 self->cancel_error = error;
163 self->canceled = true;
164 pthread_exit(PTHREAD_CANCELED);
165 }
166 }
167
168
169 static inline bool
170 _pthread_is_canceled(pthread_t thread)
171 {
172 const int flags = (PTHREAD_CANCEL_ENABLE|_PTHREAD_CANCEL_PENDING);
173 int state = os_atomic_load2o(thread, cancel_state, seq_cst);
174 return (state & flags) == flags;
175 }
176
177 PTHREAD_NOEXPORT_VARIANT
178 void
179 _pthread_testcancel(int isconforming)
180 {
181 pthread_t self = pthread_self();
182 if (_pthread_is_canceled(self)) {
183 _pthread_validate_signature(self);
184 // 4597450: begin
185 self->canceled = (isconforming != PTHREAD_CONFORM_DARWIN_LEGACY);
186 // 4597450: end
187 pthread_exit(isconforming ? PTHREAD_CANCELED : NULL);
188 }
189 }
190
191 PTHREAD_NOEXPORT
192 void
193 _pthread_markcancel_if_canceled(pthread_t thread, mach_port_t kport)
194 {
195 const int flags = (PTHREAD_CANCEL_ENABLE|_PTHREAD_CANCEL_PENDING);
196 int state = os_atomic_load2o(thread, cancel_state, relaxed);
197 if ((state & flags) == flags && __unix_conforming) {
198 __pthread_markcancel(kport);
199 }
200 }
201
202 /* When a thread exits set the cancellation state to DISABLE and DEFERRED */
203 PTHREAD_NOEXPORT
204 void
205 _pthread_setcancelstate_exit(pthread_t thread, void *value_ptr)
206 {
207 _pthread_update_cancel_state(thread,
208 _PTHREAD_CANCEL_STATE_MASK | _PTHREAD_CANCEL_TYPE_MASK,
209 PTHREAD_CANCEL_DISABLE | PTHREAD_CANCEL_DEFERRED);
210 }
211
212 #endif /* !BUILDING_VARIANT ] */
213
214 /*
215 * Query/update the cancelability 'state' of a thread
216 */
217 PTHREAD_ALWAYS_INLINE
218 static inline int
219 _pthread_setcancelstate_internal(int state, int *oldstateptr, int conforming)
220 {
221 pthread_t self = pthread_self();
222
223 _pthread_validate_signature(self);
224
225 switch (state) {
226 case PTHREAD_CANCEL_ENABLE:
227 if (conforming) {
228 __pthread_canceled(1);
229 }
230 break;
231 case PTHREAD_CANCEL_DISABLE:
232 if (conforming) {
233 __pthread_canceled(2);
234 }
235 break;
236 default:
237 return EINVAL;
238 }
239
240 int oldstate = _pthread_update_cancel_state(self, _PTHREAD_CANCEL_STATE_MASK, state);
241 if (oldstateptr) {
242 *oldstateptr = oldstate & _PTHREAD_CANCEL_STATE_MASK;
243 }
244 if (!conforming) {
245 /* See if we need to 'die' now... */
246 _pthread_testcancel(PTHREAD_CONFORM_DARWIN_LEGACY);
247 }
248 return 0;
249 }
250
251 PTHREAD_NOEXPORT_VARIANT
252 int
253 pthread_setcancelstate(int state, int *oldstate)
254 {
255 #if __DARWIN_UNIX03
256 if (__unix_conforming == 0) {
257 __unix_conforming = 1;
258 }
259 return (_pthread_setcancelstate_internal(state, oldstate, 1));
260 #else /* __DARWIN_UNIX03 */
261 return (_pthread_setcancelstate_internal(state, oldstate, 0));
262 #endif /* __DARWIN_UNIX03 */
263 }
264
265 /*
266 * Query/update the cancelability 'type' of a thread
267 */
268 PTHREAD_NOEXPORT_VARIANT
269 int
270 pthread_setcanceltype(int type, int *oldtype)
271 {
272 pthread_t self;
273
274 #if __DARWIN_UNIX03
275 if (__unix_conforming == 0)
276 __unix_conforming = 1;
277 #endif /* __DARWIN_UNIX03 */
278
279 if ((type != PTHREAD_CANCEL_DEFERRED) &&
280 (type != PTHREAD_CANCEL_ASYNCHRONOUS))
281 return EINVAL;
282 self = pthread_self();
283 _pthread_validate_signature(self);
284 int oldstate = _pthread_update_cancel_state(self, _PTHREAD_CANCEL_TYPE_MASK, type);
285 if (oldtype) {
286 *oldtype = oldstate & _PTHREAD_CANCEL_TYPE_MASK;
287 }
288 #if !__DARWIN_UNIX03
289 /* See if we need to 'die' now... */
290 _pthread_testcancel(PTHREAD_CONFORM_DARWIN_LEGACY);
291 #endif /* __DARWIN_UNIX03 */
292 return (0);
293 }
294
295
296 int
297 pthread_sigmask(int how, const sigset_t * set, sigset_t * oset)
298 {
299 #if __DARWIN_UNIX03
300 int err = 0;
301
302 if (__pthread_sigmask(how, set, oset) == -1) {
303 err = errno;
304 }
305 return(err);
306 #else /* __DARWIN_UNIX03 */
307 return(__pthread_sigmask(how, set, oset));
308 #endif /* __DARWIN_UNIX03 */
309 }
310
311 #ifndef BUILDING_VARIANT /* [ */
312
313 typedef struct pthread_join_context_s {
314 pthread_t waiter;
315 void **value_ptr;
316 mach_port_t kport;
317 semaphore_t custom_stack_sema;
318 bool detached;
319 } pthread_join_context_s, *pthread_join_context_t;
320
321 static inline void *
322 _pthread_get_exit_value(pthread_t thread)
323 {
324 if (__unix_conforming && _pthread_is_canceled(thread)) {
325 return PTHREAD_CANCELED;
326 }
327 return thread->tl_exit_value;
328 }
329
330 // called with _pthread_list_lock held
331 PTHREAD_NOEXPORT
332 semaphore_t
333 _pthread_joiner_prepost_wake(pthread_t thread)
334 {
335 pthread_join_context_t ctx = thread->tl_join_ctx;
336 semaphore_t sema = MACH_PORT_NULL;
337
338 if (thread->tl_joinable) {
339 sema = ctx->custom_stack_sema;
340 thread->tl_joinable = false;
341 } else {
342 ctx->detached = true;
343 thread->tl_join_ctx = NULL;
344 }
345 if (ctx->value_ptr) *ctx->value_ptr = _pthread_get_exit_value(thread);
346 return sema;
347 }
348
349 static inline bool
350 _pthread_joiner_abort_wait(pthread_t thread, pthread_join_context_t ctx)
351 {
352 bool aborted = false;
353
354 _PTHREAD_LOCK(_pthread_list_lock);
355 if (!ctx->detached && thread->tl_exit_gate != MACH_PORT_DEAD) {
356 /*
357 * _pthread_joiner_prepost_wake() didn't happen
358 * allow another thread to join
359 */
360 PTHREAD_DEBUG_ASSERT(thread->tl_join_ctx == ctx);
361 thread->tl_join_ctx = NULL;
362 thread->tl_exit_gate = MACH_PORT_NULL;
363 aborted = true;
364 }
365 _PTHREAD_UNLOCK(_pthread_list_lock);
366 return aborted;
367 }
368
369 static int
370 _pthread_joiner_wait(pthread_t thread, pthread_join_context_t ctx, int conforming)
371 {
372 uint32_t *exit_gate = &thread->tl_exit_gate;
373 int ulock_op = UL_UNFAIR_LOCK | ULF_NO_ERRNO;
374
375 if (conforming == PTHREAD_CONFORM_UNIX03_CANCELABLE) {
376 ulock_op |= ULF_WAIT_CANCEL_POINT;
377 }
378
379 for (;;) {
380 uint32_t cur = os_atomic_load(exit_gate, acquire);
381 if (cur == MACH_PORT_DEAD) {
382 break;
383 }
384 if (os_unlikely(cur != ctx->kport)) {
385 PTHREAD_CLIENT_CRASH(cur, "pthread_join() state corruption");
386 }
387 int ret = __ulock_wait(ulock_op, exit_gate, ctx->kport, 0);
388 switch (-ret) {
389 case 0:
390 case EFAULT:
391 break;
392 case EINTR:
393 /*
394 * POSIX says:
395 *
396 * As specified, either the pthread_join() call is canceled, or it
397 * succeeds, but not both. The difference is obvious to the
398 * application, since either a cancellation handler is run or
399 * pthread_join() returns.
400 *
401 * When __ulock_wait() returns EINTR, we check if we have been
402 * canceled, and if we have, we try to abort the wait.
403 *
404 * If we can't, it means the other thread finished the join while we
405 * were being canceled and commited the waiter to return from
406 * pthread_join(). Returning from the join then takes precedence
407 * over the cancelation which will be acted upon at the next
408 * cancelation point.
409 */
410 if (conforming == PTHREAD_CONFORM_UNIX03_CANCELABLE &&
411 _pthread_is_canceled(ctx->waiter)) {
412 if (_pthread_joiner_abort_wait(thread, ctx)) {
413 ctx->waiter->canceled = true;
414 pthread_exit(PTHREAD_CANCELED);
415 }
416 }
417 break;
418 }
419 }
420
421 bool cleanup = false;
422
423 _PTHREAD_LOCK(_pthread_list_lock);
424 // If pthread_detach() was called, we can't safely dereference the thread,
425 // else, decide who gets to deallocate the thread (see _pthread_terminate).
426 if (!ctx->detached) {
427 PTHREAD_DEBUG_ASSERT(thread->tl_join_ctx == ctx);
428 thread->tl_join_ctx = NULL;
429 cleanup = thread->tl_joiner_cleans_up;
430 }
431 _PTHREAD_UNLOCK(_pthread_list_lock);
432
433 if (cleanup) {
434 _pthread_deallocate(thread, false);
435 }
436 return 0;
437 }
438
439 PTHREAD_NOEXPORT PTHREAD_NOINLINE
440 int
441 _pthread_join(pthread_t thread, void **value_ptr, int conforming)
442 {
443 pthread_t self = pthread_self();
444 pthread_join_context_s ctx = {
445 .waiter = self,
446 .value_ptr = value_ptr,
447 .kport = MACH_PORT_NULL,
448 .custom_stack_sema = MACH_PORT_NULL,
449 };
450 int res = 0;
451 kern_return_t kr;
452
453 if (!_pthread_validate_thread_and_list_lock(thread)) {
454 return ESRCH;
455 }
456 _pthread_validate_signature(self);
457
458 if (!thread->tl_joinable || (thread->tl_join_ctx != NULL)) {
459 res = EINVAL;
460 } else if (thread == self ||
461 (self->tl_join_ctx && self->tl_join_ctx->waiter == thread)) {
462 res = EDEADLK;
463 } else if (thread->tl_exit_gate == MACH_PORT_DEAD) {
464 TAILQ_REMOVE(&__pthread_head, thread, tl_plist);
465 PTHREAD_DEBUG_ASSERT(thread->tl_joiner_cleans_up);
466 thread->tl_joinable = false;
467 if (value_ptr) *value_ptr = _pthread_get_exit_value(thread);
468 } else {
469 ctx.kport = _pthread_kernel_thread(thread);
470 thread->tl_exit_gate = ctx.kport;
471 thread->tl_join_ctx = &ctx;
472 if (thread->tl_has_custom_stack) {
473 ctx.custom_stack_sema = (semaphore_t)os_get_cached_semaphore();
474 }
475 }
476 _PTHREAD_UNLOCK(_pthread_list_lock);
477
478 if (res == 0) {
479 if (ctx.kport == MACH_PORT_NULL) {
480 _pthread_deallocate(thread, false);
481 } else {
482 res = _pthread_joiner_wait(thread, &ctx, conforming);
483 }
484 }
485 if (res == 0 && ctx.custom_stack_sema && !ctx.detached) {
486 // threads with a custom stack need to make sure _pthread_terminate
487 // returned before the joiner is unblocked, the joiner may quickly
488 // deallocate the stack with rather dire consequences.
489 //
490 // When we reach this point we know the pthread_join has to succeed
491 // so this can't be a cancelation point.
492 do {
493 kr = __semwait_signal_nocancel(ctx.custom_stack_sema, 0, 0, 0, 0, 0);
494 } while (kr != KERN_SUCCESS);
495 }
496 if (ctx.custom_stack_sema) {
497 os_put_cached_semaphore(ctx.custom_stack_sema);
498 }
499 return res;
500 }
501
502 #endif /* !BUILDING_VARIANT ] */
503 #endif /* VARIANT_CANCELABLE */
504
505 /*
506 * Wait for a thread to terminate and obtain its exit value.
507 */
508 int
509 pthread_join(pthread_t thread, void **value_ptr)
510 {
511 int conforming = _pthread_conformance();
512 if (conforming == PTHREAD_CONFORM_UNIX03_CANCELABLE) {
513 _pthread_testcancel(conforming);
514 }
515 return _pthread_join(thread, value_ptr, conforming);
516 }
517
518 int
519 pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
520 {
521 return _pthread_cond_wait(cond, mutex, NULL, 0, _pthread_conformance());
522 }
523
524 int
525 pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
526 const struct timespec *abstime)
527 {
528 return _pthread_cond_wait(cond, mutex, abstime, 0, _pthread_conformance());
529 }
530
531 int
532 sigwait(const sigset_t * set, int * sig)
533 {
534 #if __DARWIN_UNIX03
535 int err = 0, conformance = _pthread_conformance();
536
537 if (__unix_conforming == 0)
538 __unix_conforming = 1;
539
540 if (conformance == PTHREAD_CONFORM_UNIX03_CANCELABLE) {
541 _pthread_testcancel(conformance);
542 }
543
544 if (__sigwait(set, sig) == -1) {
545 err = errno;
546
547 if (conformance == PTHREAD_CONFORM_UNIX03_CANCELABLE) {
548 _pthread_testcancel(conformance);
549 }
550
551 /*
552 * EINTR that isn't a result of pthread_cancel()
553 * is translated to 0.
554 */
555 if (err == EINTR) {
556 err = 0;
557 }
558 }
559 return(err);
560 #else /* __DARWIN_UNIX03 */
561 if (__sigwait(set, sig) == -1) {
562 /*
563 * EINTR that isn't a result of pthread_cancel()
564 * is translated to 0.
565 */
566 if (errno != EINTR) {
567 return -1;
568 }
569 }
570
571 return 0;
572 #endif /* __DARWIN_UNIX03 */
573 }
574