15e53a4f9SPedro F. Giffuni /*- 24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 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 2937a6356bSDavid Xu #include "namespace.h" 30a091d823SDavid Xu #include <pthread.h> 3137a6356bSDavid Xu #include "un-namespace.h" 32a091d823SDavid Xu 33a091d823SDavid Xu #include "thr_private.h" 346da7f493SMike Makonnen 350ab1bfc7SKonstantin Belousov __weak_reference(_thr_cancel, pthread_cancel); 360ab1bfc7SKonstantin Belousov __weak_reference(_thr_cancel, _pthread_cancel); 370ab1bfc7SKonstantin Belousov __weak_reference(_thr_setcancelstate, pthread_setcancelstate); 380ab1bfc7SKonstantin Belousov __weak_reference(_thr_setcancelstate, _pthread_setcancelstate); 390ab1bfc7SKonstantin Belousov __weak_reference(_thr_setcanceltype, pthread_setcanceltype); 400ab1bfc7SKonstantin Belousov __weak_reference(_thr_setcanceltype, _pthread_setcanceltype); 410ab1bfc7SKonstantin Belousov __weak_reference(_Tthr_testcancel, pthread_testcancel); 420ab1bfc7SKonstantin Belousov __weak_reference(_Tthr_testcancel, _pthread_testcancel); 4365174f68SKonstantin Belousov __weak_reference(_Tthr_cancel_enter, _pthread_cancel_enter); 4465174f68SKonstantin Belousov __weak_reference(_Tthr_cancel_leave, _pthread_cancel_leave); 45bb535300SJeff Roberson 46f08e1bf6SDavid Xu static inline void 47f08e1bf6SDavid Xu testcancel(struct pthread *curthread) 48f08e1bf6SDavid Xu { 49f08e1bf6SDavid Xu if (__predict_false(SHOULD_CANCEL(curthread) && 50635f917aSDavid Xu !THR_IN_CRITICAL(curthread))) 51f08e1bf6SDavid Xu _pthread_exit(PTHREAD_CANCELED); 52f08e1bf6SDavid Xu } 53f08e1bf6SDavid Xu 54f08e1bf6SDavid Xu void 55f08e1bf6SDavid Xu _thr_testcancel(struct pthread *curthread) 56f08e1bf6SDavid Xu { 57f08e1bf6SDavid Xu testcancel(curthread); 58f08e1bf6SDavid Xu } 59f08e1bf6SDavid Xu 60bb535300SJeff Roberson int 610ab1bfc7SKonstantin Belousov _thr_cancel(pthread_t pthread) 62bb535300SJeff Roberson { 63a091d823SDavid Xu struct pthread *curthread = _get_curthread(); 64a091d823SDavid Xu int ret; 65bb535300SJeff Roberson 66d39d6512SMike Makonnen /* 67f08e1bf6SDavid Xu * POSIX says _pthread_cancel should be async cancellation safe. 68a9b764e2SDavid Xu * _thr_find_thread and THR_THREAD_UNLOCK will enter and leave critical 69f08e1bf6SDavid Xu * region automatically. 70d39d6512SMike Makonnen */ 71751fae1eSKonstantin Belousov if ((ret = _thr_find_thread(curthread, pthread, 1)) == 0) { 72f08e1bf6SDavid Xu if (!pthread->cancel_pending) { 73f08e1bf6SDavid Xu pthread->cancel_pending = 1; 7417dce7e1SDavid Xu if (pthread->state != PS_DEAD) 75a091d823SDavid Xu _thr_send_sig(pthread, SIGCANCEL); 766da7f493SMike Makonnen } 77f08e1bf6SDavid Xu THR_THREAD_UNLOCK(curthread, pthread); 78f08e1bf6SDavid Xu } 79f08e1bf6SDavid Xu return (ret); 80a091d823SDavid Xu } 81a091d823SDavid Xu 82bb535300SJeff Roberson int 830ab1bfc7SKonstantin Belousov _thr_setcancelstate(int state, int *oldstate) 84bb535300SJeff Roberson { 85a091d823SDavid Xu struct pthread *curthread = _get_curthread(); 86*030f48f7SKonstantin Belousov int oldval, val; 87bb535300SJeff Roberson 88bb535300SJeff Roberson switch (state) { 89bb535300SJeff Roberson case PTHREAD_CANCEL_DISABLE: 90*030f48f7SKonstantin Belousov val = 0; 91a091d823SDavid Xu break; 92a091d823SDavid Xu case PTHREAD_CANCEL_ENABLE: 93*030f48f7SKonstantin Belousov val = 1; 94bb535300SJeff Roberson break; 95bb535300SJeff Roberson default: 96f08e1bf6SDavid Xu return (EINVAL); 974cd18a22SMike Makonnen } 98bb535300SJeff Roberson 99*030f48f7SKonstantin Belousov oldval = atomic_swap_int(&curthread->cancel_enable, val); 100*030f48f7SKonstantin Belousov if (state == PTHREAD_CANCEL_ENABLE && curthread->cancel_async) 101*030f48f7SKonstantin Belousov testcancel(curthread); 1023282e368SKonstantin Belousov if (oldstate != NULL) { 103f08e1bf6SDavid Xu *oldstate = oldval ? PTHREAD_CANCEL_ENABLE : 104f08e1bf6SDavid Xu PTHREAD_CANCEL_DISABLE; 105f08e1bf6SDavid Xu } 106f08e1bf6SDavid Xu return (0); 107a091d823SDavid Xu } 108a091d823SDavid Xu 1094cd18a22SMike Makonnen int 1100ab1bfc7SKonstantin Belousov _thr_setcanceltype(int type, int *oldtype) 1114cd18a22SMike Makonnen { 112a091d823SDavid Xu struct pthread *curthread = _get_curthread(); 113f08e1bf6SDavid Xu int oldval; 1144cd18a22SMike Makonnen 115f08e1bf6SDavid Xu oldval = curthread->cancel_async; 1164cd18a22SMike Makonnen switch (type) { 1174cd18a22SMike Makonnen case PTHREAD_CANCEL_ASYNCHRONOUS: 118f08e1bf6SDavid Xu curthread->cancel_async = 1; 119a091d823SDavid Xu testcancel(curthread); 1204cd18a22SMike Makonnen break; 1214cd18a22SMike Makonnen case PTHREAD_CANCEL_DEFERRED: 122f08e1bf6SDavid Xu curthread->cancel_async = 0; 1234cd18a22SMike Makonnen break; 1244cd18a22SMike Makonnen default: 125f08e1bf6SDavid Xu return (EINVAL); 1264cd18a22SMike Makonnen } 127a091d823SDavid Xu 1283282e368SKonstantin Belousov if (oldtype != NULL) { 129f08e1bf6SDavid Xu *oldtype = oldval ? PTHREAD_CANCEL_ASYNCHRONOUS : 130f08e1bf6SDavid Xu PTHREAD_CANCEL_DEFERRED; 131f08e1bf6SDavid Xu } 132f08e1bf6SDavid Xu return (0); 133bb535300SJeff Roberson } 134bb535300SJeff Roberson 135bb535300SJeff Roberson void 1360ab1bfc7SKonstantin Belousov _Tthr_testcancel(void) 137bb535300SJeff Roberson { 138dc356606SJohn Baldwin struct pthread *curthread; 1396da7f493SMike Makonnen 140dc356606SJohn Baldwin _thr_check_init(); 141dc356606SJohn Baldwin curthread = _get_curthread(); 14202c3c858SDavid Xu testcancel(curthread); 1434cd18a22SMike Makonnen } 144bb535300SJeff Roberson 145bb535300SJeff Roberson void 146f08e1bf6SDavid Xu _thr_cancel_enter(struct pthread *curthread) 147bb535300SJeff Roberson { 14802c3c858SDavid Xu curthread->cancel_point = 1; 149f08e1bf6SDavid Xu testcancel(curthread); 150f08e1bf6SDavid Xu } 151635f917aSDavid Xu 152635f917aSDavid Xu void 15302c3c858SDavid Xu _thr_cancel_enter2(struct pthread *curthread, int maycancel) 154635f917aSDavid Xu { 15502c3c858SDavid Xu curthread->cancel_point = 1; 156635f917aSDavid Xu if (__predict_false(SHOULD_CANCEL(curthread) && 157635f917aSDavid Xu !THR_IN_CRITICAL(curthread))) { 158635f917aSDavid Xu if (!maycancel) 159635f917aSDavid Xu thr_wake(curthread->tid); 160635f917aSDavid Xu else 161635f917aSDavid Xu _pthread_exit(PTHREAD_CANCELED); 162635f917aSDavid Xu } 163f08e1bf6SDavid Xu } 164f08e1bf6SDavid Xu 165f08e1bf6SDavid Xu void 16602c3c858SDavid Xu _thr_cancel_leave(struct pthread *curthread, int maycancel) 167f08e1bf6SDavid Xu { 16893ea4a71SDavid Xu curthread->cancel_point = 0; 169a944e6d5SKonstantin Belousov if (maycancel) 170a944e6d5SKonstantin Belousov testcancel(curthread); 1713ce4e91dSDavid Xu } 172f4213b90SDavid Xu 173f4213b90SDavid Xu void 17465174f68SKonstantin Belousov _Tthr_cancel_enter(int maycancel) 175f4213b90SDavid Xu { 176f4213b90SDavid Xu _thr_cancel_enter2(_get_curthread(), maycancel); 177f4213b90SDavid Xu } 178f4213b90SDavid Xu 179f4213b90SDavid Xu void 18065174f68SKonstantin Belousov _Tthr_cancel_leave(int maycancel) 181f4213b90SDavid Xu { 182f4213b90SDavid Xu _thr_cancel_leave(_get_curthread(), maycancel); 183f4213b90SDavid Xu } 184