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