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