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 5*3348528fSdm120769 * Common Development and Distribution License, Version 1.0 only 6*3348528fSdm120769 * (the "License"). You may not use this file except in compliance 7*3348528fSdm120769 * with the License. 87c478bd9Sstevel@tonic-gate * 97c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 107c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 117c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 127c478bd9Sstevel@tonic-gate * and limitations under the License. 137c478bd9Sstevel@tonic-gate * 147c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 157c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 167c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 177c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 187c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 197c478bd9Sstevel@tonic-gate * 207c478bd9Sstevel@tonic-gate * CDDL HEADER END 217c478bd9Sstevel@tonic-gate */ 227c478bd9Sstevel@tonic-gate /* 23*3348528fSdm120769 * Copyright 2004 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 #pragma ident "%Z%%M% %I% %E% SMI" 307c478bd9Sstevel@tonic-gate 317c478bd9Sstevel@tonic-gate #include <sys/param.h> 327c478bd9Sstevel@tonic-gate #include <sys/types.h> 337c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 347c478bd9Sstevel@tonic-gate #include <sys/systm.h> 357c478bd9Sstevel@tonic-gate #include <sys/prsystm.h> 367c478bd9Sstevel@tonic-gate #include <sys/cred.h> 377c478bd9Sstevel@tonic-gate #include <sys/errno.h> 387c478bd9Sstevel@tonic-gate #include <sys/proc.h> 397c478bd9Sstevel@tonic-gate #include <sys/signal.h> 407c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 417c478bd9Sstevel@tonic-gate #include <sys/unistd.h> 427c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 437c478bd9Sstevel@tonic-gate #include <sys/schedctl.h> 447c478bd9Sstevel@tonic-gate #include <sys/debug.h> 457c478bd9Sstevel@tonic-gate #include <sys/contract/process_impl.h> 467c478bd9Sstevel@tonic-gate 477c478bd9Sstevel@tonic-gate kthread_t * 487c478bd9Sstevel@tonic-gate idtot(proc_t *p, id_t lwpid) 497c478bd9Sstevel@tonic-gate { 507c478bd9Sstevel@tonic-gate lwpdir_t *ldp; 517c478bd9Sstevel@tonic-gate 527c478bd9Sstevel@tonic-gate if ((ldp = lwp_hash_lookup(p, lwpid)) != NULL) 537c478bd9Sstevel@tonic-gate return (ldp->ld_entry->le_thread); 547c478bd9Sstevel@tonic-gate return (NULL); 557c478bd9Sstevel@tonic-gate } 567c478bd9Sstevel@tonic-gate 577c478bd9Sstevel@tonic-gate /* 587c478bd9Sstevel@tonic-gate * Stop an lwp of the current process 597c478bd9Sstevel@tonic-gate */ 607c478bd9Sstevel@tonic-gate int 617c478bd9Sstevel@tonic-gate syslwp_suspend(id_t lwpid) 627c478bd9Sstevel@tonic-gate { 637c478bd9Sstevel@tonic-gate kthread_t *t; 647c478bd9Sstevel@tonic-gate int error; 657c478bd9Sstevel@tonic-gate proc_t *p = ttoproc(curthread); 667c478bd9Sstevel@tonic-gate 677c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); 687c478bd9Sstevel@tonic-gate if ((t = idtot(p, lwpid)) == NULL) 697c478bd9Sstevel@tonic-gate error = ESRCH; 707c478bd9Sstevel@tonic-gate else 717c478bd9Sstevel@tonic-gate error = lwp_suspend(t); 727c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 737c478bd9Sstevel@tonic-gate if (error) 747c478bd9Sstevel@tonic-gate return (set_errno(error)); 757c478bd9Sstevel@tonic-gate return (0); 767c478bd9Sstevel@tonic-gate } 777c478bd9Sstevel@tonic-gate 787c478bd9Sstevel@tonic-gate int 797c478bd9Sstevel@tonic-gate syslwp_continue(id_t lwpid) 807c478bd9Sstevel@tonic-gate { 817c478bd9Sstevel@tonic-gate kthread_t *t; 827c478bd9Sstevel@tonic-gate proc_t *p = ttoproc(curthread); 837c478bd9Sstevel@tonic-gate 847c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); 857c478bd9Sstevel@tonic-gate if ((t = idtot(p, lwpid)) == NULL) { 867c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 877c478bd9Sstevel@tonic-gate return (set_errno(ESRCH)); 887c478bd9Sstevel@tonic-gate } 897c478bd9Sstevel@tonic-gate lwp_continue(t); 907c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 917c478bd9Sstevel@tonic-gate return (0); 927c478bd9Sstevel@tonic-gate } 937c478bd9Sstevel@tonic-gate 947c478bd9Sstevel@tonic-gate int 957c478bd9Sstevel@tonic-gate lwp_kill(id_t lwpid, int sig) 967c478bd9Sstevel@tonic-gate { 977c478bd9Sstevel@tonic-gate sigqueue_t *sqp; 987c478bd9Sstevel@tonic-gate kthread_t *t; 997c478bd9Sstevel@tonic-gate proc_t *p = ttoproc(curthread); 1007c478bd9Sstevel@tonic-gate 1017c478bd9Sstevel@tonic-gate if (sig < 0 || sig >= NSIG) 1027c478bd9Sstevel@tonic-gate return (set_errno(EINVAL)); 1037c478bd9Sstevel@tonic-gate if (sig != 0) 1047c478bd9Sstevel@tonic-gate sqp = kmem_zalloc(sizeof (sigqueue_t), KM_SLEEP); 1057c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); 1067c478bd9Sstevel@tonic-gate if ((t = idtot(p, lwpid)) == NULL) { 1077c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 1087c478bd9Sstevel@tonic-gate if (sig != 0) 1097c478bd9Sstevel@tonic-gate kmem_free(sqp, sizeof (sigqueue_t)); 1107c478bd9Sstevel@tonic-gate return (set_errno(ESRCH)); 1117c478bd9Sstevel@tonic-gate } 1127c478bd9Sstevel@tonic-gate if (sig == 0) { 1137c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 1147c478bd9Sstevel@tonic-gate return (0); 1157c478bd9Sstevel@tonic-gate } 1167c478bd9Sstevel@tonic-gate sqp->sq_info.si_signo = sig; 1177c478bd9Sstevel@tonic-gate sqp->sq_info.si_code = SI_LWP; 1187c478bd9Sstevel@tonic-gate sqp->sq_info.si_pid = p->p_pid; 1197c478bd9Sstevel@tonic-gate sqp->sq_info.si_ctid = PRCTID(p); 1207c478bd9Sstevel@tonic-gate sqp->sq_info.si_zoneid = getzoneid(); 1217c478bd9Sstevel@tonic-gate sqp->sq_info.si_uid = crgetruid(CRED()); 1227c478bd9Sstevel@tonic-gate sigaddqa(p, t, sqp); 1237c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 1247c478bd9Sstevel@tonic-gate return (0); 1257c478bd9Sstevel@tonic-gate } 1267c478bd9Sstevel@tonic-gate 1277c478bd9Sstevel@tonic-gate /* 1287c478bd9Sstevel@tonic-gate * This is the specification of lwp_wait() from the _lwp_wait(2) manual page: 1297c478bd9Sstevel@tonic-gate * 1307c478bd9Sstevel@tonic-gate * The lwp_wait() function blocks the current lwp until the lwp specified 1317c478bd9Sstevel@tonic-gate * by 'lwpid' terminates. If the specified lwp terminated prior to the call 1327c478bd9Sstevel@tonic-gate * to lwp_wait(), then lwp_wait() returns immediately. If 'lwpid' is zero, 1337c478bd9Sstevel@tonic-gate * then lwp_wait() waits for any undetached lwp in the current process. 1347c478bd9Sstevel@tonic-gate * If 'lwpid' is not zero, then it must specify an undetached lwp in the 1357c478bd9Sstevel@tonic-gate * current process. If 'departed' is not NULL, then it points to a location 1367c478bd9Sstevel@tonic-gate * where the id of the exited lwp is stored. 1377c478bd9Sstevel@tonic-gate * 1387c478bd9Sstevel@tonic-gate * When an lwp exits and there are one or more lwps in the process waiting 1397c478bd9Sstevel@tonic-gate * for this specific lwp to exit, then one of the waiting lwps is unblocked 1407c478bd9Sstevel@tonic-gate * and it returns from lwp_wait() successfully. Any other lwps waiting for 1417c478bd9Sstevel@tonic-gate * this same lwp to exit are also unblocked, however, they return from 1427c478bd9Sstevel@tonic-gate * lwp_wait() with the error ESRCH. If there are no lwps in the process 1437c478bd9Sstevel@tonic-gate * waiting for this specific lwp to exit but there are one or more lwps 1447c478bd9Sstevel@tonic-gate * waiting for any lwp to exit, then one of the waiting lwps is unblocked 1457c478bd9Sstevel@tonic-gate * and it returns from lwp_wait() successfully. 1467c478bd9Sstevel@tonic-gate * 1477c478bd9Sstevel@tonic-gate * If an lwp is waiting for any lwp to exit, it blocks until an undetached 1487c478bd9Sstevel@tonic-gate * lwp for which no other lwp is waiting terminates, at which time it returns 1497c478bd9Sstevel@tonic-gate * successfully, or until all other lwps in the process are either daemon 1507c478bd9Sstevel@tonic-gate * lwps or lwps waiting in lwp_wait(), in which case it returns EDEADLK. 1517c478bd9Sstevel@tonic-gate */ 1527c478bd9Sstevel@tonic-gate int 1537c478bd9Sstevel@tonic-gate lwp_wait(id_t lwpid, id_t *departed) 1547c478bd9Sstevel@tonic-gate { 1557c478bd9Sstevel@tonic-gate proc_t *p = ttoproc(curthread); 1567c478bd9Sstevel@tonic-gate int error = 0; 1577c478bd9Sstevel@tonic-gate int daemon = (curthread->t_proc_flag & TP_DAEMON)? 1 : 0; 1587c478bd9Sstevel@tonic-gate lwpent_t *target_lep; 1597c478bd9Sstevel@tonic-gate lwpdir_t *ldp; 1607c478bd9Sstevel@tonic-gate lwpent_t *lep; 1617c478bd9Sstevel@tonic-gate 1627c478bd9Sstevel@tonic-gate /* 1637c478bd9Sstevel@tonic-gate * lwp_wait() is not supported for the /proc agent lwp. 1647c478bd9Sstevel@tonic-gate */ 1657c478bd9Sstevel@tonic-gate if (curthread == p->p_agenttp) 1667c478bd9Sstevel@tonic-gate return (set_errno(ENOTSUP)); 1677c478bd9Sstevel@tonic-gate 1687c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); 1697c478bd9Sstevel@tonic-gate prbarrier(p); 1707c478bd9Sstevel@tonic-gate 1717c478bd9Sstevel@tonic-gate curthread->t_waitfor = lwpid; 1727c478bd9Sstevel@tonic-gate p->p_lwpwait++; 1737c478bd9Sstevel@tonic-gate p->p_lwpdwait += daemon; 1747c478bd9Sstevel@tonic-gate 1757c478bd9Sstevel@tonic-gate if (lwpid != 0) { 1767c478bd9Sstevel@tonic-gate if ((ldp = lwp_hash_lookup(p, lwpid)) == NULL) 1777c478bd9Sstevel@tonic-gate target_lep = NULL; 1787c478bd9Sstevel@tonic-gate else { 1797c478bd9Sstevel@tonic-gate target_lep = ldp->ld_entry; 1807c478bd9Sstevel@tonic-gate target_lep->le_waiters++; 1817c478bd9Sstevel@tonic-gate target_lep->le_dwaiters += daemon; 1827c478bd9Sstevel@tonic-gate } 1837c478bd9Sstevel@tonic-gate } 1847c478bd9Sstevel@tonic-gate 1857c478bd9Sstevel@tonic-gate while (error == 0) { 1867c478bd9Sstevel@tonic-gate kthread_t *t; 1877c478bd9Sstevel@tonic-gate id_t tid; 1887c478bd9Sstevel@tonic-gate int i; 1897c478bd9Sstevel@tonic-gate 1907c478bd9Sstevel@tonic-gate if (lwpid != 0) { 1917c478bd9Sstevel@tonic-gate /* 1927c478bd9Sstevel@tonic-gate * Look for a specific zombie lwp. 1937c478bd9Sstevel@tonic-gate */ 1947c478bd9Sstevel@tonic-gate if (target_lep == NULL) 1957c478bd9Sstevel@tonic-gate error = ESRCH; 1967c478bd9Sstevel@tonic-gate else if ((t = target_lep->le_thread) != NULL) { 1977c478bd9Sstevel@tonic-gate if (!(t->t_proc_flag & TP_TWAIT)) 1987c478bd9Sstevel@tonic-gate error = EINVAL; 1997c478bd9Sstevel@tonic-gate } else { 2007c478bd9Sstevel@tonic-gate /* 2017c478bd9Sstevel@tonic-gate * We found the zombie we are waiting for. 2027c478bd9Sstevel@tonic-gate */ 2037c478bd9Sstevel@tonic-gate ASSERT(p->p_zombcnt > 0); 2047c478bd9Sstevel@tonic-gate p->p_zombcnt--; 2057c478bd9Sstevel@tonic-gate p->p_lwpwait--; 2067c478bd9Sstevel@tonic-gate p->p_lwpdwait -= daemon; 2077c478bd9Sstevel@tonic-gate curthread->t_waitfor = -1; 2087c478bd9Sstevel@tonic-gate lwp_hash_out(p, lwpid); 2097c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 2107c478bd9Sstevel@tonic-gate if (departed != NULL && 2117c478bd9Sstevel@tonic-gate copyout(&lwpid, departed, sizeof (id_t))) 2127c478bd9Sstevel@tonic-gate return (set_errno(EFAULT)); 2137c478bd9Sstevel@tonic-gate return (0); 2147c478bd9Sstevel@tonic-gate } 2157c478bd9Sstevel@tonic-gate } else { 2167c478bd9Sstevel@tonic-gate /* 2177c478bd9Sstevel@tonic-gate * Look for any zombie lwp. 2187c478bd9Sstevel@tonic-gate */ 2197c478bd9Sstevel@tonic-gate int some_non_daemon_will_return = 0; 2207c478bd9Sstevel@tonic-gate 2217c478bd9Sstevel@tonic-gate /* for each entry in the lwp directory... */ 2227c478bd9Sstevel@tonic-gate ldp = p->p_lwpdir; 2237c478bd9Sstevel@tonic-gate for (i = 0; i < p->p_lwpdir_sz; i++, ldp++) { 2247c478bd9Sstevel@tonic-gate 2257c478bd9Sstevel@tonic-gate if ((lep = ldp->ld_entry) == NULL || 2267c478bd9Sstevel@tonic-gate lep->le_thread != NULL) 2277c478bd9Sstevel@tonic-gate continue; 2287c478bd9Sstevel@tonic-gate 2297c478bd9Sstevel@tonic-gate /* 2307c478bd9Sstevel@tonic-gate * We found a zombie lwp. If there is some 2317c478bd9Sstevel@tonic-gate * other thread waiting specifically for the 2327c478bd9Sstevel@tonic-gate * zombie we just found, then defer to the other 2337c478bd9Sstevel@tonic-gate * waiting thread and continue searching for 2347c478bd9Sstevel@tonic-gate * another zombie. Also check to see if there 2357c478bd9Sstevel@tonic-gate * is some non-daemon thread sleeping here in 2367c478bd9Sstevel@tonic-gate * lwp_wait() that will succeed and return when 2377c478bd9Sstevel@tonic-gate * we drop p->p_lock. This is tested below. 2387c478bd9Sstevel@tonic-gate */ 2397c478bd9Sstevel@tonic-gate tid = lep->le_lwpid; 2407c478bd9Sstevel@tonic-gate if (lep->le_waiters != 0) { 2417c478bd9Sstevel@tonic-gate if (lep->le_waiters - lep->le_dwaiters) 2427c478bd9Sstevel@tonic-gate some_non_daemon_will_return = 1; 2437c478bd9Sstevel@tonic-gate continue; 2447c478bd9Sstevel@tonic-gate } 2457c478bd9Sstevel@tonic-gate 2467c478bd9Sstevel@tonic-gate /* 2477c478bd9Sstevel@tonic-gate * We found a zombie that no one else 2487c478bd9Sstevel@tonic-gate * is specifically waiting for. 2497c478bd9Sstevel@tonic-gate */ 2507c478bd9Sstevel@tonic-gate ASSERT(p->p_zombcnt > 0); 2517c478bd9Sstevel@tonic-gate p->p_zombcnt--; 2527c478bd9Sstevel@tonic-gate p->p_lwpwait--; 2537c478bd9Sstevel@tonic-gate p->p_lwpdwait -= daemon; 2547c478bd9Sstevel@tonic-gate curthread->t_waitfor = -1; 2557c478bd9Sstevel@tonic-gate lwp_hash_out(p, tid); 2567c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 2577c478bd9Sstevel@tonic-gate if (departed != NULL && 2587c478bd9Sstevel@tonic-gate copyout(&tid, departed, sizeof (id_t))) 2597c478bd9Sstevel@tonic-gate return (set_errno(EFAULT)); 2607c478bd9Sstevel@tonic-gate return (0); 2617c478bd9Sstevel@tonic-gate } 2627c478bd9Sstevel@tonic-gate 2637c478bd9Sstevel@tonic-gate /* 2647c478bd9Sstevel@tonic-gate * We are waiting for anyone. If all non-daemon lwps 2657c478bd9Sstevel@tonic-gate * are waiting here, and if we determined above that 2667c478bd9Sstevel@tonic-gate * no non-daemon lwp will return, we have deadlock. 2677c478bd9Sstevel@tonic-gate */ 2687c478bd9Sstevel@tonic-gate if (!some_non_daemon_will_return && 2697c478bd9Sstevel@tonic-gate p->p_lwpcnt == p->p_lwpdaemon + 2707c478bd9Sstevel@tonic-gate (p->p_lwpwait - p->p_lwpdwait)) 2717c478bd9Sstevel@tonic-gate error = EDEADLK; 2727c478bd9Sstevel@tonic-gate } 2737c478bd9Sstevel@tonic-gate 2747c478bd9Sstevel@tonic-gate if (error == 0 && lwpid != 0) { 2757c478bd9Sstevel@tonic-gate /* 2767c478bd9Sstevel@tonic-gate * We are waiting for a specific non-zombie lwp. 2777c478bd9Sstevel@tonic-gate * Fail if there is a deadlock loop. 2787c478bd9Sstevel@tonic-gate */ 2797c478bd9Sstevel@tonic-gate for (;;) { 2807c478bd9Sstevel@tonic-gate if (t == curthread) { 2817c478bd9Sstevel@tonic-gate error = EDEADLK; 2827c478bd9Sstevel@tonic-gate break; 2837c478bd9Sstevel@tonic-gate } 2847c478bd9Sstevel@tonic-gate /* who is he waiting for? */ 2857c478bd9Sstevel@tonic-gate if ((tid = t->t_waitfor) == -1) 2867c478bd9Sstevel@tonic-gate break; 2877c478bd9Sstevel@tonic-gate if (tid == 0) { 2887c478bd9Sstevel@tonic-gate /* 2897c478bd9Sstevel@tonic-gate * The lwp we are waiting for is 2907c478bd9Sstevel@tonic-gate * waiting for anyone (transitively). 2917c478bd9Sstevel@tonic-gate * If there are no zombies right now 2927c478bd9Sstevel@tonic-gate * and if we would have deadlock due 2937c478bd9Sstevel@tonic-gate * to all non-daemon lwps waiting here, 2947c478bd9Sstevel@tonic-gate * wake up the lwp that is waiting for 2957c478bd9Sstevel@tonic-gate * anyone so it can return EDEADLK. 2967c478bd9Sstevel@tonic-gate */ 2977c478bd9Sstevel@tonic-gate if (p->p_zombcnt == 0 && 2987c478bd9Sstevel@tonic-gate p->p_lwpcnt == p->p_lwpdaemon + 2997c478bd9Sstevel@tonic-gate p->p_lwpwait - p->p_lwpdwait) 3007c478bd9Sstevel@tonic-gate cv_broadcast(&p->p_lwpexit); 3017c478bd9Sstevel@tonic-gate break; 3027c478bd9Sstevel@tonic-gate } 3037c478bd9Sstevel@tonic-gate if ((ldp = lwp_hash_lookup(p, tid)) == NULL || 3047c478bd9Sstevel@tonic-gate (t = ldp->ld_entry->le_thread) == NULL) 3057c478bd9Sstevel@tonic-gate break; 3067c478bd9Sstevel@tonic-gate } 3077c478bd9Sstevel@tonic-gate } 3087c478bd9Sstevel@tonic-gate 3097c478bd9Sstevel@tonic-gate if (error) 3107c478bd9Sstevel@tonic-gate break; 3117c478bd9Sstevel@tonic-gate 3127c478bd9Sstevel@tonic-gate /* 3137c478bd9Sstevel@tonic-gate * Wait for some lwp to terminate. 3147c478bd9Sstevel@tonic-gate */ 3157c478bd9Sstevel@tonic-gate if (!cv_wait_sig(&p->p_lwpexit, &p->p_lock)) 3167c478bd9Sstevel@tonic-gate error = EINTR; 3177c478bd9Sstevel@tonic-gate prbarrier(p); 3187c478bd9Sstevel@tonic-gate 3197c478bd9Sstevel@tonic-gate if (lwpid != 0) { 3207c478bd9Sstevel@tonic-gate if ((ldp = lwp_hash_lookup(p, lwpid)) == NULL) 3217c478bd9Sstevel@tonic-gate target_lep = NULL; 3227c478bd9Sstevel@tonic-gate else 3237c478bd9Sstevel@tonic-gate target_lep = ldp->ld_entry; 3247c478bd9Sstevel@tonic-gate } 3257c478bd9Sstevel@tonic-gate } 3267c478bd9Sstevel@tonic-gate 3277c478bd9Sstevel@tonic-gate if (lwpid != 0 && target_lep != NULL) { 3287c478bd9Sstevel@tonic-gate target_lep->le_waiters--; 3297c478bd9Sstevel@tonic-gate target_lep->le_dwaiters -= daemon; 3307c478bd9Sstevel@tonic-gate } 3317c478bd9Sstevel@tonic-gate p->p_lwpwait--; 3327c478bd9Sstevel@tonic-gate p->p_lwpdwait -= daemon; 3337c478bd9Sstevel@tonic-gate curthread->t_waitfor = -1; 3347c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 3357c478bd9Sstevel@tonic-gate return (set_errno(error)); 3367c478bd9Sstevel@tonic-gate } 3377c478bd9Sstevel@tonic-gate 3387c478bd9Sstevel@tonic-gate int 3397c478bd9Sstevel@tonic-gate lwp_detach(id_t lwpid) 3407c478bd9Sstevel@tonic-gate { 3417c478bd9Sstevel@tonic-gate kthread_t *t; 3427c478bd9Sstevel@tonic-gate proc_t *p = ttoproc(curthread); 3437c478bd9Sstevel@tonic-gate lwpdir_t *ldp; 3447c478bd9Sstevel@tonic-gate int error = 0; 3457c478bd9Sstevel@tonic-gate 3467c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); 3477c478bd9Sstevel@tonic-gate prbarrier(p); 3487c478bd9Sstevel@tonic-gate if ((ldp = lwp_hash_lookup(p, lwpid)) == NULL) 3497c478bd9Sstevel@tonic-gate error = ESRCH; 3507c478bd9Sstevel@tonic-gate else if ((t = ldp->ld_entry->le_thread) != NULL) { 3517c478bd9Sstevel@tonic-gate if (!(t->t_proc_flag & TP_TWAIT)) 3527c478bd9Sstevel@tonic-gate error = EINVAL; 3537c478bd9Sstevel@tonic-gate else { 3547c478bd9Sstevel@tonic-gate t->t_proc_flag &= ~TP_TWAIT; 3557c478bd9Sstevel@tonic-gate cv_broadcast(&p->p_lwpexit); 3567c478bd9Sstevel@tonic-gate } 3577c478bd9Sstevel@tonic-gate } else { 3587c478bd9Sstevel@tonic-gate ASSERT(p->p_zombcnt > 0); 3597c478bd9Sstevel@tonic-gate p->p_zombcnt--; 3607c478bd9Sstevel@tonic-gate lwp_hash_out(p, lwpid); 3617c478bd9Sstevel@tonic-gate } 3627c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 3637c478bd9Sstevel@tonic-gate 3647c478bd9Sstevel@tonic-gate if (error) 3657c478bd9Sstevel@tonic-gate return (set_errno(error)); 3667c478bd9Sstevel@tonic-gate return (0); 3677c478bd9Sstevel@tonic-gate } 3687c478bd9Sstevel@tonic-gate 3697c478bd9Sstevel@tonic-gate /* 3707c478bd9Sstevel@tonic-gate * Unpark the specified lwp. 3717c478bd9Sstevel@tonic-gate */ 3727c478bd9Sstevel@tonic-gate static int 3737c478bd9Sstevel@tonic-gate lwp_unpark(id_t lwpid) 3747c478bd9Sstevel@tonic-gate { 3757c478bd9Sstevel@tonic-gate proc_t *p = ttoproc(curthread); 3767c478bd9Sstevel@tonic-gate kthread_t *t; 3777c478bd9Sstevel@tonic-gate int error = 0; 3787c478bd9Sstevel@tonic-gate 3797c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); 3807c478bd9Sstevel@tonic-gate if ((t = idtot(p, lwpid)) == NULL) 3817c478bd9Sstevel@tonic-gate error = ESRCH; 3827c478bd9Sstevel@tonic-gate else { 3837c478bd9Sstevel@tonic-gate mutex_enter(&t->t_delay_lock); 3847c478bd9Sstevel@tonic-gate t->t_unpark = 1; 3857c478bd9Sstevel@tonic-gate cv_signal(&t->t_delay_cv); 3867c478bd9Sstevel@tonic-gate mutex_exit(&t->t_delay_lock); 3877c478bd9Sstevel@tonic-gate } 3887c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 3897c478bd9Sstevel@tonic-gate return (error); 3907c478bd9Sstevel@tonic-gate } 3917c478bd9Sstevel@tonic-gate 3927c478bd9Sstevel@tonic-gate /* 3937c478bd9Sstevel@tonic-gate * Sleep until we are set running by lwp_unpark() or until we are 3947c478bd9Sstevel@tonic-gate * interrupted by a signal or until we exhaust our timeout. 3957c478bd9Sstevel@tonic-gate * timeoutp is an in/out parameter. On entry, it contains the relative 3967c478bd9Sstevel@tonic-gate * time until timeout. On exit, we copyout the residual time left to it. 3977c478bd9Sstevel@tonic-gate */ 3987c478bd9Sstevel@tonic-gate static int 3997c478bd9Sstevel@tonic-gate lwp_park(timespec_t *timeoutp, id_t lwpid) 4007c478bd9Sstevel@tonic-gate { 4017c478bd9Sstevel@tonic-gate timespec_t rqtime; 4027c478bd9Sstevel@tonic-gate timespec_t rmtime; 4037c478bd9Sstevel@tonic-gate timespec_t now; 4047c478bd9Sstevel@tonic-gate timespec_t *rqtp = NULL; 4057c478bd9Sstevel@tonic-gate kthread_t *t = curthread; 406*3348528fSdm120769 int timecheck = 0; 4077c478bd9Sstevel@tonic-gate int error = 0; 4087c478bd9Sstevel@tonic-gate model_t datamodel = ttoproc(t)->p_model; 4097c478bd9Sstevel@tonic-gate 4107c478bd9Sstevel@tonic-gate if (lwpid != 0) /* unpark the other lwp, if any */ 4117c478bd9Sstevel@tonic-gate (void) lwp_unpark(lwpid); 4127c478bd9Sstevel@tonic-gate 4137c478bd9Sstevel@tonic-gate if (timeoutp) { 414*3348528fSdm120769 timecheck = timechanged; 4157c478bd9Sstevel@tonic-gate gethrestime(&now); 4167c478bd9Sstevel@tonic-gate if (datamodel == DATAMODEL_NATIVE) { 4177c478bd9Sstevel@tonic-gate if (copyin(timeoutp, &rqtime, sizeof (timespec_t))) { 4187c478bd9Sstevel@tonic-gate error = EFAULT; 4197c478bd9Sstevel@tonic-gate goto out; 4207c478bd9Sstevel@tonic-gate } 4217c478bd9Sstevel@tonic-gate } else { 4227c478bd9Sstevel@tonic-gate timespec32_t timeout32; 4237c478bd9Sstevel@tonic-gate 4247c478bd9Sstevel@tonic-gate if (copyin(timeoutp, &timeout32, sizeof (timeout32))) { 4257c478bd9Sstevel@tonic-gate error = EFAULT; 4267c478bd9Sstevel@tonic-gate goto out; 4277c478bd9Sstevel@tonic-gate } 4287c478bd9Sstevel@tonic-gate TIMESPEC32_TO_TIMESPEC(&rqtime, &timeout32) 4297c478bd9Sstevel@tonic-gate } 4307c478bd9Sstevel@tonic-gate 4317c478bd9Sstevel@tonic-gate if (itimerspecfix(&rqtime)) { 4327c478bd9Sstevel@tonic-gate error = EINVAL; 4337c478bd9Sstevel@tonic-gate goto out; 4347c478bd9Sstevel@tonic-gate } 4357c478bd9Sstevel@tonic-gate /* 4367c478bd9Sstevel@tonic-gate * Convert the timespec value into absolute time. 4377c478bd9Sstevel@tonic-gate */ 4387c478bd9Sstevel@tonic-gate timespecadd(&rqtime, &now); 4397c478bd9Sstevel@tonic-gate rqtp = &rqtime; 4407c478bd9Sstevel@tonic-gate } 4417c478bd9Sstevel@tonic-gate 4427c478bd9Sstevel@tonic-gate (void) new_mstate(t, LMS_USER_LOCK); 4437c478bd9Sstevel@tonic-gate 4447c478bd9Sstevel@tonic-gate mutex_enter(&t->t_delay_lock); 4457c478bd9Sstevel@tonic-gate if (!schedctl_is_park()) 4467c478bd9Sstevel@tonic-gate error = EINTR; 4477c478bd9Sstevel@tonic-gate while (error == 0 && t->t_unpark == 0) { 4487c478bd9Sstevel@tonic-gate switch (cv_waituntil_sig(&t->t_delay_cv, 449*3348528fSdm120769 &t->t_delay_lock, rqtp, timecheck)) { 4507c478bd9Sstevel@tonic-gate case 0: 4517c478bd9Sstevel@tonic-gate error = EINTR; 4527c478bd9Sstevel@tonic-gate break; 4537c478bd9Sstevel@tonic-gate case -1: 4547c478bd9Sstevel@tonic-gate error = ETIME; 4557c478bd9Sstevel@tonic-gate break; 4567c478bd9Sstevel@tonic-gate } 4577c478bd9Sstevel@tonic-gate } 4587c478bd9Sstevel@tonic-gate t->t_unpark = 0; 4597c478bd9Sstevel@tonic-gate mutex_exit(&t->t_delay_lock); 4607c478bd9Sstevel@tonic-gate 4617c478bd9Sstevel@tonic-gate if (timeoutp != NULL) { 4627c478bd9Sstevel@tonic-gate rmtime.tv_sec = rmtime.tv_nsec = 0; 4637c478bd9Sstevel@tonic-gate if (error != ETIME) { 4647c478bd9Sstevel@tonic-gate gethrestime(&now); 4657c478bd9Sstevel@tonic-gate if ((now.tv_sec < rqtime.tv_sec) || 4667c478bd9Sstevel@tonic-gate ((now.tv_sec == rqtime.tv_sec) && 4677c478bd9Sstevel@tonic-gate (now.tv_nsec < rqtime.tv_nsec))) { 4687c478bd9Sstevel@tonic-gate rmtime = rqtime; 4697c478bd9Sstevel@tonic-gate timespecsub(&rmtime, &now); 4707c478bd9Sstevel@tonic-gate } 4717c478bd9Sstevel@tonic-gate } 4727c478bd9Sstevel@tonic-gate if (datamodel == DATAMODEL_NATIVE) { 4737c478bd9Sstevel@tonic-gate if (copyout(&rmtime, timeoutp, sizeof (rmtime))) 4747c478bd9Sstevel@tonic-gate error = EFAULT; 4757c478bd9Sstevel@tonic-gate } else { 4767c478bd9Sstevel@tonic-gate timespec32_t rmtime32; 4777c478bd9Sstevel@tonic-gate 4787c478bd9Sstevel@tonic-gate TIMESPEC_TO_TIMESPEC32(&rmtime32, &rmtime); 4797c478bd9Sstevel@tonic-gate if (copyout(&rmtime32, timeoutp, sizeof (rmtime32))) 4807c478bd9Sstevel@tonic-gate error = EFAULT; 4817c478bd9Sstevel@tonic-gate } 4827c478bd9Sstevel@tonic-gate } 4837c478bd9Sstevel@tonic-gate out: 4847c478bd9Sstevel@tonic-gate schedctl_unpark(); 4857c478bd9Sstevel@tonic-gate if (t->t_mstate == LMS_USER_LOCK) 4867c478bd9Sstevel@tonic-gate (void) new_mstate(t, LMS_SYSTEM); 4877c478bd9Sstevel@tonic-gate return (error); 4887c478bd9Sstevel@tonic-gate } 4897c478bd9Sstevel@tonic-gate 4907c478bd9Sstevel@tonic-gate #define MAXLWPIDS 1024 4917c478bd9Sstevel@tonic-gate 4927c478bd9Sstevel@tonic-gate /* 4937c478bd9Sstevel@tonic-gate * Unpark all of the specified lwps. 4947c478bd9Sstevel@tonic-gate * Do it in chunks of MAXLWPIDS to avoid allocating too much memory. 4957c478bd9Sstevel@tonic-gate */ 4967c478bd9Sstevel@tonic-gate static int 4977c478bd9Sstevel@tonic-gate lwp_unpark_all(id_t *lwpidp, int nids) 4987c478bd9Sstevel@tonic-gate { 4997c478bd9Sstevel@tonic-gate proc_t *p = ttoproc(curthread); 5007c478bd9Sstevel@tonic-gate kthread_t *t; 5017c478bd9Sstevel@tonic-gate int error = 0; 5027c478bd9Sstevel@tonic-gate id_t *lwpid; 5037c478bd9Sstevel@tonic-gate size_t lwpidsz; 5047c478bd9Sstevel@tonic-gate int n; 5057c478bd9Sstevel@tonic-gate int i; 5067c478bd9Sstevel@tonic-gate 5077c478bd9Sstevel@tonic-gate if (nids <= 0) 5087c478bd9Sstevel@tonic-gate return (EINVAL); 5097c478bd9Sstevel@tonic-gate 5107c478bd9Sstevel@tonic-gate lwpidsz = MIN(nids, MAXLWPIDS) * sizeof (id_t); 5117c478bd9Sstevel@tonic-gate lwpid = kmem_alloc(lwpidsz, KM_SLEEP); 5127c478bd9Sstevel@tonic-gate while (nids > 0) { 5137c478bd9Sstevel@tonic-gate n = MIN(nids, MAXLWPIDS); 5147c478bd9Sstevel@tonic-gate if (copyin(lwpidp, lwpid, n * sizeof (id_t))) { 5157c478bd9Sstevel@tonic-gate error = EFAULT; 5167c478bd9Sstevel@tonic-gate break; 5177c478bd9Sstevel@tonic-gate } 5187c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); 5197c478bd9Sstevel@tonic-gate for (i = 0; i < n; i++) { 5207c478bd9Sstevel@tonic-gate if ((t = idtot(p, lwpid[i])) == NULL) 5217c478bd9Sstevel@tonic-gate error = ESRCH; 5227c478bd9Sstevel@tonic-gate else { 5237c478bd9Sstevel@tonic-gate mutex_enter(&t->t_delay_lock); 5247c478bd9Sstevel@tonic-gate t->t_unpark = 1; 5257c478bd9Sstevel@tonic-gate cv_signal(&t->t_delay_cv); 5267c478bd9Sstevel@tonic-gate mutex_exit(&t->t_delay_lock); 5277c478bd9Sstevel@tonic-gate } 5287c478bd9Sstevel@tonic-gate } 5297c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 5307c478bd9Sstevel@tonic-gate lwpidp += n; 5317c478bd9Sstevel@tonic-gate nids -= n; 5327c478bd9Sstevel@tonic-gate } 5337c478bd9Sstevel@tonic-gate kmem_free(lwpid, lwpidsz); 5347c478bd9Sstevel@tonic-gate return (error); 5357c478bd9Sstevel@tonic-gate } 5367c478bd9Sstevel@tonic-gate 5377c478bd9Sstevel@tonic-gate /* 5387c478bd9Sstevel@tonic-gate * SYS_lwp_park() system call. 5397c478bd9Sstevel@tonic-gate */ 5407c478bd9Sstevel@tonic-gate int 5417c478bd9Sstevel@tonic-gate syslwp_park(int which, uintptr_t arg1, uintptr_t arg2) 5427c478bd9Sstevel@tonic-gate { 5437c478bd9Sstevel@tonic-gate int error; 5447c478bd9Sstevel@tonic-gate 5457c478bd9Sstevel@tonic-gate switch (which) { 5467c478bd9Sstevel@tonic-gate case 0: 5477c478bd9Sstevel@tonic-gate error = lwp_park((timespec_t *)arg1, (id_t)arg2); 5487c478bd9Sstevel@tonic-gate break; 5497c478bd9Sstevel@tonic-gate case 1: 5507c478bd9Sstevel@tonic-gate error = lwp_unpark((id_t)arg1); 5517c478bd9Sstevel@tonic-gate break; 5527c478bd9Sstevel@tonic-gate case 2: 5537c478bd9Sstevel@tonic-gate error = lwp_unpark_all((id_t *)arg1, (int)arg2); 5547c478bd9Sstevel@tonic-gate break; 5557c478bd9Sstevel@tonic-gate default: 5567c478bd9Sstevel@tonic-gate error = EINVAL; 5577c478bd9Sstevel@tonic-gate break; 5587c478bd9Sstevel@tonic-gate } 5597c478bd9Sstevel@tonic-gate 5607c478bd9Sstevel@tonic-gate if (error) 5617c478bd9Sstevel@tonic-gate return (set_errno(error)); 5627c478bd9Sstevel@tonic-gate return (0); 5637c478bd9Sstevel@tonic-gate } 564