17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 547eb4d1eSsl108498 * Common Development and Distribution License (the "License"). 647eb4d1eSsl108498 * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 21*6eb30ec3SRoger A. Faulkner 227c478bd9Sstevel@tonic-gate /* 23*6eb30ec3SRoger A. Faulkner * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 287c478bd9Sstevel@tonic-gate 297c478bd9Sstevel@tonic-gate #include <sys/param.h> 307c478bd9Sstevel@tonic-gate #include <sys/types.h> 317c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 327c478bd9Sstevel@tonic-gate #include <sys/systm.h> 337c478bd9Sstevel@tonic-gate #include <sys/prsystm.h> 347c478bd9Sstevel@tonic-gate #include <sys/cred.h> 357c478bd9Sstevel@tonic-gate #include <sys/errno.h> 367c478bd9Sstevel@tonic-gate #include <sys/proc.h> 377c478bd9Sstevel@tonic-gate #include <sys/signal.h> 387c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 397c478bd9Sstevel@tonic-gate #include <sys/unistd.h> 407c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 417c478bd9Sstevel@tonic-gate #include <sys/schedctl.h> 427c478bd9Sstevel@tonic-gate #include <sys/debug.h> 437c478bd9Sstevel@tonic-gate #include <sys/contract/process_impl.h> 447c478bd9Sstevel@tonic-gate 457c478bd9Sstevel@tonic-gate kthread_t * 467c478bd9Sstevel@tonic-gate idtot(proc_t *p, id_t lwpid) 477c478bd9Sstevel@tonic-gate { 487c478bd9Sstevel@tonic-gate lwpdir_t *ldp; 497c478bd9Sstevel@tonic-gate 507c478bd9Sstevel@tonic-gate if ((ldp = lwp_hash_lookup(p, lwpid)) != NULL) 517c478bd9Sstevel@tonic-gate return (ldp->ld_entry->le_thread); 527c478bd9Sstevel@tonic-gate return (NULL); 537c478bd9Sstevel@tonic-gate } 547c478bd9Sstevel@tonic-gate 557c478bd9Sstevel@tonic-gate /* 56*6eb30ec3SRoger A. Faulkner * Same as idtot(), but acquire and return 57*6eb30ec3SRoger A. Faulkner * the tid hash table entry lock on success. 58*6eb30ec3SRoger A. Faulkner * This allows lwp_unpark() to do its job without acquiring 59*6eb30ec3SRoger A. Faulkner * p->p_lock (and thereby causing congestion problems when 60*6eb30ec3SRoger A. Faulkner * the application calls lwp_unpark() too often). 61*6eb30ec3SRoger A. Faulkner */ 62*6eb30ec3SRoger A. Faulkner static kthread_t * 63*6eb30ec3SRoger A. Faulkner idtot_and_lock(proc_t *p, id_t lwpid, kmutex_t **mpp) 64*6eb30ec3SRoger A. Faulkner { 65*6eb30ec3SRoger A. Faulkner lwpdir_t *ldp; 66*6eb30ec3SRoger A. Faulkner kthread_t *t; 67*6eb30ec3SRoger A. Faulkner 68*6eb30ec3SRoger A. Faulkner if ((ldp = lwp_hash_lookup_and_lock(p, lwpid, mpp)) != NULL) { 69*6eb30ec3SRoger A. Faulkner if ((t = ldp->ld_entry->le_thread) == NULL) 70*6eb30ec3SRoger A. Faulkner mutex_exit(*mpp); 71*6eb30ec3SRoger A. Faulkner return (t); 72*6eb30ec3SRoger A. Faulkner } 73*6eb30ec3SRoger A. Faulkner return (NULL); 74*6eb30ec3SRoger A. Faulkner } 75*6eb30ec3SRoger A. Faulkner 76*6eb30ec3SRoger A. Faulkner /* 777c478bd9Sstevel@tonic-gate * Stop an lwp of the current process 787c478bd9Sstevel@tonic-gate */ 797c478bd9Sstevel@tonic-gate int 807c478bd9Sstevel@tonic-gate syslwp_suspend(id_t lwpid) 817c478bd9Sstevel@tonic-gate { 827c478bd9Sstevel@tonic-gate kthread_t *t; 837c478bd9Sstevel@tonic-gate int error; 847c478bd9Sstevel@tonic-gate proc_t *p = ttoproc(curthread); 857c478bd9Sstevel@tonic-gate 867c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); 877c478bd9Sstevel@tonic-gate if ((t = idtot(p, lwpid)) == NULL) 887c478bd9Sstevel@tonic-gate error = ESRCH; 897c478bd9Sstevel@tonic-gate else 907c478bd9Sstevel@tonic-gate error = lwp_suspend(t); 917c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 927c478bd9Sstevel@tonic-gate if (error) 937c478bd9Sstevel@tonic-gate return (set_errno(error)); 947c478bd9Sstevel@tonic-gate return (0); 957c478bd9Sstevel@tonic-gate } 967c478bd9Sstevel@tonic-gate 977c478bd9Sstevel@tonic-gate int 987c478bd9Sstevel@tonic-gate syslwp_continue(id_t lwpid) 997c478bd9Sstevel@tonic-gate { 1007c478bd9Sstevel@tonic-gate kthread_t *t; 1017c478bd9Sstevel@tonic-gate proc_t *p = ttoproc(curthread); 1027c478bd9Sstevel@tonic-gate 1037c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); 1047c478bd9Sstevel@tonic-gate if ((t = idtot(p, lwpid)) == NULL) { 1057c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 1067c478bd9Sstevel@tonic-gate return (set_errno(ESRCH)); 1077c478bd9Sstevel@tonic-gate } 1087c478bd9Sstevel@tonic-gate lwp_continue(t); 1097c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 1107c478bd9Sstevel@tonic-gate return (0); 1117c478bd9Sstevel@tonic-gate } 1127c478bd9Sstevel@tonic-gate 1137c478bd9Sstevel@tonic-gate int 1147c478bd9Sstevel@tonic-gate lwp_kill(id_t lwpid, int sig) 1157c478bd9Sstevel@tonic-gate { 1167c478bd9Sstevel@tonic-gate sigqueue_t *sqp; 1177c478bd9Sstevel@tonic-gate kthread_t *t; 1187c478bd9Sstevel@tonic-gate proc_t *p = ttoproc(curthread); 1197c478bd9Sstevel@tonic-gate 1207c478bd9Sstevel@tonic-gate if (sig < 0 || sig >= NSIG) 1217c478bd9Sstevel@tonic-gate return (set_errno(EINVAL)); 1227c478bd9Sstevel@tonic-gate if (sig != 0) 1237c478bd9Sstevel@tonic-gate sqp = kmem_zalloc(sizeof (sigqueue_t), KM_SLEEP); 1247c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); 1257c478bd9Sstevel@tonic-gate if ((t = idtot(p, lwpid)) == NULL) { 1267c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 1277c478bd9Sstevel@tonic-gate if (sig != 0) 1287c478bd9Sstevel@tonic-gate kmem_free(sqp, sizeof (sigqueue_t)); 1297c478bd9Sstevel@tonic-gate return (set_errno(ESRCH)); 1307c478bd9Sstevel@tonic-gate } 1317c478bd9Sstevel@tonic-gate if (sig == 0) { 1327c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 1337c478bd9Sstevel@tonic-gate return (0); 1347c478bd9Sstevel@tonic-gate } 1357c478bd9Sstevel@tonic-gate sqp->sq_info.si_signo = sig; 1367c478bd9Sstevel@tonic-gate sqp->sq_info.si_code = SI_LWP; 1377c478bd9Sstevel@tonic-gate sqp->sq_info.si_pid = p->p_pid; 1387c478bd9Sstevel@tonic-gate sqp->sq_info.si_ctid = PRCTID(p); 1397c478bd9Sstevel@tonic-gate sqp->sq_info.si_zoneid = getzoneid(); 1407c478bd9Sstevel@tonic-gate sqp->sq_info.si_uid = crgetruid(CRED()); 1417c478bd9Sstevel@tonic-gate sigaddqa(p, t, sqp); 1427c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 1437c478bd9Sstevel@tonic-gate return (0); 1447c478bd9Sstevel@tonic-gate } 1457c478bd9Sstevel@tonic-gate 1467c478bd9Sstevel@tonic-gate /* 1477c478bd9Sstevel@tonic-gate * This is the specification of lwp_wait() from the _lwp_wait(2) manual page: 1487c478bd9Sstevel@tonic-gate * 1497c478bd9Sstevel@tonic-gate * The lwp_wait() function blocks the current lwp until the lwp specified 1507c478bd9Sstevel@tonic-gate * by 'lwpid' terminates. If the specified lwp terminated prior to the call 1517c478bd9Sstevel@tonic-gate * to lwp_wait(), then lwp_wait() returns immediately. If 'lwpid' is zero, 1527c478bd9Sstevel@tonic-gate * then lwp_wait() waits for any undetached lwp in the current process. 1537c478bd9Sstevel@tonic-gate * If 'lwpid' is not zero, then it must specify an undetached lwp in the 1547c478bd9Sstevel@tonic-gate * current process. If 'departed' is not NULL, then it points to a location 1557c478bd9Sstevel@tonic-gate * where the id of the exited lwp is stored. 1567c478bd9Sstevel@tonic-gate * 1577c478bd9Sstevel@tonic-gate * When an lwp exits and there are one or more lwps in the process waiting 1587c478bd9Sstevel@tonic-gate * for this specific lwp to exit, then one of the waiting lwps is unblocked 1597c478bd9Sstevel@tonic-gate * and it returns from lwp_wait() successfully. Any other lwps waiting for 1607c478bd9Sstevel@tonic-gate * this same lwp to exit are also unblocked, however, they return from 1617c478bd9Sstevel@tonic-gate * lwp_wait() with the error ESRCH. If there are no lwps in the process 1627c478bd9Sstevel@tonic-gate * waiting for this specific lwp to exit but there are one or more lwps 1637c478bd9Sstevel@tonic-gate * waiting for any lwp to exit, then one of the waiting lwps is unblocked 1647c478bd9Sstevel@tonic-gate * and it returns from lwp_wait() successfully. 1657c478bd9Sstevel@tonic-gate * 1667c478bd9Sstevel@tonic-gate * If an lwp is waiting for any lwp to exit, it blocks until an undetached 1677c478bd9Sstevel@tonic-gate * lwp for which no other lwp is waiting terminates, at which time it returns 1687c478bd9Sstevel@tonic-gate * successfully, or until all other lwps in the process are either daemon 1697c478bd9Sstevel@tonic-gate * lwps or lwps waiting in lwp_wait(), in which case it returns EDEADLK. 1707c478bd9Sstevel@tonic-gate */ 1717c478bd9Sstevel@tonic-gate int 1727c478bd9Sstevel@tonic-gate lwp_wait(id_t lwpid, id_t *departed) 1737c478bd9Sstevel@tonic-gate { 1747c478bd9Sstevel@tonic-gate proc_t *p = ttoproc(curthread); 1757c478bd9Sstevel@tonic-gate int error = 0; 1767c478bd9Sstevel@tonic-gate int daemon = (curthread->t_proc_flag & TP_DAEMON)? 1 : 0; 1777c478bd9Sstevel@tonic-gate lwpent_t *target_lep; 1787c478bd9Sstevel@tonic-gate lwpdir_t *ldp; 1797c478bd9Sstevel@tonic-gate lwpent_t *lep; 1807c478bd9Sstevel@tonic-gate 1817c478bd9Sstevel@tonic-gate /* 1827c478bd9Sstevel@tonic-gate * lwp_wait() is not supported for the /proc agent lwp. 1837c478bd9Sstevel@tonic-gate */ 1847c478bd9Sstevel@tonic-gate if (curthread == p->p_agenttp) 1857c478bd9Sstevel@tonic-gate return (set_errno(ENOTSUP)); 1867c478bd9Sstevel@tonic-gate 1877c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); 1887c478bd9Sstevel@tonic-gate prbarrier(p); 1897c478bd9Sstevel@tonic-gate 1907c478bd9Sstevel@tonic-gate curthread->t_waitfor = lwpid; 1917c478bd9Sstevel@tonic-gate p->p_lwpwait++; 1927c478bd9Sstevel@tonic-gate p->p_lwpdwait += daemon; 1937c478bd9Sstevel@tonic-gate 1947c478bd9Sstevel@tonic-gate if (lwpid != 0) { 1957c478bd9Sstevel@tonic-gate if ((ldp = lwp_hash_lookup(p, lwpid)) == NULL) 1967c478bd9Sstevel@tonic-gate target_lep = NULL; 1977c478bd9Sstevel@tonic-gate else { 1987c478bd9Sstevel@tonic-gate target_lep = ldp->ld_entry; 1997c478bd9Sstevel@tonic-gate target_lep->le_waiters++; 2007c478bd9Sstevel@tonic-gate target_lep->le_dwaiters += daemon; 2017c478bd9Sstevel@tonic-gate } 2027c478bd9Sstevel@tonic-gate } 2037c478bd9Sstevel@tonic-gate 2047c478bd9Sstevel@tonic-gate while (error == 0) { 2057c478bd9Sstevel@tonic-gate kthread_t *t; 2067c478bd9Sstevel@tonic-gate id_t tid; 2077c478bd9Sstevel@tonic-gate int i; 2087c478bd9Sstevel@tonic-gate 2097c478bd9Sstevel@tonic-gate if (lwpid != 0) { 2107c478bd9Sstevel@tonic-gate /* 2117c478bd9Sstevel@tonic-gate * Look for a specific zombie lwp. 2127c478bd9Sstevel@tonic-gate */ 2137c478bd9Sstevel@tonic-gate if (target_lep == NULL) 2147c478bd9Sstevel@tonic-gate error = ESRCH; 2157c478bd9Sstevel@tonic-gate else if ((t = target_lep->le_thread) != NULL) { 2167c478bd9Sstevel@tonic-gate if (!(t->t_proc_flag & TP_TWAIT)) 2177c478bd9Sstevel@tonic-gate error = EINVAL; 2187c478bd9Sstevel@tonic-gate } else { 2197c478bd9Sstevel@tonic-gate /* 2207c478bd9Sstevel@tonic-gate * We found the zombie we are waiting for. 2217c478bd9Sstevel@tonic-gate */ 2227c478bd9Sstevel@tonic-gate ASSERT(p->p_zombcnt > 0); 2237c478bd9Sstevel@tonic-gate p->p_zombcnt--; 2247c478bd9Sstevel@tonic-gate p->p_lwpwait--; 2257c478bd9Sstevel@tonic-gate p->p_lwpdwait -= daemon; 2267c478bd9Sstevel@tonic-gate curthread->t_waitfor = -1; 2277c478bd9Sstevel@tonic-gate lwp_hash_out(p, lwpid); 2287c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 2297c478bd9Sstevel@tonic-gate if (departed != NULL && 2307c478bd9Sstevel@tonic-gate copyout(&lwpid, departed, sizeof (id_t))) 2317c478bd9Sstevel@tonic-gate return (set_errno(EFAULT)); 2327c478bd9Sstevel@tonic-gate return (0); 2337c478bd9Sstevel@tonic-gate } 2347c478bd9Sstevel@tonic-gate } else { 2357c478bd9Sstevel@tonic-gate /* 2367c478bd9Sstevel@tonic-gate * Look for any zombie lwp. 2377c478bd9Sstevel@tonic-gate */ 2387c478bd9Sstevel@tonic-gate int some_non_daemon_will_return = 0; 2397c478bd9Sstevel@tonic-gate 2407c478bd9Sstevel@tonic-gate /* for each entry in the lwp directory... */ 2417c478bd9Sstevel@tonic-gate ldp = p->p_lwpdir; 2427c478bd9Sstevel@tonic-gate for (i = 0; i < p->p_lwpdir_sz; i++, ldp++) { 2437c478bd9Sstevel@tonic-gate 2447c478bd9Sstevel@tonic-gate if ((lep = ldp->ld_entry) == NULL || 2457c478bd9Sstevel@tonic-gate lep->le_thread != NULL) 2467c478bd9Sstevel@tonic-gate continue; 2477c478bd9Sstevel@tonic-gate 2487c478bd9Sstevel@tonic-gate /* 2497c478bd9Sstevel@tonic-gate * We found a zombie lwp. If there is some 2507c478bd9Sstevel@tonic-gate * other thread waiting specifically for the 2517c478bd9Sstevel@tonic-gate * zombie we just found, then defer to the other 2527c478bd9Sstevel@tonic-gate * waiting thread and continue searching for 2537c478bd9Sstevel@tonic-gate * another zombie. Also check to see if there 2547c478bd9Sstevel@tonic-gate * is some non-daemon thread sleeping here in 2557c478bd9Sstevel@tonic-gate * lwp_wait() that will succeed and return when 2567c478bd9Sstevel@tonic-gate * we drop p->p_lock. This is tested below. 2577c478bd9Sstevel@tonic-gate */ 2587c478bd9Sstevel@tonic-gate tid = lep->le_lwpid; 2597c478bd9Sstevel@tonic-gate if (lep->le_waiters != 0) { 2607c478bd9Sstevel@tonic-gate if (lep->le_waiters - lep->le_dwaiters) 2617c478bd9Sstevel@tonic-gate some_non_daemon_will_return = 1; 2627c478bd9Sstevel@tonic-gate continue; 2637c478bd9Sstevel@tonic-gate } 2647c478bd9Sstevel@tonic-gate 2657c478bd9Sstevel@tonic-gate /* 2667c478bd9Sstevel@tonic-gate * We found a zombie that no one else 2677c478bd9Sstevel@tonic-gate * is specifically waiting for. 2687c478bd9Sstevel@tonic-gate */ 2697c478bd9Sstevel@tonic-gate ASSERT(p->p_zombcnt > 0); 2707c478bd9Sstevel@tonic-gate p->p_zombcnt--; 2717c478bd9Sstevel@tonic-gate p->p_lwpwait--; 2727c478bd9Sstevel@tonic-gate p->p_lwpdwait -= daemon; 2737c478bd9Sstevel@tonic-gate curthread->t_waitfor = -1; 2747c478bd9Sstevel@tonic-gate lwp_hash_out(p, tid); 2757c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 2767c478bd9Sstevel@tonic-gate if (departed != NULL && 2777c478bd9Sstevel@tonic-gate copyout(&tid, departed, sizeof (id_t))) 2787c478bd9Sstevel@tonic-gate return (set_errno(EFAULT)); 2797c478bd9Sstevel@tonic-gate return (0); 2807c478bd9Sstevel@tonic-gate } 2817c478bd9Sstevel@tonic-gate 2827c478bd9Sstevel@tonic-gate /* 2837c478bd9Sstevel@tonic-gate * We are waiting for anyone. If all non-daemon lwps 2847c478bd9Sstevel@tonic-gate * are waiting here, and if we determined above that 2857c478bd9Sstevel@tonic-gate * no non-daemon lwp will return, we have deadlock. 2867c478bd9Sstevel@tonic-gate */ 2877c478bd9Sstevel@tonic-gate if (!some_non_daemon_will_return && 2887c478bd9Sstevel@tonic-gate p->p_lwpcnt == p->p_lwpdaemon + 2897c478bd9Sstevel@tonic-gate (p->p_lwpwait - p->p_lwpdwait)) 2907c478bd9Sstevel@tonic-gate error = EDEADLK; 2917c478bd9Sstevel@tonic-gate } 2927c478bd9Sstevel@tonic-gate 2937c478bd9Sstevel@tonic-gate if (error == 0 && lwpid != 0) { 2947c478bd9Sstevel@tonic-gate /* 2957c478bd9Sstevel@tonic-gate * We are waiting for a specific non-zombie lwp. 2967c478bd9Sstevel@tonic-gate * Fail if there is a deadlock loop. 2977c478bd9Sstevel@tonic-gate */ 2987c478bd9Sstevel@tonic-gate for (;;) { 2997c478bd9Sstevel@tonic-gate if (t == curthread) { 3007c478bd9Sstevel@tonic-gate error = EDEADLK; 3017c478bd9Sstevel@tonic-gate break; 3027c478bd9Sstevel@tonic-gate } 3037c478bd9Sstevel@tonic-gate /* who is he waiting for? */ 3047c478bd9Sstevel@tonic-gate if ((tid = t->t_waitfor) == -1) 3057c478bd9Sstevel@tonic-gate break; 3067c478bd9Sstevel@tonic-gate if (tid == 0) { 3077c478bd9Sstevel@tonic-gate /* 3087c478bd9Sstevel@tonic-gate * The lwp we are waiting for is 3097c478bd9Sstevel@tonic-gate * waiting for anyone (transitively). 3107c478bd9Sstevel@tonic-gate * If there are no zombies right now 3117c478bd9Sstevel@tonic-gate * and if we would have deadlock due 3127c478bd9Sstevel@tonic-gate * to all non-daemon lwps waiting here, 3137c478bd9Sstevel@tonic-gate * wake up the lwp that is waiting for 3147c478bd9Sstevel@tonic-gate * anyone so it can return EDEADLK. 3157c478bd9Sstevel@tonic-gate */ 3167c478bd9Sstevel@tonic-gate if (p->p_zombcnt == 0 && 3177c478bd9Sstevel@tonic-gate p->p_lwpcnt == p->p_lwpdaemon + 3187c478bd9Sstevel@tonic-gate p->p_lwpwait - p->p_lwpdwait) 3197c478bd9Sstevel@tonic-gate cv_broadcast(&p->p_lwpexit); 3207c478bd9Sstevel@tonic-gate break; 3217c478bd9Sstevel@tonic-gate } 3227c478bd9Sstevel@tonic-gate if ((ldp = lwp_hash_lookup(p, tid)) == NULL || 3237c478bd9Sstevel@tonic-gate (t = ldp->ld_entry->le_thread) == NULL) 3247c478bd9Sstevel@tonic-gate break; 3257c478bd9Sstevel@tonic-gate } 3267c478bd9Sstevel@tonic-gate } 3277c478bd9Sstevel@tonic-gate 3287c478bd9Sstevel@tonic-gate if (error) 3297c478bd9Sstevel@tonic-gate break; 3307c478bd9Sstevel@tonic-gate 3317c478bd9Sstevel@tonic-gate /* 3327c478bd9Sstevel@tonic-gate * Wait for some lwp to terminate. 3337c478bd9Sstevel@tonic-gate */ 3347c478bd9Sstevel@tonic-gate if (!cv_wait_sig(&p->p_lwpexit, &p->p_lock)) 3357c478bd9Sstevel@tonic-gate error = EINTR; 3367c478bd9Sstevel@tonic-gate prbarrier(p); 3377c478bd9Sstevel@tonic-gate 3387c478bd9Sstevel@tonic-gate if (lwpid != 0) { 3397c478bd9Sstevel@tonic-gate if ((ldp = lwp_hash_lookup(p, lwpid)) == NULL) 3407c478bd9Sstevel@tonic-gate target_lep = NULL; 3417c478bd9Sstevel@tonic-gate else 3427c478bd9Sstevel@tonic-gate target_lep = ldp->ld_entry; 3437c478bd9Sstevel@tonic-gate } 3447c478bd9Sstevel@tonic-gate } 3457c478bd9Sstevel@tonic-gate 3467c478bd9Sstevel@tonic-gate if (lwpid != 0 && target_lep != NULL) { 3477c478bd9Sstevel@tonic-gate target_lep->le_waiters--; 3487c478bd9Sstevel@tonic-gate target_lep->le_dwaiters -= daemon; 3497c478bd9Sstevel@tonic-gate } 3507c478bd9Sstevel@tonic-gate p->p_lwpwait--; 3517c478bd9Sstevel@tonic-gate p->p_lwpdwait -= daemon; 3527c478bd9Sstevel@tonic-gate curthread->t_waitfor = -1; 3537c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 3547c478bd9Sstevel@tonic-gate return (set_errno(error)); 3557c478bd9Sstevel@tonic-gate } 3567c478bd9Sstevel@tonic-gate 3577c478bd9Sstevel@tonic-gate int 3587c478bd9Sstevel@tonic-gate lwp_detach(id_t lwpid) 3597c478bd9Sstevel@tonic-gate { 3607c478bd9Sstevel@tonic-gate kthread_t *t; 3617c478bd9Sstevel@tonic-gate proc_t *p = ttoproc(curthread); 3627c478bd9Sstevel@tonic-gate lwpdir_t *ldp; 3637c478bd9Sstevel@tonic-gate int error = 0; 3647c478bd9Sstevel@tonic-gate 3657c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); 3667c478bd9Sstevel@tonic-gate prbarrier(p); 3677c478bd9Sstevel@tonic-gate if ((ldp = lwp_hash_lookup(p, lwpid)) == NULL) 3687c478bd9Sstevel@tonic-gate error = ESRCH; 3697c478bd9Sstevel@tonic-gate else if ((t = ldp->ld_entry->le_thread) != NULL) { 3707c478bd9Sstevel@tonic-gate if (!(t->t_proc_flag & TP_TWAIT)) 3717c478bd9Sstevel@tonic-gate error = EINVAL; 3727c478bd9Sstevel@tonic-gate else { 3737c478bd9Sstevel@tonic-gate t->t_proc_flag &= ~TP_TWAIT; 3747c478bd9Sstevel@tonic-gate cv_broadcast(&p->p_lwpexit); 3757c478bd9Sstevel@tonic-gate } 3767c478bd9Sstevel@tonic-gate } else { 3777c478bd9Sstevel@tonic-gate ASSERT(p->p_zombcnt > 0); 3787c478bd9Sstevel@tonic-gate p->p_zombcnt--; 3797c478bd9Sstevel@tonic-gate lwp_hash_out(p, lwpid); 3807c478bd9Sstevel@tonic-gate } 3817c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 3827c478bd9Sstevel@tonic-gate 3837c478bd9Sstevel@tonic-gate if (error) 3847c478bd9Sstevel@tonic-gate return (set_errno(error)); 3857c478bd9Sstevel@tonic-gate return (0); 3867c478bd9Sstevel@tonic-gate } 3877c478bd9Sstevel@tonic-gate 3887c478bd9Sstevel@tonic-gate /* 3897c478bd9Sstevel@tonic-gate * Unpark the specified lwp. 3907c478bd9Sstevel@tonic-gate */ 3917c478bd9Sstevel@tonic-gate static int 3927c478bd9Sstevel@tonic-gate lwp_unpark(id_t lwpid) 3937c478bd9Sstevel@tonic-gate { 3947c478bd9Sstevel@tonic-gate proc_t *p = ttoproc(curthread); 3957c478bd9Sstevel@tonic-gate kthread_t *t; 396*6eb30ec3SRoger A. Faulkner kmutex_t *mp; 3977c478bd9Sstevel@tonic-gate int error = 0; 3987c478bd9Sstevel@tonic-gate 399*6eb30ec3SRoger A. Faulkner if ((t = idtot_and_lock(p, lwpid, &mp)) == NULL) { 4007c478bd9Sstevel@tonic-gate error = ESRCH; 401*6eb30ec3SRoger A. Faulkner } else { 4027c478bd9Sstevel@tonic-gate mutex_enter(&t->t_delay_lock); 4037c478bd9Sstevel@tonic-gate t->t_unpark = 1; 4047c478bd9Sstevel@tonic-gate cv_signal(&t->t_delay_cv); 4057c478bd9Sstevel@tonic-gate mutex_exit(&t->t_delay_lock); 406*6eb30ec3SRoger A. Faulkner mutex_exit(mp); 4077c478bd9Sstevel@tonic-gate } 4087c478bd9Sstevel@tonic-gate return (error); 4097c478bd9Sstevel@tonic-gate } 4107c478bd9Sstevel@tonic-gate 4117c478bd9Sstevel@tonic-gate /* 41247eb4d1eSsl108498 * Cancel a previous unpark for the specified lwp. 41347eb4d1eSsl108498 * 41447eb4d1eSsl108498 * This interface exists ONLY to support older versions of libthread, which 41547eb4d1eSsl108498 * called lwp_unpark(self) to force calls to lwp_park(self) to return 41647eb4d1eSsl108498 * immediately. These older libthreads required a mechanism to cancel the 41747eb4d1eSsl108498 * lwp_unpark(self). 41847eb4d1eSsl108498 * 41947eb4d1eSsl108498 * libc does not call this interface. Instead, the sc_park flag in the 42047eb4d1eSsl108498 * schedctl page is cleared to force calls to lwp_park() to return 42147eb4d1eSsl108498 * immediately. 42247eb4d1eSsl108498 */ 42347eb4d1eSsl108498 static int 42447eb4d1eSsl108498 lwp_unpark_cancel(id_t lwpid) 42547eb4d1eSsl108498 { 42647eb4d1eSsl108498 proc_t *p = ttoproc(curthread); 42747eb4d1eSsl108498 kthread_t *t; 428*6eb30ec3SRoger A. Faulkner kmutex_t *mp; 42947eb4d1eSsl108498 int error = 0; 43047eb4d1eSsl108498 431*6eb30ec3SRoger A. Faulkner if ((t = idtot_and_lock(p, lwpid, &mp)) == NULL) { 43247eb4d1eSsl108498 error = ESRCH; 43347eb4d1eSsl108498 } else { 43447eb4d1eSsl108498 mutex_enter(&t->t_delay_lock); 43547eb4d1eSsl108498 t->t_unpark = 0; 43647eb4d1eSsl108498 mutex_exit(&t->t_delay_lock); 437*6eb30ec3SRoger A. Faulkner mutex_exit(mp); 43847eb4d1eSsl108498 } 43947eb4d1eSsl108498 return (error); 44047eb4d1eSsl108498 } 44147eb4d1eSsl108498 44247eb4d1eSsl108498 /* 4437c478bd9Sstevel@tonic-gate * Sleep until we are set running by lwp_unpark() or until we are 4447c478bd9Sstevel@tonic-gate * interrupted by a signal or until we exhaust our timeout. 4457c478bd9Sstevel@tonic-gate * timeoutp is an in/out parameter. On entry, it contains the relative 4467c478bd9Sstevel@tonic-gate * time until timeout. On exit, we copyout the residual time left to it. 4477c478bd9Sstevel@tonic-gate */ 4487c478bd9Sstevel@tonic-gate static int 4497c478bd9Sstevel@tonic-gate lwp_park(timespec_t *timeoutp, id_t lwpid) 4507c478bd9Sstevel@tonic-gate { 4517c478bd9Sstevel@tonic-gate timespec_t rqtime; 4527c478bd9Sstevel@tonic-gate timespec_t rmtime; 4537c478bd9Sstevel@tonic-gate timespec_t now; 4547c478bd9Sstevel@tonic-gate timespec_t *rqtp = NULL; 4557c478bd9Sstevel@tonic-gate kthread_t *t = curthread; 4563348528fSdm120769 int timecheck = 0; 4577c478bd9Sstevel@tonic-gate int error = 0; 4587c478bd9Sstevel@tonic-gate model_t datamodel = ttoproc(t)->p_model; 4597c478bd9Sstevel@tonic-gate 4607c478bd9Sstevel@tonic-gate if (lwpid != 0) /* unpark the other lwp, if any */ 4617c478bd9Sstevel@tonic-gate (void) lwp_unpark(lwpid); 4627c478bd9Sstevel@tonic-gate 4637c478bd9Sstevel@tonic-gate if (timeoutp) { 4643348528fSdm120769 timecheck = timechanged; 4657c478bd9Sstevel@tonic-gate gethrestime(&now); 4667c478bd9Sstevel@tonic-gate if (datamodel == DATAMODEL_NATIVE) { 4677c478bd9Sstevel@tonic-gate if (copyin(timeoutp, &rqtime, sizeof (timespec_t))) { 4687c478bd9Sstevel@tonic-gate error = EFAULT; 4697c478bd9Sstevel@tonic-gate goto out; 4707c478bd9Sstevel@tonic-gate } 4717c478bd9Sstevel@tonic-gate } else { 4727c478bd9Sstevel@tonic-gate timespec32_t timeout32; 4737c478bd9Sstevel@tonic-gate 4747c478bd9Sstevel@tonic-gate if (copyin(timeoutp, &timeout32, sizeof (timeout32))) { 4757c478bd9Sstevel@tonic-gate error = EFAULT; 4767c478bd9Sstevel@tonic-gate goto out; 4777c478bd9Sstevel@tonic-gate } 4787c478bd9Sstevel@tonic-gate TIMESPEC32_TO_TIMESPEC(&rqtime, &timeout32) 4797c478bd9Sstevel@tonic-gate } 4807c478bd9Sstevel@tonic-gate 4817c478bd9Sstevel@tonic-gate if (itimerspecfix(&rqtime)) { 4827c478bd9Sstevel@tonic-gate error = EINVAL; 4837c478bd9Sstevel@tonic-gate goto out; 4847c478bd9Sstevel@tonic-gate } 4857c478bd9Sstevel@tonic-gate /* 4867c478bd9Sstevel@tonic-gate * Convert the timespec value into absolute time. 4877c478bd9Sstevel@tonic-gate */ 4887c478bd9Sstevel@tonic-gate timespecadd(&rqtime, &now); 4897c478bd9Sstevel@tonic-gate rqtp = &rqtime; 4907c478bd9Sstevel@tonic-gate } 4917c478bd9Sstevel@tonic-gate 4927c478bd9Sstevel@tonic-gate (void) new_mstate(t, LMS_USER_LOCK); 4937c478bd9Sstevel@tonic-gate 4947c478bd9Sstevel@tonic-gate mutex_enter(&t->t_delay_lock); 4957c478bd9Sstevel@tonic-gate if (!schedctl_is_park()) 4967c478bd9Sstevel@tonic-gate error = EINTR; 4977c478bd9Sstevel@tonic-gate while (error == 0 && t->t_unpark == 0) { 4987c478bd9Sstevel@tonic-gate switch (cv_waituntil_sig(&t->t_delay_cv, 4993348528fSdm120769 &t->t_delay_lock, rqtp, timecheck)) { 5007c478bd9Sstevel@tonic-gate case 0: 5017c478bd9Sstevel@tonic-gate error = EINTR; 5027c478bd9Sstevel@tonic-gate break; 5037c478bd9Sstevel@tonic-gate case -1: 5047c478bd9Sstevel@tonic-gate error = ETIME; 5057c478bd9Sstevel@tonic-gate break; 5067c478bd9Sstevel@tonic-gate } 5077c478bd9Sstevel@tonic-gate } 5087c478bd9Sstevel@tonic-gate t->t_unpark = 0; 5097c478bd9Sstevel@tonic-gate mutex_exit(&t->t_delay_lock); 5107c478bd9Sstevel@tonic-gate 5117c478bd9Sstevel@tonic-gate if (timeoutp != NULL) { 5127c478bd9Sstevel@tonic-gate rmtime.tv_sec = rmtime.tv_nsec = 0; 5137c478bd9Sstevel@tonic-gate if (error != ETIME) { 5147c478bd9Sstevel@tonic-gate gethrestime(&now); 5157c478bd9Sstevel@tonic-gate if ((now.tv_sec < rqtime.tv_sec) || 5167c478bd9Sstevel@tonic-gate ((now.tv_sec == rqtime.tv_sec) && 5177c478bd9Sstevel@tonic-gate (now.tv_nsec < rqtime.tv_nsec))) { 5187c478bd9Sstevel@tonic-gate rmtime = rqtime; 5197c478bd9Sstevel@tonic-gate timespecsub(&rmtime, &now); 5207c478bd9Sstevel@tonic-gate } 5217c478bd9Sstevel@tonic-gate } 5227c478bd9Sstevel@tonic-gate if (datamodel == DATAMODEL_NATIVE) { 5237c478bd9Sstevel@tonic-gate if (copyout(&rmtime, timeoutp, sizeof (rmtime))) 5247c478bd9Sstevel@tonic-gate error = EFAULT; 5257c478bd9Sstevel@tonic-gate } else { 5267c478bd9Sstevel@tonic-gate timespec32_t rmtime32; 5277c478bd9Sstevel@tonic-gate 5287c478bd9Sstevel@tonic-gate TIMESPEC_TO_TIMESPEC32(&rmtime32, &rmtime); 5297c478bd9Sstevel@tonic-gate if (copyout(&rmtime32, timeoutp, sizeof (rmtime32))) 5307c478bd9Sstevel@tonic-gate error = EFAULT; 5317c478bd9Sstevel@tonic-gate } 5327c478bd9Sstevel@tonic-gate } 5337c478bd9Sstevel@tonic-gate out: 5347c478bd9Sstevel@tonic-gate schedctl_unpark(); 5357c478bd9Sstevel@tonic-gate if (t->t_mstate == LMS_USER_LOCK) 5367c478bd9Sstevel@tonic-gate (void) new_mstate(t, LMS_SYSTEM); 5377c478bd9Sstevel@tonic-gate return (error); 5387c478bd9Sstevel@tonic-gate } 5397c478bd9Sstevel@tonic-gate 5407c478bd9Sstevel@tonic-gate #define MAXLWPIDS 1024 5417c478bd9Sstevel@tonic-gate 5427c478bd9Sstevel@tonic-gate /* 5437c478bd9Sstevel@tonic-gate * Unpark all of the specified lwps. 5447c478bd9Sstevel@tonic-gate * Do it in chunks of MAXLWPIDS to avoid allocating too much memory. 5457c478bd9Sstevel@tonic-gate */ 5467c478bd9Sstevel@tonic-gate static int 5477c478bd9Sstevel@tonic-gate lwp_unpark_all(id_t *lwpidp, int nids) 5487c478bd9Sstevel@tonic-gate { 5497c478bd9Sstevel@tonic-gate proc_t *p = ttoproc(curthread); 5507c478bd9Sstevel@tonic-gate kthread_t *t; 551*6eb30ec3SRoger A. Faulkner kmutex_t *mp; 5527c478bd9Sstevel@tonic-gate int error = 0; 5537c478bd9Sstevel@tonic-gate id_t *lwpid; 5547c478bd9Sstevel@tonic-gate size_t lwpidsz; 5557c478bd9Sstevel@tonic-gate int n; 5567c478bd9Sstevel@tonic-gate int i; 5577c478bd9Sstevel@tonic-gate 5587c478bd9Sstevel@tonic-gate if (nids <= 0) 5597c478bd9Sstevel@tonic-gate return (EINVAL); 5607c478bd9Sstevel@tonic-gate 5617c478bd9Sstevel@tonic-gate lwpidsz = MIN(nids, MAXLWPIDS) * sizeof (id_t); 5627c478bd9Sstevel@tonic-gate lwpid = kmem_alloc(lwpidsz, KM_SLEEP); 5637c478bd9Sstevel@tonic-gate while (nids > 0) { 5647c478bd9Sstevel@tonic-gate n = MIN(nids, MAXLWPIDS); 5657c478bd9Sstevel@tonic-gate if (copyin(lwpidp, lwpid, n * sizeof (id_t))) { 5667c478bd9Sstevel@tonic-gate error = EFAULT; 5677c478bd9Sstevel@tonic-gate break; 5687c478bd9Sstevel@tonic-gate } 5697c478bd9Sstevel@tonic-gate for (i = 0; i < n; i++) { 570*6eb30ec3SRoger A. Faulkner if ((t = idtot_and_lock(p, lwpid[i], &mp)) == NULL) { 5717c478bd9Sstevel@tonic-gate error = ESRCH; 572*6eb30ec3SRoger A. Faulkner } else { 5737c478bd9Sstevel@tonic-gate mutex_enter(&t->t_delay_lock); 5747c478bd9Sstevel@tonic-gate t->t_unpark = 1; 5757c478bd9Sstevel@tonic-gate cv_signal(&t->t_delay_cv); 5767c478bd9Sstevel@tonic-gate mutex_exit(&t->t_delay_lock); 577*6eb30ec3SRoger A. Faulkner mutex_exit(mp); 5787c478bd9Sstevel@tonic-gate } 5797c478bd9Sstevel@tonic-gate } 5807c478bd9Sstevel@tonic-gate lwpidp += n; 5817c478bd9Sstevel@tonic-gate nids -= n; 5827c478bd9Sstevel@tonic-gate } 5837c478bd9Sstevel@tonic-gate kmem_free(lwpid, lwpidsz); 5847c478bd9Sstevel@tonic-gate return (error); 5857c478bd9Sstevel@tonic-gate } 5867c478bd9Sstevel@tonic-gate 5877c478bd9Sstevel@tonic-gate /* 5887c478bd9Sstevel@tonic-gate * SYS_lwp_park() system call. 5897c478bd9Sstevel@tonic-gate */ 5907c478bd9Sstevel@tonic-gate int 5917c478bd9Sstevel@tonic-gate syslwp_park(int which, uintptr_t arg1, uintptr_t arg2) 5927c478bd9Sstevel@tonic-gate { 5937c478bd9Sstevel@tonic-gate int error; 5947c478bd9Sstevel@tonic-gate 5957c478bd9Sstevel@tonic-gate switch (which) { 5967c478bd9Sstevel@tonic-gate case 0: 5977c478bd9Sstevel@tonic-gate error = lwp_park((timespec_t *)arg1, (id_t)arg2); 5987c478bd9Sstevel@tonic-gate break; 5997c478bd9Sstevel@tonic-gate case 1: 6007c478bd9Sstevel@tonic-gate error = lwp_unpark((id_t)arg1); 6017c478bd9Sstevel@tonic-gate break; 6027c478bd9Sstevel@tonic-gate case 2: 6037c478bd9Sstevel@tonic-gate error = lwp_unpark_all((id_t *)arg1, (int)arg2); 6047c478bd9Sstevel@tonic-gate break; 60547eb4d1eSsl108498 case 3: 60647eb4d1eSsl108498 /* 60747eb4d1eSsl108498 * This subcode is not used by libc. It exists ONLY to 60847eb4d1eSsl108498 * support older versions of libthread which do not use 60947eb4d1eSsl108498 * the sc_park flag in the schedctl page. 61047eb4d1eSsl108498 * 61147eb4d1eSsl108498 * These versions of libthread need to be modifed or emulated 61247eb4d1eSsl108498 * to change calls to syslwp_park(1, tid, 0) to 61347eb4d1eSsl108498 * syslwp_park(3, tid). 61447eb4d1eSsl108498 */ 61547eb4d1eSsl108498 error = lwp_unpark_cancel((id_t)arg1); 61647eb4d1eSsl108498 break; 61747eb4d1eSsl108498 case 4: 61847eb4d1eSsl108498 /* 61947eb4d1eSsl108498 * This subcode is not used by libc. It exists ONLY to 62047eb4d1eSsl108498 * support older versions of libthread which do not use 62147eb4d1eSsl108498 * the sc_park flag in the schedctl page. 62247eb4d1eSsl108498 * 62347eb4d1eSsl108498 * These versions of libthread need to be modified or emulated 62447eb4d1eSsl108498 * to change calls to syslwp_park(0, ts, tid) to 62547eb4d1eSsl108498 * syslwp_park(4, ts, tid). 62647eb4d1eSsl108498 */ 62747eb4d1eSsl108498 schedctl_set_park(); 62847eb4d1eSsl108498 error = lwp_park((timespec_t *)arg1, (id_t)arg2); 62947eb4d1eSsl108498 break; 6307c478bd9Sstevel@tonic-gate default: 6317c478bd9Sstevel@tonic-gate error = EINVAL; 6327c478bd9Sstevel@tonic-gate break; 6337c478bd9Sstevel@tonic-gate } 6347c478bd9Sstevel@tonic-gate 6357c478bd9Sstevel@tonic-gate if (error) 6367c478bd9Sstevel@tonic-gate return (set_errno(error)); 6377c478bd9Sstevel@tonic-gate return (0); 6387c478bd9Sstevel@tonic-gate } 639