1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include "lint.h" 30 #include "thr_uberdata.h" 31 32 /* 33 * pthread_cancel: tries to cancel the targeted thread. 34 * If the target thread has already exited no action is taken. 35 * Else send SIGCANCEL to request the other thread to cancel itself. 36 */ 37 #pragma weak pthread_cancel = _pthread_cancel 38 int 39 _pthread_cancel(thread_t tid) 40 { 41 ulwp_t *self = curthread; 42 uberdata_t *udp = self->ul_uberdata; 43 ulwp_t *ulwp; 44 int error = 0; 45 46 if ((ulwp = find_lwp(tid)) == NULL) 47 return (ESRCH); 48 49 if (ulwp->ul_cancel_pending) { 50 /* 51 * Don't send SIGCANCEL more than once. 52 */ 53 ulwp_unlock(ulwp, udp); 54 } else if (ulwp == self) { 55 /* 56 * Unlock self before cancelling. 57 */ 58 ulwp_unlock(ulwp, udp); 59 ulwp->ul_nocancel = 0; /* cancellation is now possible */ 60 if (ulwp->ul_sigdefer) 61 ulwp->ul_cancel_pending = 1; 62 else 63 do_sigcancel(); 64 } else if (ulwp->ul_cancel_disabled) { 65 /* 66 * Don't send SIGCANCEL if cancellation is disabled; 67 * just set the thread's ulwp->ul_cancel_pending flag. 68 * This avoids a potential EINTR for the target thread. 69 */ 70 ulwp->ul_cancel_pending = 1; 71 ulwp_unlock(ulwp, udp); 72 } else { 73 /* 74 * Request the other thread to cancel itself. 75 */ 76 error = __lwp_kill(tid, SIGCANCEL); 77 ulwp_unlock(ulwp, udp); 78 } 79 80 return (error); 81 } 82 83 /* 84 * pthread_setcancelstate: sets the state ENABLED or DISABLED 85 * If the state is being set as ENABLED, then it becomes 86 * a cancellation point only if the type of cancellation is 87 * ASYNCHRONOUS and a cancel request is pending. 88 * Disabling cancellation is not a cancellation point. 89 */ 90 #pragma weak pthread_setcancelstate = _pthread_setcancelstate 91 int 92 _pthread_setcancelstate(int state, int *oldstate) 93 { 94 ulwp_t *self = curthread; 95 uberdata_t *udp = self->ul_uberdata; 96 int was_disabled; 97 98 /* 99 * Grab ulwp_lock(self) to protect the setting of ul_cancel_disabled 100 * since it is tested under this lock by pthread_cancel(), above. 101 * This has the side-effect of calling enter_critical() and this 102 * defers SIGCANCEL until ulwp_unlock(self) when exit_critical() 103 * is called. (self->ul_cancel_pending is set in the SIGCANCEL 104 * handler and we must be async-signal safe here.) 105 */ 106 ulwp_lock(self, udp); 107 108 was_disabled = self->ul_cancel_disabled; 109 switch (state) { 110 case PTHREAD_CANCEL_ENABLE: 111 self->ul_cancel_disabled = 0; 112 break; 113 case PTHREAD_CANCEL_DISABLE: 114 self->ul_cancel_disabled = 1; 115 break; 116 default: 117 ulwp_unlock(self, udp); 118 return (EINVAL); 119 } 120 121 /* 122 * If this thread has been requested to be canceled and 123 * is in async mode and is or was enabled, then exit. 124 */ 125 if ((!self->ul_cancel_disabled || !was_disabled) && 126 self->ul_cancel_async && self->ul_cancel_pending) { 127 ulwp_unlock(self, udp); 128 _pthread_exit(PTHREAD_CANCELED); 129 } 130 131 ulwp_unlock(self, udp); 132 133 if (oldstate != NULL) { 134 if (was_disabled) 135 *oldstate = PTHREAD_CANCEL_DISABLE; 136 else 137 *oldstate = PTHREAD_CANCEL_ENABLE; 138 } 139 return (0); 140 } 141 142 /* 143 * pthread_setcanceltype: sets the type DEFERRED or ASYNCHRONOUS 144 * If the type is being set as ASYNC, then it becomes 145 * a cancellation point if there is a cancellation pending. 146 */ 147 #pragma weak pthread_setcanceltype = _pthread_setcanceltype 148 int 149 _pthread_setcanceltype(int type, int *oldtype) 150 { 151 ulwp_t *self = curthread; 152 int was_async; 153 154 /* 155 * Call enter_critical() to defer SIGCANCEL until exit_critical(). 156 * We do this because curthread->ul_cancel_pending is set in the 157 * SIGCANCEL handler and we must be async-signal safe here. 158 */ 159 enter_critical(self); 160 161 was_async = self->ul_cancel_async; 162 switch (type) { 163 case PTHREAD_CANCEL_ASYNCHRONOUS: 164 self->ul_cancel_async = 1; 165 break; 166 case PTHREAD_CANCEL_DEFERRED: 167 self->ul_cancel_async = 0; 168 break; 169 default: 170 exit_critical(self); 171 return (EINVAL); 172 } 173 self->ul_save_async = self->ul_cancel_async; 174 175 /* 176 * If this thread has been requested to be canceled and 177 * is in enabled mode and is or was in async mode, exit. 178 */ 179 if ((self->ul_cancel_async || was_async) && 180 self->ul_cancel_pending && !self->ul_cancel_disabled) { 181 exit_critical(self); 182 _pthread_exit(PTHREAD_CANCELED); 183 } 184 185 exit_critical(self); 186 187 if (oldtype != NULL) { 188 if (was_async) 189 *oldtype = PTHREAD_CANCEL_ASYNCHRONOUS; 190 else 191 *oldtype = PTHREAD_CANCEL_DEFERRED; 192 } 193 return (0); 194 } 195 196 /* 197 * pthread_testcancel: tests for any cancellation pending 198 * if the cancellation is enabled and is pending, act on 199 * it by calling thr_exit. thr_exit takes care of calling 200 * cleanup handlers. 201 */ 202 #pragma weak _private_testcancel = _pthread_testcancel 203 #pragma weak pthread_testcancel = _pthread_testcancel 204 void 205 _pthread_testcancel(void) 206 { 207 ulwp_t *self = curthread; 208 209 if (self->ul_cancel_pending && !self->ul_cancel_disabled) 210 _pthread_exit(PTHREAD_CANCELED); 211 } 212 213 /* 214 * For deferred mode, this routine makes a thread cancelable. 215 * It is called from the functions which want to be cancellation 216 * points and are about to block, such as cond_wait(). 217 */ 218 void 219 _cancelon() 220 { 221 ulwp_t *self = curthread; 222 223 ASSERT(!(self->ul_cancelable && self->ul_cancel_disabled)); 224 if (!self->ul_cancel_disabled) { 225 ASSERT(self->ul_cancelable >= 0); 226 self->ul_cancelable++; 227 if (self->ul_cancel_pending) 228 _pthread_exit(PTHREAD_CANCELED); 229 } 230 } 231 232 /* 233 * This routine turns cancelability off and possible calls pthread_exit(). 234 * It is called from functions which are cancellation points, like cond_wait(). 235 */ 236 void 237 _canceloff() 238 { 239 ulwp_t *self = curthread; 240 241 ASSERT(!(self->ul_cancelable && self->ul_cancel_disabled)); 242 if (!self->ul_cancel_disabled) { 243 if (self->ul_cancel_pending) 244 _pthread_exit(PTHREAD_CANCELED); 245 self->ul_cancelable--; 246 ASSERT(self->ul_cancelable >= 0); 247 } 248 } 249 250 /* 251 * Same as _canceloff() but don't actually cancel the thread. 252 * This is used by cond_wait() and sema_wait() when they don't get EINTR. 253 */ 254 void 255 _canceloff_nocancel() 256 { 257 ulwp_t *self = curthread; 258 259 ASSERT(!(self->ul_cancelable && self->ul_cancel_disabled)); 260 if (!self->ul_cancel_disabled) { 261 self->ul_cancelable--; 262 ASSERT(self->ul_cancelable >= 0); 263 } 264 } 265 266 /* 267 * __pthread_cleanup_push: called by macro in pthread.h which defines 268 * POSIX.1c pthread_cleanup_push(). Macro in pthread.h allocates the 269 * cleanup struct and calls this routine to push the handler off the 270 * curthread's struct. 271 */ 272 void 273 __pthread_cleanup_push(void (*routine)(void *), 274 void *args, caddr_t fp, _cleanup_t *clnup_info) 275 { 276 ulwp_t *self = curthread; 277 __cleanup_t *infop = (__cleanup_t *)clnup_info; 278 279 infop->func = routine; 280 infop->arg = args; 281 infop->fp = fp; 282 infop->next = self->ul_clnup_hdr; 283 self->ul_clnup_hdr = infop; 284 } 285 286 /* 287 * __pthread_cleanup_pop: called by macro in pthread.h which defines 288 * POSIX.1c pthread_cleanup_pop(). It calls this routine to pop the 289 * handler off the curthread's struct and execute it if necessary. 290 */ 291 /* ARGSUSED1 */ 292 void 293 __pthread_cleanup_pop(int ex, _cleanup_t *clnup_info) 294 { 295 ulwp_t *self = curthread; 296 __cleanup_t *infop = self->ul_clnup_hdr; 297 298 self->ul_clnup_hdr = infop->next; 299 if (ex) 300 (*infop->func)(infop->arg); 301 } 302