]> git.saurik.com Git - apple/libpthread.git/blame - src/pthread_cancelable.c
libpthread-454.40.3.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
c1f56ec9 67#ifndef BUILDING_VARIANT /* [ */
f1a1da6c 68
c1f56ec9 69OS_ALWAYS_INLINE
a0619f9c
A
70static inline int
71_pthread_update_cancel_state(pthread_t thread, int mask, int state)
72{
c1f56ec9
A
73 uint16_t oldstate, newstate;
74 os_atomic_rmw_loop(&thread->cancel_state, oldstate, newstate, relaxed, {
a0619f9c
A
75 newstate = oldstate;
76 newstate &= ~mask;
77 newstate |= state;
78 });
79 return oldstate;
80}
81
c1f56ec9
A
82/* When a thread exits set the cancellation state to DISABLE and DEFERRED */
83void
84_pthread_setcancelstate_exit(pthread_t thread, void *value_ptr)
85{
86 _pthread_update_cancel_state(thread,
87 _PTHREAD_CANCEL_STATE_MASK | _PTHREAD_CANCEL_TYPE_MASK,
88 PTHREAD_CANCEL_DISABLE | PTHREAD_CANCEL_DEFERRED |
89 _PTHREAD_CANCEL_EXITING);
90}
91
f1a1da6c
A
92/*
93 * Cancel a thread
94 */
a0619f9c 95PTHREAD_NOEXPORT_VARIANT
f1a1da6c
A
96int
97pthread_cancel(pthread_t thread)
98{
214d78a2 99 if (!_pthread_is_valid(thread, NULL)) {
f1a1da6c 100 return(ESRCH);
a0619f9c 101 }
f1a1da6c
A
102
103 /* if the thread is a workqueue thread, then return error */
104 if (thread->wqthread != 0) {
105 return(ENOTSUP);
106 }
c1f56ec9 107 int state = os_atomic_or(&thread->cancel_state, _PTHREAD_CANCEL_PENDING, relaxed);
a0619f9c 108 if (state & PTHREAD_CANCEL_ENABLE) {
c1f56ec9 109 mach_port_t kport = _pthread_tsd_slot(thread, MACH_THREAD_SELF);
a0619f9c
A
110 if (kport) __pthread_markcancel(kport);
111 }
f1a1da6c
A
112 return (0);
113}
114
f1a1da6c
A
115/*
116 * Query/update the cancelability 'state' of a thread
117 */
c1f56ec9
A
118PTHREAD_NOEXPORT_VARIANT
119int
120pthread_setcancelstate(int state, int *oldstateptr)
a0619f9c 121{
214d78a2 122 pthread_t self = pthread_self();
a0619f9c 123
e3ecba16
A
124 _pthread_validate_signature(self);
125
a0619f9c 126 switch (state) {
214d78a2 127 case PTHREAD_CANCEL_ENABLE:
c1f56ec9 128 __pthread_canceled(1);
214d78a2
A
129 break;
130 case PTHREAD_CANCEL_DISABLE:
c1f56ec9 131 __pthread_canceled(2);
214d78a2
A
132 break;
133 default:
134 return EINVAL;
a0619f9c
A
135 }
136
a0619f9c
A
137 int oldstate = _pthread_update_cancel_state(self, _PTHREAD_CANCEL_STATE_MASK, state);
138 if (oldstateptr) {
139 *oldstateptr = oldstate & _PTHREAD_CANCEL_STATE_MASK;
140 }
a0619f9c
A
141 return 0;
142}
143
f1a1da6c
A
144/*
145 * Query/update the cancelability 'type' of a thread
146 */
a0619f9c 147PTHREAD_NOEXPORT_VARIANT
f1a1da6c
A
148int
149pthread_setcanceltype(int type, int *oldtype)
150{
c1f56ec9 151 pthread_t self = pthread_self();
f1a1da6c 152
c1f56ec9 153 _pthread_validate_signature(self);
f1a1da6c
A
154
155 if ((type != PTHREAD_CANCEL_DEFERRED) &&
156 (type != PTHREAD_CANCEL_ASYNCHRONOUS))
157 return EINVAL;
a0619f9c
A
158 int oldstate = _pthread_update_cancel_state(self, _PTHREAD_CANCEL_TYPE_MASK, type);
159 if (oldtype) {
160 *oldtype = oldstate & _PTHREAD_CANCEL_TYPE_MASK;
161 }
f1a1da6c
A
162 return (0);
163}
164
a0619f9c 165
c1f56ec9
A
166OS_ALWAYS_INLINE
167static inline bool
168_pthread_is_canceled(pthread_t thread)
f1a1da6c 169{
c1f56ec9
A
170 const int flags = (PTHREAD_CANCEL_ENABLE|_PTHREAD_CANCEL_PENDING);
171 int state = os_atomic_load(&thread->cancel_state, seq_cst);
172 return (state & flags) == flags;
f1a1da6c
A
173}
174
c1f56ec9 175OS_ALWAYS_INLINE
214d78a2
A
176static inline void *
177_pthread_get_exit_value(pthread_t thread)
f1a1da6c 178{
c1f56ec9 179 if (os_unlikely(_pthread_is_canceled(thread))) {
214d78a2
A
180 return PTHREAD_CANCELED;
181 }
182 return thread->tl_exit_value;
183}
f1a1da6c 184
c1f56ec9
A
185void
186pthread_testcancel(void)
187{
188 pthread_t self = pthread_self();
189 if (os_unlikely(_pthread_is_canceled(self))) {
190 _pthread_validate_signature(self);
191 // 4597450: begin
192 self->canceled = true;
193 // 4597450: end
194 pthread_exit(PTHREAD_CANCELED);
195 }
196}
197
198void
199_pthread_markcancel_if_canceled(pthread_t thread, mach_port_t kport)
200{
201 if (os_unlikely(_pthread_is_canceled(thread))) {
202 __pthread_markcancel(kport);
203 }
204}
205
206void
207_pthread_exit_if_canceled(int error)
208{
209 if ((error & 0xff) == EINTR && __pthread_canceled(0) == 0) {
210 pthread_t self = pthread_self();
211
212 _pthread_validate_signature(self);
213 self->cancel_error = error;
214 self->canceled = true;
215 pthread_exit(PTHREAD_CANCELED);
216 }
217}
218
219int
220pthread_sigmask(int how, const sigset_t * set, sigset_t * oset)
221{
222 int err = 0;
223
224 if (__pthread_sigmask(how, set, oset) == -1) {
225 err = errno;
226 }
227 return(err);
228}
229
214d78a2 230// called with _pthread_list_lock held
214d78a2
A
231semaphore_t
232_pthread_joiner_prepost_wake(pthread_t thread)
233{
234 pthread_join_context_t ctx = thread->tl_join_ctx;
235 semaphore_t sema = MACH_PORT_NULL;
236
237 if (thread->tl_joinable) {
238 sema = ctx->custom_stack_sema;
239 thread->tl_joinable = false;
240 } else {
241 ctx->detached = true;
242 thread->tl_join_ctx = NULL;
243 }
244 if (ctx->value_ptr) *ctx->value_ptr = _pthread_get_exit_value(thread);
245 return sema;
246}
247
248static inline bool
249_pthread_joiner_abort_wait(pthread_t thread, pthread_join_context_t ctx)
250{
251 bool aborted = false;
252
c1f56ec9 253 _pthread_lock_lock(&_pthread_list_lock);
214d78a2
A
254 if (!ctx->detached && thread->tl_exit_gate != MACH_PORT_DEAD) {
255 /*
256 * _pthread_joiner_prepost_wake() didn't happen
257 * allow another thread to join
258 */
c6e5f90c 259 PTHREAD_DEBUG_ASSERT(thread->tl_join_ctx == ctx);
214d78a2
A
260 thread->tl_join_ctx = NULL;
261 thread->tl_exit_gate = MACH_PORT_NULL;
262 aborted = true;
263 }
c1f56ec9 264 _pthread_lock_unlock(&_pthread_list_lock);
214d78a2
A
265 return aborted;
266}
267
268static int
c1f56ec9
A
269_pthread_joiner_wait(pthread_t thread, pthread_join_context_t ctx,
270 pthread_conformance_t conforming)
214d78a2
A
271{
272 uint32_t *exit_gate = &thread->tl_exit_gate;
273 int ulock_op = UL_UNFAIR_LOCK | ULF_NO_ERRNO;
274
275 if (conforming == PTHREAD_CONFORM_UNIX03_CANCELABLE) {
276 ulock_op |= ULF_WAIT_CANCEL_POINT;
277 }
278
279 for (;;) {
280 uint32_t cur = os_atomic_load(exit_gate, acquire);
281 if (cur == MACH_PORT_DEAD) {
282 break;
283 }
284 if (os_unlikely(cur != ctx->kport)) {
285 PTHREAD_CLIENT_CRASH(cur, "pthread_join() state corruption");
286 }
287 int ret = __ulock_wait(ulock_op, exit_gate, ctx->kport, 0);
288 switch (-ret) {
289 case 0:
290 case EFAULT:
291 break;
292 case EINTR:
293 /*
294 * POSIX says:
295 *
296 * As specified, either the pthread_join() call is canceled, or it
297 * succeeds, but not both. The difference is obvious to the
298 * application, since either a cancellation handler is run or
299 * pthread_join() returns.
300 *
301 * When __ulock_wait() returns EINTR, we check if we have been
302 * canceled, and if we have, we try to abort the wait.
303 *
304 * If we can't, it means the other thread finished the join while we
305 * were being canceled and commited the waiter to return from
306 * pthread_join(). Returning from the join then takes precedence
307 * over the cancelation which will be acted upon at the next
308 * cancelation point.
309 */
c1f56ec9
A
310 if (os_unlikely(conforming == PTHREAD_CONFORM_UNIX03_CANCELABLE &&
311 _pthread_is_canceled(ctx->waiter))) {
214d78a2
A
312 if (_pthread_joiner_abort_wait(thread, ctx)) {
313 ctx->waiter->canceled = true;
314 pthread_exit(PTHREAD_CANCELED);
315 }
316 }
317 break;
318 }
319 }
320
321 bool cleanup = false;
322
c1f56ec9 323 _pthread_lock_lock(&_pthread_list_lock);
214d78a2
A
324 // If pthread_detach() was called, we can't safely dereference the thread,
325 // else, decide who gets to deallocate the thread (see _pthread_terminate).
326 if (!ctx->detached) {
c6e5f90c 327 PTHREAD_DEBUG_ASSERT(thread->tl_join_ctx == ctx);
214d78a2
A
328 thread->tl_join_ctx = NULL;
329 cleanup = thread->tl_joiner_cleans_up;
330 }
c1f56ec9 331 _pthread_lock_unlock(&_pthread_list_lock);
214d78a2
A
332
333 if (cleanup) {
334 _pthread_deallocate(thread, false);
335 }
336 return 0;
f1a1da6c
A
337}
338
c1f56ec9 339OS_NOINLINE
a0619f9c 340int
c1f56ec9 341_pthread_join(pthread_t thread, void **value_ptr, pthread_conformance_t conforming)
f1a1da6c 342{
f1a1da6c 343 pthread_t self = pthread_self();
214d78a2
A
344 pthread_join_context_s ctx = {
345 .waiter = self,
346 .value_ptr = value_ptr,
347 .kport = MACH_PORT_NULL,
348 .custom_stack_sema = MACH_PORT_NULL,
349 };
350 int res = 0;
351 kern_return_t kr;
f1a1da6c 352
214d78a2
A
353 if (!_pthread_validate_thread_and_list_lock(thread)) {
354 return ESRCH;
a0619f9c 355 }
c1f56ec9 356
e3ecba16 357 _pthread_validate_signature(self);
f1a1da6c 358
214d78a2 359 if (!thread->tl_joinable || (thread->tl_join_ctx != NULL)) {
a0619f9c 360 res = EINVAL;
214d78a2
A
361 } else if (thread == self ||
362 (self->tl_join_ctx && self->tl_join_ctx->waiter == thread)) {
a0619f9c 363 res = EDEADLK;
214d78a2
A
364 } else if (thread->tl_exit_gate == MACH_PORT_DEAD) {
365 TAILQ_REMOVE(&__pthread_head, thread, tl_plist);
c6e5f90c 366 PTHREAD_DEBUG_ASSERT(thread->tl_joiner_cleans_up);
214d78a2
A
367 thread->tl_joinable = false;
368 if (value_ptr) *value_ptr = _pthread_get_exit_value(thread);
369 } else {
c1f56ec9 370 ctx.kport = _pthread_tsd_slot(thread, MACH_THREAD_SELF);
214d78a2
A
371 thread->tl_exit_gate = ctx.kport;
372 thread->tl_join_ctx = &ctx;
373 if (thread->tl_has_custom_stack) {
374 ctx.custom_stack_sema = (semaphore_t)os_get_cached_semaphore();
375 }
a0619f9c 376 }
c1f56ec9 377 _pthread_lock_unlock(&_pthread_list_lock);
a0619f9c 378
214d78a2
A
379 if (res == 0) {
380 if (ctx.kport == MACH_PORT_NULL) {
381 _pthread_deallocate(thread, false);
382 } else {
383 res = _pthread_joiner_wait(thread, &ctx, conforming);
384 }
a0619f9c 385 }
214d78a2
A
386 if (res == 0 && ctx.custom_stack_sema && !ctx.detached) {
387 // threads with a custom stack need to make sure _pthread_terminate
388 // returned before the joiner is unblocked, the joiner may quickly
389 // deallocate the stack with rather dire consequences.
390 //
391 // When we reach this point we know the pthread_join has to succeed
392 // so this can't be a cancelation point.
a0619f9c 393 do {
214d78a2
A
394 kr = __semwait_signal_nocancel(ctx.custom_stack_sema, 0, 0, 0, 0, 0);
395 } while (kr != KERN_SUCCESS);
a0619f9c 396 }
214d78a2
A
397 if (ctx.custom_stack_sema) {
398 os_put_cached_semaphore(ctx.custom_stack_sema);
a0619f9c
A
399 }
400 return res;
401}
f1a1da6c 402
a0619f9c 403#endif /* !BUILDING_VARIANT ] */
a0619f9c 404
c1f56ec9
A
405static inline pthread_conformance_t
406_pthread_conformance(void)
407{
408#ifdef VARIANT_CANCELABLE
409 return PTHREAD_CONFORM_UNIX03_CANCELABLE;
410#else /* !VARIANT_CANCELABLE */
411 return PTHREAD_CONFORM_UNIX03_NOCANCEL;
412#endif
413}
414
415static inline void
416_pthread_testcancel_if_cancelable_variant(void)
417{
418#ifdef VARIANT_CANCELABLE
419 pthread_testcancel();
420#endif
421}
422
a0619f9c
A
423int
424pthread_join(pthread_t thread, void **value_ptr)
425{
c1f56ec9
A
426 _pthread_testcancel_if_cancelable_variant();
427 return _pthread_join(thread, value_ptr, _pthread_conformance());
f1a1da6c
A
428}
429
a0619f9c 430int
214d78a2 431pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
f1a1da6c 432{
214d78a2 433 return _pthread_cond_wait(cond, mutex, NULL, 0, _pthread_conformance());
f1a1da6c
A
434}
435
a0619f9c 436int
214d78a2
A
437pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
438 const struct timespec *abstime)
f1a1da6c 439{
214d78a2 440 return _pthread_cond_wait(cond, mutex, abstime, 0, _pthread_conformance());
f1a1da6c
A
441}
442
443int
444sigwait(const sigset_t * set, int * sig)
445{
c1f56ec9 446 int err = 0;
f1a1da6c 447
c1f56ec9 448 _pthread_testcancel_if_cancelable_variant();
f1a1da6c
A
449
450 if (__sigwait(set, sig) == -1) {
451 err = errno;
452
c1f56ec9 453 _pthread_testcancel_if_cancelable_variant();
a0619f9c
A
454
455 /*
f1a1da6c
A
456 * EINTR that isn't a result of pthread_cancel()
457 * is translated to 0.
458 */
459 if (err == EINTR) {
460 err = 0;
461 }
462 }
463 return(err);
f1a1da6c 464}
a0619f9c 465