1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2005, David Xu <davidxu@freebsd.org> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice unmodified, this list of conditions, and the following 12 * disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __FBSDID("$FreeBSD$"); 31 32 #include "namespace.h" 33 #include <pthread.h> 34 #include "un-namespace.h" 35 36 #include "thr_private.h" 37 38 __weak_reference(_pthread_cancel, pthread_cancel); 39 __weak_reference(_pthread_setcancelstate, pthread_setcancelstate); 40 __weak_reference(_pthread_setcanceltype, pthread_setcanceltype); 41 __weak_reference(_pthread_testcancel, pthread_testcancel); 42 43 static inline void 44 testcancel(struct pthread *curthread) 45 { 46 if (__predict_false(SHOULD_CANCEL(curthread) && 47 !THR_IN_CRITICAL(curthread))) 48 _pthread_exit(PTHREAD_CANCELED); 49 } 50 51 void 52 _thr_testcancel(struct pthread *curthread) 53 { 54 testcancel(curthread); 55 } 56 57 int 58 _pthread_cancel(pthread_t pthread) 59 { 60 struct pthread *curthread = _get_curthread(); 61 int ret; 62 63 /* 64 * POSIX says _pthread_cancel should be async cancellation safe. 65 * _thr_find_thread and THR_THREAD_UNLOCK will enter and leave critical 66 * region automatically. 67 */ 68 if ((ret = _thr_find_thread(curthread, pthread, 0)) == 0) { 69 if (!pthread->cancel_pending) { 70 pthread->cancel_pending = 1; 71 if (pthread->state != PS_DEAD) 72 _thr_send_sig(pthread, SIGCANCEL); 73 } 74 THR_THREAD_UNLOCK(curthread, pthread); 75 } 76 return (ret); 77 } 78 79 int 80 _pthread_setcancelstate(int state, int *oldstate) 81 { 82 struct pthread *curthread = _get_curthread(); 83 int oldval; 84 85 oldval = curthread->cancel_enable; 86 switch (state) { 87 case PTHREAD_CANCEL_DISABLE: 88 curthread->cancel_enable = 0; 89 break; 90 case PTHREAD_CANCEL_ENABLE: 91 curthread->cancel_enable = 1; 92 if (curthread->cancel_async) 93 testcancel(curthread); 94 break; 95 default: 96 return (EINVAL); 97 } 98 99 if (oldstate) { 100 *oldstate = oldval ? PTHREAD_CANCEL_ENABLE : 101 PTHREAD_CANCEL_DISABLE; 102 } 103 return (0); 104 } 105 106 int 107 _pthread_setcanceltype(int type, int *oldtype) 108 { 109 struct pthread *curthread = _get_curthread(); 110 int oldval; 111 112 oldval = curthread->cancel_async; 113 switch (type) { 114 case PTHREAD_CANCEL_ASYNCHRONOUS: 115 curthread->cancel_async = 1; 116 testcancel(curthread); 117 break; 118 case PTHREAD_CANCEL_DEFERRED: 119 curthread->cancel_async = 0; 120 break; 121 default: 122 return (EINVAL); 123 } 124 125 if (oldtype) { 126 *oldtype = oldval ? PTHREAD_CANCEL_ASYNCHRONOUS : 127 PTHREAD_CANCEL_DEFERRED; 128 } 129 return (0); 130 } 131 132 void 133 _pthread_testcancel(void) 134 { 135 struct pthread *curthread; 136 137 _thr_check_init(); 138 curthread = _get_curthread(); 139 testcancel(curthread); 140 } 141 142 void 143 _thr_cancel_enter(struct pthread *curthread) 144 { 145 curthread->cancel_point = 1; 146 testcancel(curthread); 147 } 148 149 void 150 _thr_cancel_enter2(struct pthread *curthread, int maycancel) 151 { 152 curthread->cancel_point = 1; 153 if (__predict_false(SHOULD_CANCEL(curthread) && 154 !THR_IN_CRITICAL(curthread))) { 155 if (!maycancel) 156 thr_wake(curthread->tid); 157 else 158 _pthread_exit(PTHREAD_CANCELED); 159 } 160 } 161 162 void 163 _thr_cancel_leave(struct pthread *curthread, int maycancel) 164 { 165 curthread->cancel_point = 0; 166 if (__predict_false(SHOULD_CANCEL(curthread) && 167 !THR_IN_CRITICAL(curthread) && maycancel)) 168 _pthread_exit(PTHREAD_CANCELED); 169 } 170 171 void 172 _pthread_cancel_enter(int maycancel) 173 { 174 _thr_cancel_enter2(_get_curthread(), maycancel); 175 } 176 177 void 178 _pthread_cancel_leave(int maycancel) 179 { 180 _thr_cancel_leave(_get_curthread(), maycancel); 181 } 182