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