10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 55891Sraf * Common Development and Distribution License (the "License"). 65891Sraf * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 215891Sraf 220Sstevel@tonic-gate /* 235891Sraf * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate 270Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 280Sstevel@tonic-gate 290Sstevel@tonic-gate #include "lint.h" 300Sstevel@tonic-gate #include "thr_uberdata.h" 310Sstevel@tonic-gate 320Sstevel@tonic-gate /* 330Sstevel@tonic-gate * pthread_cancel: tries to cancel the targeted thread. 340Sstevel@tonic-gate * If the target thread has already exited no action is taken. 350Sstevel@tonic-gate * Else send SIGCANCEL to request the other thread to cancel itself. 360Sstevel@tonic-gate */ 370Sstevel@tonic-gate int 38*6812Sraf pthread_cancel(thread_t tid) 390Sstevel@tonic-gate { 400Sstevel@tonic-gate ulwp_t *self = curthread; 410Sstevel@tonic-gate uberdata_t *udp = self->ul_uberdata; 420Sstevel@tonic-gate ulwp_t *ulwp; 430Sstevel@tonic-gate int error = 0; 440Sstevel@tonic-gate 450Sstevel@tonic-gate if ((ulwp = find_lwp(tid)) == NULL) 460Sstevel@tonic-gate return (ESRCH); 470Sstevel@tonic-gate 480Sstevel@tonic-gate if (ulwp->ul_cancel_pending) { 490Sstevel@tonic-gate /* 500Sstevel@tonic-gate * Don't send SIGCANCEL more than once. 510Sstevel@tonic-gate */ 520Sstevel@tonic-gate ulwp_unlock(ulwp, udp); 530Sstevel@tonic-gate } else if (ulwp == self) { 540Sstevel@tonic-gate /* 550Sstevel@tonic-gate * Unlock self before cancelling. 560Sstevel@tonic-gate */ 575891Sraf ulwp_unlock(self, udp); 585891Sraf self->ul_nocancel = 0; /* cancellation is now possible */ 595891Sraf if (self->ul_sigdefer == 0) 600Sstevel@tonic-gate do_sigcancel(); 615891Sraf else { 625891Sraf self->ul_cancel_pending = 1; 635891Sraf set_cancel_pending_flag(self, 0); 645891Sraf } 650Sstevel@tonic-gate } else if (ulwp->ul_cancel_disabled) { 660Sstevel@tonic-gate /* 670Sstevel@tonic-gate * Don't send SIGCANCEL if cancellation is disabled; 680Sstevel@tonic-gate * just set the thread's ulwp->ul_cancel_pending flag. 690Sstevel@tonic-gate * This avoids a potential EINTR for the target thread. 705891Sraf * We don't call set_cancel_pending_flag() here because 715891Sraf * we cannot modify another thread's schedctl data. 720Sstevel@tonic-gate */ 730Sstevel@tonic-gate ulwp->ul_cancel_pending = 1; 740Sstevel@tonic-gate ulwp_unlock(ulwp, udp); 750Sstevel@tonic-gate } else { 760Sstevel@tonic-gate /* 770Sstevel@tonic-gate * Request the other thread to cancel itself. 780Sstevel@tonic-gate */ 79*6812Sraf error = _lwp_kill(tid, SIGCANCEL); 800Sstevel@tonic-gate ulwp_unlock(ulwp, udp); 810Sstevel@tonic-gate } 820Sstevel@tonic-gate 830Sstevel@tonic-gate return (error); 840Sstevel@tonic-gate } 850Sstevel@tonic-gate 860Sstevel@tonic-gate /* 875891Sraf * pthread_setcancelstate: sets the state ENABLED or DISABLED. 885891Sraf * If the state is already ENABLED or is being set to ENABLED, 895891Sraf * the type of cancellation is ASYNCHRONOUS, and a cancel request 905891Sraf * is pending, then the thread is cancelled right here. 915891Sraf * Otherwise, pthread_setcancelstate() is not a cancellation point. 920Sstevel@tonic-gate */ 930Sstevel@tonic-gate int 94*6812Sraf pthread_setcancelstate(int state, int *oldstate) 950Sstevel@tonic-gate { 960Sstevel@tonic-gate ulwp_t *self = curthread; 970Sstevel@tonic-gate uberdata_t *udp = self->ul_uberdata; 980Sstevel@tonic-gate int was_disabled; 990Sstevel@tonic-gate 1000Sstevel@tonic-gate /* 1010Sstevel@tonic-gate * Grab ulwp_lock(self) to protect the setting of ul_cancel_disabled 1020Sstevel@tonic-gate * since it is tested under this lock by pthread_cancel(), above. 1030Sstevel@tonic-gate * This has the side-effect of calling enter_critical() and this 1040Sstevel@tonic-gate * defers SIGCANCEL until ulwp_unlock(self) when exit_critical() 1050Sstevel@tonic-gate * is called. (self->ul_cancel_pending is set in the SIGCANCEL 1060Sstevel@tonic-gate * handler and we must be async-signal safe here.) 1070Sstevel@tonic-gate */ 1080Sstevel@tonic-gate ulwp_lock(self, udp); 1090Sstevel@tonic-gate 1100Sstevel@tonic-gate was_disabled = self->ul_cancel_disabled; 1110Sstevel@tonic-gate switch (state) { 1120Sstevel@tonic-gate case PTHREAD_CANCEL_ENABLE: 1130Sstevel@tonic-gate self->ul_cancel_disabled = 0; 1140Sstevel@tonic-gate break; 1150Sstevel@tonic-gate case PTHREAD_CANCEL_DISABLE: 1160Sstevel@tonic-gate self->ul_cancel_disabled = 1; 1170Sstevel@tonic-gate break; 1180Sstevel@tonic-gate default: 1190Sstevel@tonic-gate ulwp_unlock(self, udp); 1200Sstevel@tonic-gate return (EINVAL); 1210Sstevel@tonic-gate } 1225891Sraf set_cancel_pending_flag(self, 0); 1230Sstevel@tonic-gate 1240Sstevel@tonic-gate /* 1250Sstevel@tonic-gate * If this thread has been requested to be canceled and 1260Sstevel@tonic-gate * is in async mode and is or was enabled, then exit. 1270Sstevel@tonic-gate */ 1280Sstevel@tonic-gate if ((!self->ul_cancel_disabled || !was_disabled) && 1290Sstevel@tonic-gate self->ul_cancel_async && self->ul_cancel_pending) { 1300Sstevel@tonic-gate ulwp_unlock(self, udp); 131*6812Sraf pthread_exit(PTHREAD_CANCELED); 1320Sstevel@tonic-gate } 1330Sstevel@tonic-gate 1340Sstevel@tonic-gate ulwp_unlock(self, udp); 1350Sstevel@tonic-gate 1360Sstevel@tonic-gate if (oldstate != NULL) { 1370Sstevel@tonic-gate if (was_disabled) 1380Sstevel@tonic-gate *oldstate = PTHREAD_CANCEL_DISABLE; 1390Sstevel@tonic-gate else 1400Sstevel@tonic-gate *oldstate = PTHREAD_CANCEL_ENABLE; 1410Sstevel@tonic-gate } 1420Sstevel@tonic-gate return (0); 1430Sstevel@tonic-gate } 1440Sstevel@tonic-gate 1450Sstevel@tonic-gate /* 1460Sstevel@tonic-gate * pthread_setcanceltype: sets the type DEFERRED or ASYNCHRONOUS 1470Sstevel@tonic-gate * If the type is being set as ASYNC, then it becomes 1480Sstevel@tonic-gate * a cancellation point if there is a cancellation pending. 1490Sstevel@tonic-gate */ 1500Sstevel@tonic-gate int 151*6812Sraf pthread_setcanceltype(int type, int *oldtype) 1520Sstevel@tonic-gate { 1530Sstevel@tonic-gate ulwp_t *self = curthread; 1540Sstevel@tonic-gate int was_async; 1550Sstevel@tonic-gate 1560Sstevel@tonic-gate /* 1570Sstevel@tonic-gate * Call enter_critical() to defer SIGCANCEL until exit_critical(). 1580Sstevel@tonic-gate * We do this because curthread->ul_cancel_pending is set in the 1590Sstevel@tonic-gate * SIGCANCEL handler and we must be async-signal safe here. 1600Sstevel@tonic-gate */ 1610Sstevel@tonic-gate enter_critical(self); 1620Sstevel@tonic-gate 1630Sstevel@tonic-gate was_async = self->ul_cancel_async; 1640Sstevel@tonic-gate switch (type) { 1650Sstevel@tonic-gate case PTHREAD_CANCEL_ASYNCHRONOUS: 1660Sstevel@tonic-gate self->ul_cancel_async = 1; 1670Sstevel@tonic-gate break; 1680Sstevel@tonic-gate case PTHREAD_CANCEL_DEFERRED: 1690Sstevel@tonic-gate self->ul_cancel_async = 0; 1700Sstevel@tonic-gate break; 1710Sstevel@tonic-gate default: 1720Sstevel@tonic-gate exit_critical(self); 1730Sstevel@tonic-gate return (EINVAL); 1740Sstevel@tonic-gate } 1750Sstevel@tonic-gate self->ul_save_async = self->ul_cancel_async; 1760Sstevel@tonic-gate 1770Sstevel@tonic-gate /* 1780Sstevel@tonic-gate * If this thread has been requested to be canceled and 1790Sstevel@tonic-gate * is in enabled mode and is or was in async mode, exit. 1800Sstevel@tonic-gate */ 1810Sstevel@tonic-gate if ((self->ul_cancel_async || was_async) && 1820Sstevel@tonic-gate self->ul_cancel_pending && !self->ul_cancel_disabled) { 1830Sstevel@tonic-gate exit_critical(self); 184*6812Sraf pthread_exit(PTHREAD_CANCELED); 1850Sstevel@tonic-gate } 1860Sstevel@tonic-gate 1870Sstevel@tonic-gate exit_critical(self); 1880Sstevel@tonic-gate 1890Sstevel@tonic-gate if (oldtype != NULL) { 1900Sstevel@tonic-gate if (was_async) 1910Sstevel@tonic-gate *oldtype = PTHREAD_CANCEL_ASYNCHRONOUS; 1920Sstevel@tonic-gate else 1930Sstevel@tonic-gate *oldtype = PTHREAD_CANCEL_DEFERRED; 1940Sstevel@tonic-gate } 1950Sstevel@tonic-gate return (0); 1960Sstevel@tonic-gate } 1970Sstevel@tonic-gate 1980Sstevel@tonic-gate /* 1990Sstevel@tonic-gate * pthread_testcancel: tests for any cancellation pending 2000Sstevel@tonic-gate * if the cancellation is enabled and is pending, act on 2010Sstevel@tonic-gate * it by calling thr_exit. thr_exit takes care of calling 2020Sstevel@tonic-gate * cleanup handlers. 2030Sstevel@tonic-gate */ 2040Sstevel@tonic-gate void 205*6812Sraf pthread_testcancel(void) 2060Sstevel@tonic-gate { 2070Sstevel@tonic-gate ulwp_t *self = curthread; 2080Sstevel@tonic-gate 2090Sstevel@tonic-gate if (self->ul_cancel_pending && !self->ul_cancel_disabled) 210*6812Sraf pthread_exit(PTHREAD_CANCELED); 2110Sstevel@tonic-gate } 2120Sstevel@tonic-gate 2130Sstevel@tonic-gate /* 2140Sstevel@tonic-gate * For deferred mode, this routine makes a thread cancelable. 2150Sstevel@tonic-gate * It is called from the functions which want to be cancellation 2160Sstevel@tonic-gate * points and are about to block, such as cond_wait(). 2170Sstevel@tonic-gate */ 2180Sstevel@tonic-gate void 2190Sstevel@tonic-gate _cancelon() 2200Sstevel@tonic-gate { 2210Sstevel@tonic-gate ulwp_t *self = curthread; 2220Sstevel@tonic-gate 2230Sstevel@tonic-gate ASSERT(!(self->ul_cancelable && self->ul_cancel_disabled)); 2240Sstevel@tonic-gate if (!self->ul_cancel_disabled) { 2250Sstevel@tonic-gate ASSERT(self->ul_cancelable >= 0); 2260Sstevel@tonic-gate self->ul_cancelable++; 2270Sstevel@tonic-gate if (self->ul_cancel_pending) 228*6812Sraf pthread_exit(PTHREAD_CANCELED); 2290Sstevel@tonic-gate } 2300Sstevel@tonic-gate } 2310Sstevel@tonic-gate 2320Sstevel@tonic-gate /* 2330Sstevel@tonic-gate * This routine turns cancelability off and possible calls pthread_exit(). 2340Sstevel@tonic-gate * It is called from functions which are cancellation points, like cond_wait(). 2350Sstevel@tonic-gate */ 2360Sstevel@tonic-gate void 2370Sstevel@tonic-gate _canceloff() 2380Sstevel@tonic-gate { 2390Sstevel@tonic-gate ulwp_t *self = curthread; 2400Sstevel@tonic-gate 2410Sstevel@tonic-gate ASSERT(!(self->ul_cancelable && self->ul_cancel_disabled)); 2420Sstevel@tonic-gate if (!self->ul_cancel_disabled) { 2430Sstevel@tonic-gate if (self->ul_cancel_pending) 244*6812Sraf pthread_exit(PTHREAD_CANCELED); 2450Sstevel@tonic-gate self->ul_cancelable--; 2460Sstevel@tonic-gate ASSERT(self->ul_cancelable >= 0); 2470Sstevel@tonic-gate } 2480Sstevel@tonic-gate } 2490Sstevel@tonic-gate 2500Sstevel@tonic-gate /* 2510Sstevel@tonic-gate * Same as _canceloff() but don't actually cancel the thread. 2520Sstevel@tonic-gate * This is used by cond_wait() and sema_wait() when they don't get EINTR. 2530Sstevel@tonic-gate */ 2540Sstevel@tonic-gate void 2550Sstevel@tonic-gate _canceloff_nocancel() 2560Sstevel@tonic-gate { 2570Sstevel@tonic-gate ulwp_t *self = curthread; 2580Sstevel@tonic-gate 2590Sstevel@tonic-gate ASSERT(!(self->ul_cancelable && self->ul_cancel_disabled)); 2600Sstevel@tonic-gate if (!self->ul_cancel_disabled) { 2610Sstevel@tonic-gate self->ul_cancelable--; 2620Sstevel@tonic-gate ASSERT(self->ul_cancelable >= 0); 2630Sstevel@tonic-gate } 2640Sstevel@tonic-gate } 2650Sstevel@tonic-gate 2660Sstevel@tonic-gate /* 2670Sstevel@tonic-gate * __pthread_cleanup_push: called by macro in pthread.h which defines 2680Sstevel@tonic-gate * POSIX.1c pthread_cleanup_push(). Macro in pthread.h allocates the 2690Sstevel@tonic-gate * cleanup struct and calls this routine to push the handler off the 2700Sstevel@tonic-gate * curthread's struct. 2710Sstevel@tonic-gate */ 2720Sstevel@tonic-gate void 2730Sstevel@tonic-gate __pthread_cleanup_push(void (*routine)(void *), 2740Sstevel@tonic-gate void *args, caddr_t fp, _cleanup_t *clnup_info) 2750Sstevel@tonic-gate { 2760Sstevel@tonic-gate ulwp_t *self = curthread; 2770Sstevel@tonic-gate __cleanup_t *infop = (__cleanup_t *)clnup_info; 2780Sstevel@tonic-gate 2790Sstevel@tonic-gate infop->func = routine; 2800Sstevel@tonic-gate infop->arg = args; 2810Sstevel@tonic-gate infop->fp = fp; 2820Sstevel@tonic-gate infop->next = self->ul_clnup_hdr; 2830Sstevel@tonic-gate self->ul_clnup_hdr = infop; 2840Sstevel@tonic-gate } 2850Sstevel@tonic-gate 2860Sstevel@tonic-gate /* 2870Sstevel@tonic-gate * __pthread_cleanup_pop: called by macro in pthread.h which defines 2880Sstevel@tonic-gate * POSIX.1c pthread_cleanup_pop(). It calls this routine to pop the 2890Sstevel@tonic-gate * handler off the curthread's struct and execute it if necessary. 2900Sstevel@tonic-gate */ 2910Sstevel@tonic-gate /* ARGSUSED1 */ 2920Sstevel@tonic-gate void 2930Sstevel@tonic-gate __pthread_cleanup_pop(int ex, _cleanup_t *clnup_info) 2940Sstevel@tonic-gate { 2950Sstevel@tonic-gate ulwp_t *self = curthread; 2960Sstevel@tonic-gate __cleanup_t *infop = self->ul_clnup_hdr; 2970Sstevel@tonic-gate 2980Sstevel@tonic-gate self->ul_clnup_hdr = infop->next; 2990Sstevel@tonic-gate if (ex) 3000Sstevel@tonic-gate (*infop->func)(infop->arg); 3010Sstevel@tonic-gate } 3025891Sraf 3035891Sraf /* 3045891Sraf * Called when either self->ul_cancel_disabled or self->ul_cancel_pending 3055891Sraf * is modified. Setting SC_CANCEL_FLG informs the kernel that we have 3065891Sraf * a pending cancellation and we do not have cancellation disabled. 3075891Sraf * In this situation, we will not go to sleep on any system call but 3085891Sraf * will instead return EINTR immediately on any attempt to sleep, 3095891Sraf * with SC_EINTR_FLG set in sc_flgs. Clearing SC_CANCEL_FLG rescinds 3105891Sraf * this condition, but SC_EINTR_FLG never goes away until the thread 3115891Sraf * terminates (indicated by clear_flags != 0). 3125891Sraf */ 3135891Sraf void 3145891Sraf set_cancel_pending_flag(ulwp_t *self, int clear_flags) 3155891Sraf { 3165891Sraf volatile sc_shared_t *scp; 3175891Sraf 3185891Sraf if (self->ul_vfork | self->ul_nocancel) 3195891Sraf return; 3205891Sraf enter_critical(self); 3215891Sraf if ((scp = self->ul_schedctl) != NULL || 3225891Sraf (scp = setup_schedctl()) != NULL) { 3235891Sraf if (clear_flags) 3245891Sraf scp->sc_flgs &= ~(SC_CANCEL_FLG | SC_EINTR_FLG); 3255891Sraf else if (self->ul_cancel_pending && !self->ul_cancel_disabled) 3265891Sraf scp->sc_flgs |= SC_CANCEL_FLG; 3275891Sraf else 3285891Sraf scp->sc_flgs &= ~SC_CANCEL_FLG; 3295891Sraf } 3305891Sraf exit_critical(self); 3315891Sraf } 3325891Sraf 3335891Sraf /* 3345891Sraf * Called from the PROLOGUE macro in scalls.c to inform subsequent 3355891Sraf * code that a cancellation point has been called and that the 3365891Sraf * current thread should cancel itself as soon as all of its locks 3375891Sraf * have been dropped (see safe_mutex_unlock()). 3385891Sraf */ 3395891Sraf void 3405891Sraf set_cancel_eintr_flag(ulwp_t *self) 3415891Sraf { 3425891Sraf volatile sc_shared_t *scp; 3435891Sraf 3445891Sraf if (self->ul_vfork | self->ul_nocancel) 3455891Sraf return; 3465891Sraf enter_critical(self); 3475891Sraf if ((scp = self->ul_schedctl) != NULL || 3485891Sraf (scp = setup_schedctl()) != NULL) 3495891Sraf scp->sc_flgs |= SC_EINTR_FLG; 3505891Sraf exit_critical(self); 3515891Sraf } 3525891Sraf 3535891Sraf /* 3545891Sraf * Calling set_parking_flag(curthread, 1) informs the kernel that we are 3555891Sraf * calling __lwp_park or ___lwp_cond_wait(). If we take a signal in 3565891Sraf * the unprotected (from signals) interval before reaching the kernel, 3575891Sraf * sigacthandler() will call set_parking_flag(curthread, 0) to inform 3585891Sraf * the kernel to return immediately from these system calls, giving us 3595891Sraf * a spurious wakeup but not a deadlock. 3605891Sraf */ 3615891Sraf void 3625891Sraf set_parking_flag(ulwp_t *self, int park) 3635891Sraf { 3645891Sraf volatile sc_shared_t *scp; 3655891Sraf 3665891Sraf enter_critical(self); 3675891Sraf if ((scp = self->ul_schedctl) != NULL || 3685891Sraf (scp = setup_schedctl()) != NULL) { 3695891Sraf if (park) { 3705891Sraf scp->sc_flgs |= SC_PARK_FLG; 3715891Sraf /* 3725891Sraf * We are parking; allow the __lwp_park() call to 3735891Sraf * block even if we have a pending cancellation. 3745891Sraf */ 3755891Sraf scp->sc_flgs &= ~SC_CANCEL_FLG; 3765891Sraf } else { 3775891Sraf scp->sc_flgs &= ~(SC_PARK_FLG | SC_CANCEL_FLG); 3785891Sraf /* 3795891Sraf * We are no longer parking; restore the 3805891Sraf * pending cancellation flag if necessary. 3815891Sraf */ 3825891Sraf if (self->ul_cancel_pending && 3835891Sraf !self->ul_cancel_disabled) 3845891Sraf scp->sc_flgs |= SC_CANCEL_FLG; 3855891Sraf } 3865891Sraf } else if (park == 0) { /* schedctl failed, do it the long way */ 3875891Sraf __lwp_unpark(self->ul_lwpid); 3885891Sraf } 3895891Sraf exit_critical(self); 3905891Sraf } 3915891Sraf 3925891Sraf /* 3935891Sraf * Test if the current thread is due to exit because of cancellation. 3945891Sraf */ 3955891Sraf int 3965891Sraf cancel_active(void) 3975891Sraf { 3985891Sraf ulwp_t *self = curthread; 3995891Sraf volatile sc_shared_t *scp; 4005891Sraf int exit_soon; 4015891Sraf 4025891Sraf /* 4035891Sraf * If there is a pending cancellation and cancellation 4045891Sraf * is not disabled (SC_CANCEL_FLG) and we received 4055891Sraf * EINTR from a recent system call (SC_EINTR_FLG), 4065891Sraf * then we will soon be exiting. 4075891Sraf */ 4085891Sraf enter_critical(self); 4095891Sraf exit_soon = 4105891Sraf (((scp = self->ul_schedctl) != NULL || 4115891Sraf (scp = setup_schedctl()) != NULL) && 4125891Sraf (scp->sc_flgs & (SC_CANCEL_FLG | SC_EINTR_FLG)) == 4135891Sraf (SC_CANCEL_FLG | SC_EINTR_FLG)); 4145891Sraf exit_critical(self); 4155891Sraf 4165891Sraf return (exit_soon); 4175891Sraf } 418