1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 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(_thr_cancel, pthread_cancel); 39 __weak_reference(_thr_cancel, _pthread_cancel); 40 __weak_reference(_thr_setcancelstate, pthread_setcancelstate); 41 __weak_reference(_thr_setcancelstate, _pthread_setcancelstate); 42 __weak_reference(_thr_setcanceltype, pthread_setcanceltype); 43 __weak_reference(_thr_setcanceltype, _pthread_setcanceltype); 44 __weak_reference(_Tthr_testcancel, pthread_testcancel); 45 __weak_reference(_Tthr_testcancel, _pthread_testcancel); 46 __weak_reference(_Tthr_cancel_enter, _pthread_cancel_enter); 47 __weak_reference(_Tthr_cancel_leave, _pthread_cancel_leave); 48 49 static inline void 50 testcancel(struct pthread *curthread) 51 { 52 if (__predict_false(SHOULD_CANCEL(curthread) && 53 !THR_IN_CRITICAL(curthread))) 54 _pthread_exit(PTHREAD_CANCELED); 55 } 56 57 void 58 _thr_testcancel(struct pthread *curthread) 59 { 60 testcancel(curthread); 61 } 62 63 int 64 _thr_cancel(pthread_t pthread) 65 { 66 struct pthread *curthread = _get_curthread(); 67 int ret; 68 69 /* 70 * POSIX says _pthread_cancel should be async cancellation safe. 71 * _thr_find_thread and THR_THREAD_UNLOCK will enter and leave critical 72 * region automatically. 73 */ 74 if ((ret = _thr_find_thread(curthread, pthread, 1)) == 0) { 75 if (!pthread->cancel_pending) { 76 pthread->cancel_pending = 1; 77 if (pthread->state != PS_DEAD) 78 _thr_send_sig(pthread, SIGCANCEL); 79 } 80 THR_THREAD_UNLOCK(curthread, pthread); 81 } 82 return (ret); 83 } 84 85 int 86 _thr_setcancelstate(int state, int *oldstate) 87 { 88 struct pthread *curthread = _get_curthread(); 89 int oldval; 90 91 oldval = curthread->cancel_enable; 92 switch (state) { 93 case PTHREAD_CANCEL_DISABLE: 94 curthread->cancel_enable = 0; 95 break; 96 case PTHREAD_CANCEL_ENABLE: 97 curthread->cancel_enable = 1; 98 if (curthread->cancel_async) 99 testcancel(curthread); 100 break; 101 default: 102 return (EINVAL); 103 } 104 105 if (oldstate) { 106 *oldstate = oldval ? PTHREAD_CANCEL_ENABLE : 107 PTHREAD_CANCEL_DISABLE; 108 } 109 return (0); 110 } 111 112 int 113 _thr_setcanceltype(int type, int *oldtype) 114 { 115 struct pthread *curthread = _get_curthread(); 116 int oldval; 117 118 oldval = curthread->cancel_async; 119 switch (type) { 120 case PTHREAD_CANCEL_ASYNCHRONOUS: 121 curthread->cancel_async = 1; 122 testcancel(curthread); 123 break; 124 case PTHREAD_CANCEL_DEFERRED: 125 curthread->cancel_async = 0; 126 break; 127 default: 128 return (EINVAL); 129 } 130 131 if (oldtype) { 132 *oldtype = oldval ? PTHREAD_CANCEL_ASYNCHRONOUS : 133 PTHREAD_CANCEL_DEFERRED; 134 } 135 return (0); 136 } 137 138 void 139 _Tthr_testcancel(void) 140 { 141 struct pthread *curthread; 142 143 _thr_check_init(); 144 curthread = _get_curthread(); 145 testcancel(curthread); 146 } 147 148 void 149 _thr_cancel_enter(struct pthread *curthread) 150 { 151 curthread->cancel_point = 1; 152 testcancel(curthread); 153 } 154 155 void 156 _thr_cancel_enter2(struct pthread *curthread, int maycancel) 157 { 158 curthread->cancel_point = 1; 159 if (__predict_false(SHOULD_CANCEL(curthread) && 160 !THR_IN_CRITICAL(curthread))) { 161 if (!maycancel) 162 thr_wake(curthread->tid); 163 else 164 _pthread_exit(PTHREAD_CANCELED); 165 } 166 } 167 168 void 169 _thr_cancel_leave(struct pthread *curthread, int maycancel) 170 { 171 curthread->cancel_point = 0; 172 if (__predict_false(SHOULD_CANCEL(curthread) && 173 !THR_IN_CRITICAL(curthread) && maycancel)) 174 _pthread_exit(PTHREAD_CANCELED); 175 } 176 177 void 178 _Tthr_cancel_enter(int maycancel) 179 { 180 _thr_cancel_enter2(_get_curthread(), maycancel); 181 } 182 183 void 184 _Tthr_cancel_leave(int maycancel) 185 { 186 _thr_cancel_leave(_get_curthread(), maycancel); 187 } 188