15e53a4f9SPedro F. Giffuni /*- 25e53a4f9SPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 35e53a4f9SPedro F. Giffuni * 4a091d823SDavid Xu * Copyright (c) 2005, David Xu <davidxu@freebsd.org> 5a091d823SDavid Xu * All rights reserved. 6a091d823SDavid Xu * 7a091d823SDavid Xu * Redistribution and use in source and binary forms, with or without 8a091d823SDavid Xu * modification, are permitted provided that the following conditions 9a091d823SDavid Xu * are met: 10a091d823SDavid Xu * 1. Redistributions of source code must retain the above copyright 11a091d823SDavid Xu * notice unmodified, this list of conditions, and the following 12a091d823SDavid Xu * disclaimer. 13a091d823SDavid Xu * 2. Redistributions in binary form must reproduce the above copyright 14a091d823SDavid Xu * notice, this list of conditions and the following disclaimer in the 15a091d823SDavid Xu * documentation and/or other materials provided with the distribution. 16a091d823SDavid Xu * 17a091d823SDavid Xu * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18a091d823SDavid Xu * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19a091d823SDavid Xu * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20a091d823SDavid Xu * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21a091d823SDavid Xu * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22a091d823SDavid Xu * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23a091d823SDavid Xu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24a091d823SDavid Xu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25a091d823SDavid Xu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26a091d823SDavid Xu * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27bb535300SJeff Roberson */ 28bb535300SJeff Roberson 2932793011SKonstantin Belousov #include <sys/cdefs.h> 3032793011SKonstantin Belousov __FBSDID("$FreeBSD$"); 3132793011SKonstantin Belousov 3237a6356bSDavid Xu #include "namespace.h" 33a091d823SDavid Xu #include <pthread.h> 3437a6356bSDavid Xu #include "un-namespace.h" 35a091d823SDavid Xu 36a091d823SDavid Xu #include "thr_private.h" 376da7f493SMike Makonnen 380ab1bfc7SKonstantin Belousov __weak_reference(_thr_cancel, pthread_cancel); 390ab1bfc7SKonstantin Belousov __weak_reference(_thr_cancel, _pthread_cancel); 400ab1bfc7SKonstantin Belousov __weak_reference(_thr_setcancelstate, pthread_setcancelstate); 410ab1bfc7SKonstantin Belousov __weak_reference(_thr_setcancelstate, _pthread_setcancelstate); 420ab1bfc7SKonstantin Belousov __weak_reference(_thr_setcanceltype, pthread_setcanceltype); 430ab1bfc7SKonstantin Belousov __weak_reference(_thr_setcanceltype, _pthread_setcanceltype); 440ab1bfc7SKonstantin Belousov __weak_reference(_Tthr_testcancel, pthread_testcancel); 450ab1bfc7SKonstantin Belousov __weak_reference(_Tthr_testcancel, _pthread_testcancel); 4665174f68SKonstantin Belousov __weak_reference(_Tthr_cancel_enter, _pthread_cancel_enter); 4765174f68SKonstantin Belousov __weak_reference(_Tthr_cancel_leave, _pthread_cancel_leave); 48bb535300SJeff Roberson 49f08e1bf6SDavid Xu static inline void 50f08e1bf6SDavid Xu testcancel(struct pthread *curthread) 51f08e1bf6SDavid Xu { 52f08e1bf6SDavid Xu if (__predict_false(SHOULD_CANCEL(curthread) && 53635f917aSDavid Xu !THR_IN_CRITICAL(curthread))) 54f08e1bf6SDavid Xu _pthread_exit(PTHREAD_CANCELED); 55f08e1bf6SDavid Xu } 56f08e1bf6SDavid Xu 57f08e1bf6SDavid Xu void 58f08e1bf6SDavid Xu _thr_testcancel(struct pthread *curthread) 59f08e1bf6SDavid Xu { 60f08e1bf6SDavid Xu testcancel(curthread); 61f08e1bf6SDavid Xu } 62f08e1bf6SDavid Xu 63bb535300SJeff Roberson int 640ab1bfc7SKonstantin Belousov _thr_cancel(pthread_t pthread) 65bb535300SJeff Roberson { 66a091d823SDavid Xu struct pthread *curthread = _get_curthread(); 67a091d823SDavid Xu int ret; 68bb535300SJeff Roberson 69d39d6512SMike Makonnen /* 70f08e1bf6SDavid Xu * POSIX says _pthread_cancel should be async cancellation safe. 71a9b764e2SDavid Xu * _thr_find_thread and THR_THREAD_UNLOCK will enter and leave critical 72f08e1bf6SDavid Xu * region automatically. 73d39d6512SMike Makonnen */ 74*751fae1eSKonstantin Belousov if ((ret = _thr_find_thread(curthread, pthread, 1)) == 0) { 75f08e1bf6SDavid Xu if (!pthread->cancel_pending) { 76f08e1bf6SDavid Xu pthread->cancel_pending = 1; 7717dce7e1SDavid Xu if (pthread->state != PS_DEAD) 78a091d823SDavid Xu _thr_send_sig(pthread, SIGCANCEL); 796da7f493SMike Makonnen } 80f08e1bf6SDavid Xu THR_THREAD_UNLOCK(curthread, pthread); 81f08e1bf6SDavid Xu } 82f08e1bf6SDavid Xu return (ret); 83a091d823SDavid Xu } 84a091d823SDavid Xu 85bb535300SJeff Roberson int 860ab1bfc7SKonstantin Belousov _thr_setcancelstate(int state, int *oldstate) 87bb535300SJeff Roberson { 88a091d823SDavid Xu struct pthread *curthread = _get_curthread(); 89f08e1bf6SDavid Xu int oldval; 90bb535300SJeff Roberson 91f08e1bf6SDavid Xu oldval = curthread->cancel_enable; 92bb535300SJeff Roberson switch (state) { 93bb535300SJeff Roberson case PTHREAD_CANCEL_DISABLE: 94f08e1bf6SDavid Xu curthread->cancel_enable = 0; 95a091d823SDavid Xu break; 96a091d823SDavid Xu case PTHREAD_CANCEL_ENABLE: 97f08e1bf6SDavid Xu curthread->cancel_enable = 1; 98a0b9cbc8SKonstantin Belousov if (curthread->cancel_async) 9902c3c858SDavid Xu testcancel(curthread); 100bb535300SJeff Roberson break; 101bb535300SJeff Roberson default: 102f08e1bf6SDavid Xu return (EINVAL); 1034cd18a22SMike Makonnen } 104bb535300SJeff Roberson 105f08e1bf6SDavid Xu if (oldstate) { 106f08e1bf6SDavid Xu *oldstate = oldval ? PTHREAD_CANCEL_ENABLE : 107f08e1bf6SDavid Xu PTHREAD_CANCEL_DISABLE; 108f08e1bf6SDavid Xu } 109f08e1bf6SDavid Xu return (0); 110a091d823SDavid Xu } 111a091d823SDavid Xu 1124cd18a22SMike Makonnen int 1130ab1bfc7SKonstantin Belousov _thr_setcanceltype(int type, int *oldtype) 1144cd18a22SMike Makonnen { 115a091d823SDavid Xu struct pthread *curthread = _get_curthread(); 116f08e1bf6SDavid Xu int oldval; 1174cd18a22SMike Makonnen 118f08e1bf6SDavid Xu oldval = curthread->cancel_async; 1194cd18a22SMike Makonnen switch (type) { 1204cd18a22SMike Makonnen case PTHREAD_CANCEL_ASYNCHRONOUS: 121f08e1bf6SDavid Xu curthread->cancel_async = 1; 122a091d823SDavid Xu testcancel(curthread); 1234cd18a22SMike Makonnen break; 1244cd18a22SMike Makonnen case PTHREAD_CANCEL_DEFERRED: 125f08e1bf6SDavid Xu curthread->cancel_async = 0; 1264cd18a22SMike Makonnen break; 1274cd18a22SMike Makonnen default: 128f08e1bf6SDavid Xu return (EINVAL); 1294cd18a22SMike Makonnen } 130a091d823SDavid Xu 131f08e1bf6SDavid Xu if (oldtype) { 132f08e1bf6SDavid Xu *oldtype = oldval ? PTHREAD_CANCEL_ASYNCHRONOUS : 133f08e1bf6SDavid Xu PTHREAD_CANCEL_DEFERRED; 134f08e1bf6SDavid Xu } 135f08e1bf6SDavid Xu return (0); 136bb535300SJeff Roberson } 137bb535300SJeff Roberson 138bb535300SJeff Roberson void 1390ab1bfc7SKonstantin Belousov _Tthr_testcancel(void) 140bb535300SJeff Roberson { 141dc356606SJohn Baldwin struct pthread *curthread; 1426da7f493SMike Makonnen 143dc356606SJohn Baldwin _thr_check_init(); 144dc356606SJohn Baldwin curthread = _get_curthread(); 14502c3c858SDavid Xu testcancel(curthread); 1464cd18a22SMike Makonnen } 147bb535300SJeff Roberson 148bb535300SJeff Roberson void 149f08e1bf6SDavid Xu _thr_cancel_enter(struct pthread *curthread) 150bb535300SJeff Roberson { 15102c3c858SDavid Xu curthread->cancel_point = 1; 152f08e1bf6SDavid Xu testcancel(curthread); 153f08e1bf6SDavid Xu } 154635f917aSDavid Xu 155635f917aSDavid Xu void 15602c3c858SDavid Xu _thr_cancel_enter2(struct pthread *curthread, int maycancel) 157635f917aSDavid Xu { 15802c3c858SDavid Xu curthread->cancel_point = 1; 159635f917aSDavid Xu if (__predict_false(SHOULD_CANCEL(curthread) && 160635f917aSDavid Xu !THR_IN_CRITICAL(curthread))) { 161635f917aSDavid Xu if (!maycancel) 162635f917aSDavid Xu thr_wake(curthread->tid); 163635f917aSDavid Xu else 164635f917aSDavid Xu _pthread_exit(PTHREAD_CANCELED); 165635f917aSDavid Xu } 166f08e1bf6SDavid Xu } 167f08e1bf6SDavid Xu 168f08e1bf6SDavid Xu void 16902c3c858SDavid Xu _thr_cancel_leave(struct pthread *curthread, int maycancel) 170f08e1bf6SDavid Xu { 17193ea4a71SDavid Xu curthread->cancel_point = 0; 172e5c66a0dSDavid Xu if (__predict_false(SHOULD_CANCEL(curthread) && 173e5c66a0dSDavid Xu !THR_IN_CRITICAL(curthread) && maycancel)) 174e5c66a0dSDavid Xu _pthread_exit(PTHREAD_CANCELED); 1753ce4e91dSDavid Xu } 176f4213b90SDavid Xu 177f4213b90SDavid Xu void 17865174f68SKonstantin Belousov _Tthr_cancel_enter(int maycancel) 179f4213b90SDavid Xu { 180f4213b90SDavid Xu _thr_cancel_enter2(_get_curthread(), maycancel); 181f4213b90SDavid Xu } 182f4213b90SDavid Xu 183f4213b90SDavid Xu void 18465174f68SKonstantin Belousov _Tthr_cancel_leave(int maycancel) 185f4213b90SDavid Xu { 186f4213b90SDavid Xu _thr_cancel_leave(_get_curthread(), maycancel); 187f4213b90SDavid Xu } 188