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