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*47eb4d1eSsl108498 * Common Development and Distribution License (the "License"). 6*47eb4d1eSsl108498 * 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 */ 217c478bd9Sstevel@tonic-gate /* 22*47eb4d1eSsl108498 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 297c478bd9Sstevel@tonic-gate 307c478bd9Sstevel@tonic-gate #include <sys/param.h> 317c478bd9Sstevel@tonic-gate #include <sys/types.h> 327c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 337c478bd9Sstevel@tonic-gate #include <sys/systm.h> 347c478bd9Sstevel@tonic-gate #include <sys/prsystm.h> 357c478bd9Sstevel@tonic-gate #include <sys/cred.h> 367c478bd9Sstevel@tonic-gate #include <sys/errno.h> 377c478bd9Sstevel@tonic-gate #include <sys/proc.h> 387c478bd9Sstevel@tonic-gate #include <sys/signal.h> 397c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 407c478bd9Sstevel@tonic-gate #include <sys/unistd.h> 417c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 427c478bd9Sstevel@tonic-gate #include <sys/schedctl.h> 437c478bd9Sstevel@tonic-gate #include <sys/debug.h> 447c478bd9Sstevel@tonic-gate #include <sys/contract/process_impl.h> 457c478bd9Sstevel@tonic-gate 467c478bd9Sstevel@tonic-gate kthread_t * 477c478bd9Sstevel@tonic-gate idtot(proc_t *p, id_t lwpid) 487c478bd9Sstevel@tonic-gate { 497c478bd9Sstevel@tonic-gate lwpdir_t *ldp; 507c478bd9Sstevel@tonic-gate 517c478bd9Sstevel@tonic-gate if ((ldp = lwp_hash_lookup(p, lwpid)) != NULL) 527c478bd9Sstevel@tonic-gate return (ldp->ld_entry->le_thread); 537c478bd9Sstevel@tonic-gate return (NULL); 547c478bd9Sstevel@tonic-gate } 557c478bd9Sstevel@tonic-gate 567c478bd9Sstevel@tonic-gate /* 577c478bd9Sstevel@tonic-gate * Stop an lwp of the current process 587c478bd9Sstevel@tonic-gate */ 597c478bd9Sstevel@tonic-gate int 607c478bd9Sstevel@tonic-gate syslwp_suspend(id_t lwpid) 617c478bd9Sstevel@tonic-gate { 627c478bd9Sstevel@tonic-gate kthread_t *t; 637c478bd9Sstevel@tonic-gate int error; 647c478bd9Sstevel@tonic-gate proc_t *p = ttoproc(curthread); 657c478bd9Sstevel@tonic-gate 667c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); 677c478bd9Sstevel@tonic-gate if ((t = idtot(p, lwpid)) == NULL) 687c478bd9Sstevel@tonic-gate error = ESRCH; 697c478bd9Sstevel@tonic-gate else 707c478bd9Sstevel@tonic-gate error = lwp_suspend(t); 717c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 727c478bd9Sstevel@tonic-gate if (error) 737c478bd9Sstevel@tonic-gate return (set_errno(error)); 747c478bd9Sstevel@tonic-gate return (0); 757c478bd9Sstevel@tonic-gate } 767c478bd9Sstevel@tonic-gate 777c478bd9Sstevel@tonic-gate int 787c478bd9Sstevel@tonic-gate syslwp_continue(id_t lwpid) 797c478bd9Sstevel@tonic-gate { 807c478bd9Sstevel@tonic-gate kthread_t *t; 817c478bd9Sstevel@tonic-gate proc_t *p = ttoproc(curthread); 827c478bd9Sstevel@tonic-gate 837c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); 847c478bd9Sstevel@tonic-gate if ((t = idtot(p, lwpid)) == NULL) { 857c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 867c478bd9Sstevel@tonic-gate return (set_errno(ESRCH)); 877c478bd9Sstevel@tonic-gate } 887c478bd9Sstevel@tonic-gate lwp_continue(t); 897c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 907c478bd9Sstevel@tonic-gate return (0); 917c478bd9Sstevel@tonic-gate } 927c478bd9Sstevel@tonic-gate 937c478bd9Sstevel@tonic-gate int 947c478bd9Sstevel@tonic-gate lwp_kill(id_t lwpid, int sig) 957c478bd9Sstevel@tonic-gate { 967c478bd9Sstevel@tonic-gate sigqueue_t *sqp; 977c478bd9Sstevel@tonic-gate kthread_t *t; 987c478bd9Sstevel@tonic-gate proc_t *p = ttoproc(curthread); 997c478bd9Sstevel@tonic-gate 1007c478bd9Sstevel@tonic-gate if (sig < 0 || sig >= NSIG) 1017c478bd9Sstevel@tonic-gate return (set_errno(EINVAL)); 1027c478bd9Sstevel@tonic-gate if (sig != 0) 1037c478bd9Sstevel@tonic-gate sqp = kmem_zalloc(sizeof (sigqueue_t), KM_SLEEP); 1047c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); 1057c478bd9Sstevel@tonic-gate if ((t = idtot(p, lwpid)) == NULL) { 1067c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 1077c478bd9Sstevel@tonic-gate if (sig != 0) 1087c478bd9Sstevel@tonic-gate kmem_free(sqp, sizeof (sigqueue_t)); 1097c478bd9Sstevel@tonic-gate return (set_errno(ESRCH)); 1107c478bd9Sstevel@tonic-gate } 1117c478bd9Sstevel@tonic-gate if (sig == 0) { 1127c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 1137c478bd9Sstevel@tonic-gate return (0); 1147c478bd9Sstevel@tonic-gate } 1157c478bd9Sstevel@tonic-gate sqp->sq_info.si_signo = sig; 1167c478bd9Sstevel@tonic-gate sqp->sq_info.si_code = SI_LWP; 1177c478bd9Sstevel@tonic-gate sqp->sq_info.si_pid = p->p_pid; 1187c478bd9Sstevel@tonic-gate sqp->sq_info.si_ctid = PRCTID(p); 1197c478bd9Sstevel@tonic-gate sqp->sq_info.si_zoneid = getzoneid(); 1207c478bd9Sstevel@tonic-gate sqp->sq_info.si_uid = crgetruid(CRED()); 1217c478bd9Sstevel@tonic-gate sigaddqa(p, t, sqp); 1227c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 1237c478bd9Sstevel@tonic-gate return (0); 1247c478bd9Sstevel@tonic-gate } 1257c478bd9Sstevel@tonic-gate 1267c478bd9Sstevel@tonic-gate /* 1277c478bd9Sstevel@tonic-gate * This is the specification of lwp_wait() from the _lwp_wait(2) manual page: 1287c478bd9Sstevel@tonic-gate * 1297c478bd9Sstevel@tonic-gate * The lwp_wait() function blocks the current lwp until the lwp specified 1307c478bd9Sstevel@tonic-gate * by 'lwpid' terminates. If the specified lwp terminated prior to the call 1317c478bd9Sstevel@tonic-gate * to lwp_wait(), then lwp_wait() returns immediately. If 'lwpid' is zero, 1327c478bd9Sstevel@tonic-gate * then lwp_wait() waits for any undetached lwp in the current process. 1337c478bd9Sstevel@tonic-gate * If 'lwpid' is not zero, then it must specify an undetached lwp in the 1347c478bd9Sstevel@tonic-gate * current process. If 'departed' is not NULL, then it points to a location 1357c478bd9Sstevel@tonic-gate * where the id of the exited lwp is stored. 1367c478bd9Sstevel@tonic-gate * 1377c478bd9Sstevel@tonic-gate * When an lwp exits and there are one or more lwps in the process waiting 1387c478bd9Sstevel@tonic-gate * for this specific lwp to exit, then one of the waiting lwps is unblocked 1397c478bd9Sstevel@tonic-gate * and it returns from lwp_wait() successfully. Any other lwps waiting for 1407c478bd9Sstevel@tonic-gate * this same lwp to exit are also unblocked, however, they return from 1417c478bd9Sstevel@tonic-gate * lwp_wait() with the error ESRCH. If there are no lwps in the process 1427c478bd9Sstevel@tonic-gate * waiting for this specific lwp to exit but there are one or more lwps 1437c478bd9Sstevel@tonic-gate * waiting for any lwp to exit, then one of the waiting lwps is unblocked 1447c478bd9Sstevel@tonic-gate * and it returns from lwp_wait() successfully. 1457c478bd9Sstevel@tonic-gate * 1467c478bd9Sstevel@tonic-gate * If an lwp is waiting for any lwp to exit, it blocks until an undetached 1477c478bd9Sstevel@tonic-gate * lwp for which no other lwp is waiting terminates, at which time it returns 1487c478bd9Sstevel@tonic-gate * successfully, or until all other lwps in the process are either daemon 1497c478bd9Sstevel@tonic-gate * lwps or lwps waiting in lwp_wait(), in which case it returns EDEADLK. 1507c478bd9Sstevel@tonic-gate */ 1517c478bd9Sstevel@tonic-gate int 1527c478bd9Sstevel@tonic-gate lwp_wait(id_t lwpid, id_t *departed) 1537c478bd9Sstevel@tonic-gate { 1547c478bd9Sstevel@tonic-gate proc_t *p = ttoproc(curthread); 1557c478bd9Sstevel@tonic-gate int error = 0; 1567c478bd9Sstevel@tonic-gate int daemon = (curthread->t_proc_flag & TP_DAEMON)? 1 : 0; 1577c478bd9Sstevel@tonic-gate lwpent_t *target_lep; 1587c478bd9Sstevel@tonic-gate lwpdir_t *ldp; 1597c478bd9Sstevel@tonic-gate lwpent_t *lep; 1607c478bd9Sstevel@tonic-gate 1617c478bd9Sstevel@tonic-gate /* 1627c478bd9Sstevel@tonic-gate * lwp_wait() is not supported for the /proc agent lwp. 1637c478bd9Sstevel@tonic-gate */ 1647c478bd9Sstevel@tonic-gate if (curthread == p->p_agenttp) 1657c478bd9Sstevel@tonic-gate return (set_errno(ENOTSUP)); 1667c478bd9Sstevel@tonic-gate 1677c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); 1687c478bd9Sstevel@tonic-gate prbarrier(p); 1697c478bd9Sstevel@tonic-gate 1707c478bd9Sstevel@tonic-gate curthread->t_waitfor = lwpid; 1717c478bd9Sstevel@tonic-gate p->p_lwpwait++; 1727c478bd9Sstevel@tonic-gate p->p_lwpdwait += daemon; 1737c478bd9Sstevel@tonic-gate 1747c478bd9Sstevel@tonic-gate if (lwpid != 0) { 1757c478bd9Sstevel@tonic-gate if ((ldp = lwp_hash_lookup(p, lwpid)) == NULL) 1767c478bd9Sstevel@tonic-gate target_lep = NULL; 1777c478bd9Sstevel@tonic-gate else { 1787c478bd9Sstevel@tonic-gate target_lep = ldp->ld_entry; 1797c478bd9Sstevel@tonic-gate target_lep->le_waiters++; 1807c478bd9Sstevel@tonic-gate target_lep->le_dwaiters += daemon; 1817c478bd9Sstevel@tonic-gate } 1827c478bd9Sstevel@tonic-gate } 1837c478bd9Sstevel@tonic-gate 1847c478bd9Sstevel@tonic-gate while (error == 0) { 1857c478bd9Sstevel@tonic-gate kthread_t *t; 1867c478bd9Sstevel@tonic-gate id_t tid; 1877c478bd9Sstevel@tonic-gate int i; 1887c478bd9Sstevel@tonic-gate 1897c478bd9Sstevel@tonic-gate if (lwpid != 0) { 1907c478bd9Sstevel@tonic-gate /* 1917c478bd9Sstevel@tonic-gate * Look for a specific zombie lwp. 1927c478bd9Sstevel@tonic-gate */ 1937c478bd9Sstevel@tonic-gate if (target_lep == NULL) 1947c478bd9Sstevel@tonic-gate error = ESRCH; 1957c478bd9Sstevel@tonic-gate else if ((t = target_lep->le_thread) != NULL) { 1967c478bd9Sstevel@tonic-gate if (!(t->t_proc_flag & TP_TWAIT)) 1977c478bd9Sstevel@tonic-gate error = EINVAL; 1987c478bd9Sstevel@tonic-gate } else { 1997c478bd9Sstevel@tonic-gate /* 2007c478bd9Sstevel@tonic-gate * We found the zombie we are waiting for. 2017c478bd9Sstevel@tonic-gate */ 2027c478bd9Sstevel@tonic-gate ASSERT(p->p_zombcnt > 0); 2037c478bd9Sstevel@tonic-gate p->p_zombcnt--; 2047c478bd9Sstevel@tonic-gate p->p_lwpwait--; 2057c478bd9Sstevel@tonic-gate p->p_lwpdwait -= daemon; 2067c478bd9Sstevel@tonic-gate curthread->t_waitfor = -1; 2077c478bd9Sstevel@tonic-gate lwp_hash_out(p, lwpid); 2087c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 2097c478bd9Sstevel@tonic-gate if (departed != NULL && 2107c478bd9Sstevel@tonic-gate copyout(&lwpid, departed, sizeof (id_t))) 2117c478bd9Sstevel@tonic-gate return (set_errno(EFAULT)); 2127c478bd9Sstevel@tonic-gate return (0); 2137c478bd9Sstevel@tonic-gate } 2147c478bd9Sstevel@tonic-gate } else { 2157c478bd9Sstevel@tonic-gate /* 2167c478bd9Sstevel@tonic-gate * Look for any zombie lwp. 2177c478bd9Sstevel@tonic-gate */ 2187c478bd9Sstevel@tonic-gate int some_non_daemon_will_return = 0; 2197c478bd9Sstevel@tonic-gate 2207c478bd9Sstevel@tonic-gate /* for each entry in the lwp directory... */ 2217c478bd9Sstevel@tonic-gate ldp = p->p_lwpdir; 2227c478bd9Sstevel@tonic-gate for (i = 0; i < p->p_lwpdir_sz; i++, ldp++) { 2237c478bd9Sstevel@tonic-gate 2247c478bd9Sstevel@tonic-gate if ((lep = ldp->ld_entry) == NULL || 2257c478bd9Sstevel@tonic-gate lep->le_thread != NULL) 2267c478bd9Sstevel@tonic-gate continue; 2277c478bd9Sstevel@tonic-gate 2287c478bd9Sstevel@tonic-gate /* 2297c478bd9Sstevel@tonic-gate * We found a zombie lwp. If there is some 2307c478bd9Sstevel@tonic-gate * other thread waiting specifically for the 2317c478bd9Sstevel@tonic-gate * zombie we just found, then defer to the other 2327c478bd9Sstevel@tonic-gate * waiting thread and continue searching for 2337c478bd9Sstevel@tonic-gate * another zombie. Also check to see if there 2347c478bd9Sstevel@tonic-gate * is some non-daemon thread sleeping here in 2357c478bd9Sstevel@tonic-gate * lwp_wait() that will succeed and return when 2367c478bd9Sstevel@tonic-gate * we drop p->p_lock. This is tested below. 2377c478bd9Sstevel@tonic-gate */ 2387c478bd9Sstevel@tonic-gate tid = lep->le_lwpid; 2397c478bd9Sstevel@tonic-gate if (lep->le_waiters != 0) { 2407c478bd9Sstevel@tonic-gate if (lep->le_waiters - lep->le_dwaiters) 2417c478bd9Sstevel@tonic-gate some_non_daemon_will_return = 1; 2427c478bd9Sstevel@tonic-gate continue; 2437c478bd9Sstevel@tonic-gate } 2447c478bd9Sstevel@tonic-gate 2457c478bd9Sstevel@tonic-gate /* 2467c478bd9Sstevel@tonic-gate * We found a zombie that no one else 2477c478bd9Sstevel@tonic-gate * is specifically waiting for. 2487c478bd9Sstevel@tonic-gate */ 2497c478bd9Sstevel@tonic-gate ASSERT(p->p_zombcnt > 0); 2507c478bd9Sstevel@tonic-gate p->p_zombcnt--; 2517c478bd9Sstevel@tonic-gate p->p_lwpwait--; 2527c478bd9Sstevel@tonic-gate p->p_lwpdwait -= daemon; 2537c478bd9Sstevel@tonic-gate curthread->t_waitfor = -1; 2547c478bd9Sstevel@tonic-gate lwp_hash_out(p, tid); 2557c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 2567c478bd9Sstevel@tonic-gate if (departed != NULL && 2577c478bd9Sstevel@tonic-gate copyout(&tid, departed, sizeof (id_t))) 2587c478bd9Sstevel@tonic-gate return (set_errno(EFAULT)); 2597c478bd9Sstevel@tonic-gate return (0); 2607c478bd9Sstevel@tonic-gate } 2617c478bd9Sstevel@tonic-gate 2627c478bd9Sstevel@tonic-gate /* 2637c478bd9Sstevel@tonic-gate * We are waiting for anyone. If all non-daemon lwps 2647c478bd9Sstevel@tonic-gate * are waiting here, and if we determined above that 2657c478bd9Sstevel@tonic-gate * no non-daemon lwp will return, we have deadlock. 2667c478bd9Sstevel@tonic-gate */ 2677c478bd9Sstevel@tonic-gate if (!some_non_daemon_will_return && 2687c478bd9Sstevel@tonic-gate p->p_lwpcnt == p->p_lwpdaemon + 2697c478bd9Sstevel@tonic-gate (p->p_lwpwait - p->p_lwpdwait)) 2707c478bd9Sstevel@tonic-gate error = EDEADLK; 2717c478bd9Sstevel@tonic-gate } 2727c478bd9Sstevel@tonic-gate 2737c478bd9Sstevel@tonic-gate if (error == 0 && lwpid != 0) { 2747c478bd9Sstevel@tonic-gate /* 2757c478bd9Sstevel@tonic-gate * We are waiting for a specific non-zombie lwp. 2767c478bd9Sstevel@tonic-gate * Fail if there is a deadlock loop. 2777c478bd9Sstevel@tonic-gate */ 2787c478bd9Sstevel@tonic-gate for (;;) { 2797c478bd9Sstevel@tonic-gate if (t == curthread) { 2807c478bd9Sstevel@tonic-gate error = EDEADLK; 2817c478bd9Sstevel@tonic-gate break; 2827c478bd9Sstevel@tonic-gate } 2837c478bd9Sstevel@tonic-gate /* who is he waiting for? */ 2847c478bd9Sstevel@tonic-gate if ((tid = t->t_waitfor) == -1) 2857c478bd9Sstevel@tonic-gate break; 2867c478bd9Sstevel@tonic-gate if (tid == 0) { 2877c478bd9Sstevel@tonic-gate /* 2887c478bd9Sstevel@tonic-gate * The lwp we are waiting for is 2897c478bd9Sstevel@tonic-gate * waiting for anyone (transitively). 2907c478bd9Sstevel@tonic-gate * If there are no zombies right now 2917c478bd9Sstevel@tonic-gate * and if we would have deadlock due 2927c478bd9Sstevel@tonic-gate * to all non-daemon lwps waiting here, 2937c478bd9Sstevel@tonic-gate * wake up the lwp that is waiting for 2947c478bd9Sstevel@tonic-gate * anyone so it can return EDEADLK. 2957c478bd9Sstevel@tonic-gate */ 2967c478bd9Sstevel@tonic-gate if (p->p_zombcnt == 0 && 2977c478bd9Sstevel@tonic-gate p->p_lwpcnt == p->p_lwpdaemon + 2987c478bd9Sstevel@tonic-gate p->p_lwpwait - p->p_lwpdwait) 2997c478bd9Sstevel@tonic-gate cv_broadcast(&p->p_lwpexit); 3007c478bd9Sstevel@tonic-gate break; 3017c478bd9Sstevel@tonic-gate } 3027c478bd9Sstevel@tonic-gate if ((ldp = lwp_hash_lookup(p, tid)) == NULL || 3037c478bd9Sstevel@tonic-gate (t = ldp->ld_entry->le_thread) == NULL) 3047c478bd9Sstevel@tonic-gate break; 3057c478bd9Sstevel@tonic-gate } 3067c478bd9Sstevel@tonic-gate } 3077c478bd9Sstevel@tonic-gate 3087c478bd9Sstevel@tonic-gate if (error) 3097c478bd9Sstevel@tonic-gate break; 3107c478bd9Sstevel@tonic-gate 3117c478bd9Sstevel@tonic-gate /* 3127c478bd9Sstevel@tonic-gate * Wait for some lwp to terminate. 3137c478bd9Sstevel@tonic-gate */ 3147c478bd9Sstevel@tonic-gate if (!cv_wait_sig(&p->p_lwpexit, &p->p_lock)) 3157c478bd9Sstevel@tonic-gate error = EINTR; 3167c478bd9Sstevel@tonic-gate prbarrier(p); 3177c478bd9Sstevel@tonic-gate 3187c478bd9Sstevel@tonic-gate if (lwpid != 0) { 3197c478bd9Sstevel@tonic-gate if ((ldp = lwp_hash_lookup(p, lwpid)) == NULL) 3207c478bd9Sstevel@tonic-gate target_lep = NULL; 3217c478bd9Sstevel@tonic-gate else 3227c478bd9Sstevel@tonic-gate target_lep = ldp->ld_entry; 3237c478bd9Sstevel@tonic-gate } 3247c478bd9Sstevel@tonic-gate } 3257c478bd9Sstevel@tonic-gate 3267c478bd9Sstevel@tonic-gate if (lwpid != 0 && target_lep != NULL) { 3277c478bd9Sstevel@tonic-gate target_lep->le_waiters--; 3287c478bd9Sstevel@tonic-gate target_lep->le_dwaiters -= daemon; 3297c478bd9Sstevel@tonic-gate } 3307c478bd9Sstevel@tonic-gate p->p_lwpwait--; 3317c478bd9Sstevel@tonic-gate p->p_lwpdwait -= daemon; 3327c478bd9Sstevel@tonic-gate curthread->t_waitfor = -1; 3337c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 3347c478bd9Sstevel@tonic-gate return (set_errno(error)); 3357c478bd9Sstevel@tonic-gate } 3367c478bd9Sstevel@tonic-gate 3377c478bd9Sstevel@tonic-gate int 3387c478bd9Sstevel@tonic-gate lwp_detach(id_t lwpid) 3397c478bd9Sstevel@tonic-gate { 3407c478bd9Sstevel@tonic-gate kthread_t *t; 3417c478bd9Sstevel@tonic-gate proc_t *p = ttoproc(curthread); 3427c478bd9Sstevel@tonic-gate lwpdir_t *ldp; 3437c478bd9Sstevel@tonic-gate int error = 0; 3447c478bd9Sstevel@tonic-gate 3457c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); 3467c478bd9Sstevel@tonic-gate prbarrier(p); 3477c478bd9Sstevel@tonic-gate if ((ldp = lwp_hash_lookup(p, lwpid)) == NULL) 3487c478bd9Sstevel@tonic-gate error = ESRCH; 3497c478bd9Sstevel@tonic-gate else if ((t = ldp->ld_entry->le_thread) != NULL) { 3507c478bd9Sstevel@tonic-gate if (!(t->t_proc_flag & TP_TWAIT)) 3517c478bd9Sstevel@tonic-gate error = EINVAL; 3527c478bd9Sstevel@tonic-gate else { 3537c478bd9Sstevel@tonic-gate t->t_proc_flag &= ~TP_TWAIT; 3547c478bd9Sstevel@tonic-gate cv_broadcast(&p->p_lwpexit); 3557c478bd9Sstevel@tonic-gate } 3567c478bd9Sstevel@tonic-gate } else { 3577c478bd9Sstevel@tonic-gate ASSERT(p->p_zombcnt > 0); 3587c478bd9Sstevel@tonic-gate p->p_zombcnt--; 3597c478bd9Sstevel@tonic-gate lwp_hash_out(p, lwpid); 3607c478bd9Sstevel@tonic-gate } 3617c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 3627c478bd9Sstevel@tonic-gate 3637c478bd9Sstevel@tonic-gate if (error) 3647c478bd9Sstevel@tonic-gate return (set_errno(error)); 3657c478bd9Sstevel@tonic-gate return (0); 3667c478bd9Sstevel@tonic-gate } 3677c478bd9Sstevel@tonic-gate 3687c478bd9Sstevel@tonic-gate /* 3697c478bd9Sstevel@tonic-gate * Unpark the specified lwp. 3707c478bd9Sstevel@tonic-gate */ 3717c478bd9Sstevel@tonic-gate static int 3727c478bd9Sstevel@tonic-gate lwp_unpark(id_t lwpid) 3737c478bd9Sstevel@tonic-gate { 3747c478bd9Sstevel@tonic-gate proc_t *p = ttoproc(curthread); 3757c478bd9Sstevel@tonic-gate kthread_t *t; 3767c478bd9Sstevel@tonic-gate int error = 0; 3777c478bd9Sstevel@tonic-gate 3787c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); 3797c478bd9Sstevel@tonic-gate if ((t = idtot(p, lwpid)) == NULL) 3807c478bd9Sstevel@tonic-gate error = ESRCH; 3817c478bd9Sstevel@tonic-gate else { 3827c478bd9Sstevel@tonic-gate mutex_enter(&t->t_delay_lock); 3837c478bd9Sstevel@tonic-gate t->t_unpark = 1; 3847c478bd9Sstevel@tonic-gate cv_signal(&t->t_delay_cv); 3857c478bd9Sstevel@tonic-gate mutex_exit(&t->t_delay_lock); 3867c478bd9Sstevel@tonic-gate } 3877c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 3887c478bd9Sstevel@tonic-gate return (error); 3897c478bd9Sstevel@tonic-gate } 3907c478bd9Sstevel@tonic-gate 3917c478bd9Sstevel@tonic-gate /* 392*47eb4d1eSsl108498 * Cancel a previous unpark for the specified lwp. 393*47eb4d1eSsl108498 * 394*47eb4d1eSsl108498 * This interface exists ONLY to support older versions of libthread, which 395*47eb4d1eSsl108498 * called lwp_unpark(self) to force calls to lwp_park(self) to return 396*47eb4d1eSsl108498 * immediately. These older libthreads required a mechanism to cancel the 397*47eb4d1eSsl108498 * lwp_unpark(self). 398*47eb4d1eSsl108498 * 399*47eb4d1eSsl108498 * libc does not call this interface. Instead, the sc_park flag in the 400*47eb4d1eSsl108498 * schedctl page is cleared to force calls to lwp_park() to return 401*47eb4d1eSsl108498 * immediately. 402*47eb4d1eSsl108498 */ 403*47eb4d1eSsl108498 static int 404*47eb4d1eSsl108498 lwp_unpark_cancel(id_t lwpid) 405*47eb4d1eSsl108498 { 406*47eb4d1eSsl108498 proc_t *p = ttoproc(curthread); 407*47eb4d1eSsl108498 kthread_t *t; 408*47eb4d1eSsl108498 int error = 0; 409*47eb4d1eSsl108498 410*47eb4d1eSsl108498 mutex_enter(&p->p_lock); 411*47eb4d1eSsl108498 if ((t = idtot(p, lwpid)) == NULL) { 412*47eb4d1eSsl108498 error = ESRCH; 413*47eb4d1eSsl108498 } else { 414*47eb4d1eSsl108498 mutex_enter(&t->t_delay_lock); 415*47eb4d1eSsl108498 t->t_unpark = 0; 416*47eb4d1eSsl108498 mutex_exit(&t->t_delay_lock); 417*47eb4d1eSsl108498 } 418*47eb4d1eSsl108498 mutex_exit(&p->p_lock); 419*47eb4d1eSsl108498 return (error); 420*47eb4d1eSsl108498 } 421*47eb4d1eSsl108498 422*47eb4d1eSsl108498 /* 4237c478bd9Sstevel@tonic-gate * Sleep until we are set running by lwp_unpark() or until we are 4247c478bd9Sstevel@tonic-gate * interrupted by a signal or until we exhaust our timeout. 4257c478bd9Sstevel@tonic-gate * timeoutp is an in/out parameter. On entry, it contains the relative 4267c478bd9Sstevel@tonic-gate * time until timeout. On exit, we copyout the residual time left to it. 4277c478bd9Sstevel@tonic-gate */ 4287c478bd9Sstevel@tonic-gate static int 4297c478bd9Sstevel@tonic-gate lwp_park(timespec_t *timeoutp, id_t lwpid) 4307c478bd9Sstevel@tonic-gate { 4317c478bd9Sstevel@tonic-gate timespec_t rqtime; 4327c478bd9Sstevel@tonic-gate timespec_t rmtime; 4337c478bd9Sstevel@tonic-gate timespec_t now; 4347c478bd9Sstevel@tonic-gate timespec_t *rqtp = NULL; 4357c478bd9Sstevel@tonic-gate kthread_t *t = curthread; 4363348528fSdm120769 int timecheck = 0; 4377c478bd9Sstevel@tonic-gate int error = 0; 4387c478bd9Sstevel@tonic-gate model_t datamodel = ttoproc(t)->p_model; 4397c478bd9Sstevel@tonic-gate 4407c478bd9Sstevel@tonic-gate if (lwpid != 0) /* unpark the other lwp, if any */ 4417c478bd9Sstevel@tonic-gate (void) lwp_unpark(lwpid); 4427c478bd9Sstevel@tonic-gate 4437c478bd9Sstevel@tonic-gate if (timeoutp) { 4443348528fSdm120769 timecheck = timechanged; 4457c478bd9Sstevel@tonic-gate gethrestime(&now); 4467c478bd9Sstevel@tonic-gate if (datamodel == DATAMODEL_NATIVE) { 4477c478bd9Sstevel@tonic-gate if (copyin(timeoutp, &rqtime, sizeof (timespec_t))) { 4487c478bd9Sstevel@tonic-gate error = EFAULT; 4497c478bd9Sstevel@tonic-gate goto out; 4507c478bd9Sstevel@tonic-gate } 4517c478bd9Sstevel@tonic-gate } else { 4527c478bd9Sstevel@tonic-gate timespec32_t timeout32; 4537c478bd9Sstevel@tonic-gate 4547c478bd9Sstevel@tonic-gate if (copyin(timeoutp, &timeout32, sizeof (timeout32))) { 4557c478bd9Sstevel@tonic-gate error = EFAULT; 4567c478bd9Sstevel@tonic-gate goto out; 4577c478bd9Sstevel@tonic-gate } 4587c478bd9Sstevel@tonic-gate TIMESPEC32_TO_TIMESPEC(&rqtime, &timeout32) 4597c478bd9Sstevel@tonic-gate } 4607c478bd9Sstevel@tonic-gate 4617c478bd9Sstevel@tonic-gate if (itimerspecfix(&rqtime)) { 4627c478bd9Sstevel@tonic-gate error = EINVAL; 4637c478bd9Sstevel@tonic-gate goto out; 4647c478bd9Sstevel@tonic-gate } 4657c478bd9Sstevel@tonic-gate /* 4667c478bd9Sstevel@tonic-gate * Convert the timespec value into absolute time. 4677c478bd9Sstevel@tonic-gate */ 4687c478bd9Sstevel@tonic-gate timespecadd(&rqtime, &now); 4697c478bd9Sstevel@tonic-gate rqtp = &rqtime; 4707c478bd9Sstevel@tonic-gate } 4717c478bd9Sstevel@tonic-gate 4727c478bd9Sstevel@tonic-gate (void) new_mstate(t, LMS_USER_LOCK); 4737c478bd9Sstevel@tonic-gate 4747c478bd9Sstevel@tonic-gate mutex_enter(&t->t_delay_lock); 4757c478bd9Sstevel@tonic-gate if (!schedctl_is_park()) 4767c478bd9Sstevel@tonic-gate error = EINTR; 4777c478bd9Sstevel@tonic-gate while (error == 0 && t->t_unpark == 0) { 4787c478bd9Sstevel@tonic-gate switch (cv_waituntil_sig(&t->t_delay_cv, 4793348528fSdm120769 &t->t_delay_lock, rqtp, timecheck)) { 4807c478bd9Sstevel@tonic-gate case 0: 4817c478bd9Sstevel@tonic-gate error = EINTR; 4827c478bd9Sstevel@tonic-gate break; 4837c478bd9Sstevel@tonic-gate case -1: 4847c478bd9Sstevel@tonic-gate error = ETIME; 4857c478bd9Sstevel@tonic-gate break; 4867c478bd9Sstevel@tonic-gate } 4877c478bd9Sstevel@tonic-gate } 4887c478bd9Sstevel@tonic-gate t->t_unpark = 0; 4897c478bd9Sstevel@tonic-gate mutex_exit(&t->t_delay_lock); 4907c478bd9Sstevel@tonic-gate 4917c478bd9Sstevel@tonic-gate if (timeoutp != NULL) { 4927c478bd9Sstevel@tonic-gate rmtime.tv_sec = rmtime.tv_nsec = 0; 4937c478bd9Sstevel@tonic-gate if (error != ETIME) { 4947c478bd9Sstevel@tonic-gate gethrestime(&now); 4957c478bd9Sstevel@tonic-gate if ((now.tv_sec < rqtime.tv_sec) || 4967c478bd9Sstevel@tonic-gate ((now.tv_sec == rqtime.tv_sec) && 4977c478bd9Sstevel@tonic-gate (now.tv_nsec < rqtime.tv_nsec))) { 4987c478bd9Sstevel@tonic-gate rmtime = rqtime; 4997c478bd9Sstevel@tonic-gate timespecsub(&rmtime, &now); 5007c478bd9Sstevel@tonic-gate } 5017c478bd9Sstevel@tonic-gate } 5027c478bd9Sstevel@tonic-gate if (datamodel == DATAMODEL_NATIVE) { 5037c478bd9Sstevel@tonic-gate if (copyout(&rmtime, timeoutp, sizeof (rmtime))) 5047c478bd9Sstevel@tonic-gate error = EFAULT; 5057c478bd9Sstevel@tonic-gate } else { 5067c478bd9Sstevel@tonic-gate timespec32_t rmtime32; 5077c478bd9Sstevel@tonic-gate 5087c478bd9Sstevel@tonic-gate TIMESPEC_TO_TIMESPEC32(&rmtime32, &rmtime); 5097c478bd9Sstevel@tonic-gate if (copyout(&rmtime32, timeoutp, sizeof (rmtime32))) 5107c478bd9Sstevel@tonic-gate error = EFAULT; 5117c478bd9Sstevel@tonic-gate } 5127c478bd9Sstevel@tonic-gate } 5137c478bd9Sstevel@tonic-gate out: 5147c478bd9Sstevel@tonic-gate schedctl_unpark(); 5157c478bd9Sstevel@tonic-gate if (t->t_mstate == LMS_USER_LOCK) 5167c478bd9Sstevel@tonic-gate (void) new_mstate(t, LMS_SYSTEM); 5177c478bd9Sstevel@tonic-gate return (error); 5187c478bd9Sstevel@tonic-gate } 5197c478bd9Sstevel@tonic-gate 5207c478bd9Sstevel@tonic-gate #define MAXLWPIDS 1024 5217c478bd9Sstevel@tonic-gate 5227c478bd9Sstevel@tonic-gate /* 5237c478bd9Sstevel@tonic-gate * Unpark all of the specified lwps. 5247c478bd9Sstevel@tonic-gate * Do it in chunks of MAXLWPIDS to avoid allocating too much memory. 5257c478bd9Sstevel@tonic-gate */ 5267c478bd9Sstevel@tonic-gate static int 5277c478bd9Sstevel@tonic-gate lwp_unpark_all(id_t *lwpidp, int nids) 5287c478bd9Sstevel@tonic-gate { 5297c478bd9Sstevel@tonic-gate proc_t *p = ttoproc(curthread); 5307c478bd9Sstevel@tonic-gate kthread_t *t; 5317c478bd9Sstevel@tonic-gate int error = 0; 5327c478bd9Sstevel@tonic-gate id_t *lwpid; 5337c478bd9Sstevel@tonic-gate size_t lwpidsz; 5347c478bd9Sstevel@tonic-gate int n; 5357c478bd9Sstevel@tonic-gate int i; 5367c478bd9Sstevel@tonic-gate 5377c478bd9Sstevel@tonic-gate if (nids <= 0) 5387c478bd9Sstevel@tonic-gate return (EINVAL); 5397c478bd9Sstevel@tonic-gate 5407c478bd9Sstevel@tonic-gate lwpidsz = MIN(nids, MAXLWPIDS) * sizeof (id_t); 5417c478bd9Sstevel@tonic-gate lwpid = kmem_alloc(lwpidsz, KM_SLEEP); 5427c478bd9Sstevel@tonic-gate while (nids > 0) { 5437c478bd9Sstevel@tonic-gate n = MIN(nids, MAXLWPIDS); 5447c478bd9Sstevel@tonic-gate if (copyin(lwpidp, lwpid, n * sizeof (id_t))) { 5457c478bd9Sstevel@tonic-gate error = EFAULT; 5467c478bd9Sstevel@tonic-gate break; 5477c478bd9Sstevel@tonic-gate } 5487c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); 5497c478bd9Sstevel@tonic-gate for (i = 0; i < n; i++) { 5507c478bd9Sstevel@tonic-gate if ((t = idtot(p, lwpid[i])) == NULL) 5517c478bd9Sstevel@tonic-gate error = ESRCH; 5527c478bd9Sstevel@tonic-gate else { 5537c478bd9Sstevel@tonic-gate mutex_enter(&t->t_delay_lock); 5547c478bd9Sstevel@tonic-gate t->t_unpark = 1; 5557c478bd9Sstevel@tonic-gate cv_signal(&t->t_delay_cv); 5567c478bd9Sstevel@tonic-gate mutex_exit(&t->t_delay_lock); 5577c478bd9Sstevel@tonic-gate } 5587c478bd9Sstevel@tonic-gate } 5597c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 5607c478bd9Sstevel@tonic-gate lwpidp += n; 5617c478bd9Sstevel@tonic-gate nids -= n; 5627c478bd9Sstevel@tonic-gate } 5637c478bd9Sstevel@tonic-gate kmem_free(lwpid, lwpidsz); 5647c478bd9Sstevel@tonic-gate return (error); 5657c478bd9Sstevel@tonic-gate } 5667c478bd9Sstevel@tonic-gate 5677c478bd9Sstevel@tonic-gate /* 5687c478bd9Sstevel@tonic-gate * SYS_lwp_park() system call. 5697c478bd9Sstevel@tonic-gate */ 5707c478bd9Sstevel@tonic-gate int 5717c478bd9Sstevel@tonic-gate syslwp_park(int which, uintptr_t arg1, uintptr_t arg2) 5727c478bd9Sstevel@tonic-gate { 5737c478bd9Sstevel@tonic-gate int error; 5747c478bd9Sstevel@tonic-gate 5757c478bd9Sstevel@tonic-gate switch (which) { 5767c478bd9Sstevel@tonic-gate case 0: 5777c478bd9Sstevel@tonic-gate error = lwp_park((timespec_t *)arg1, (id_t)arg2); 5787c478bd9Sstevel@tonic-gate break; 5797c478bd9Sstevel@tonic-gate case 1: 5807c478bd9Sstevel@tonic-gate error = lwp_unpark((id_t)arg1); 5817c478bd9Sstevel@tonic-gate break; 5827c478bd9Sstevel@tonic-gate case 2: 5837c478bd9Sstevel@tonic-gate error = lwp_unpark_all((id_t *)arg1, (int)arg2); 5847c478bd9Sstevel@tonic-gate break; 585*47eb4d1eSsl108498 case 3: 586*47eb4d1eSsl108498 /* 587*47eb4d1eSsl108498 * This subcode is not used by libc. It exists ONLY to 588*47eb4d1eSsl108498 * support older versions of libthread which do not use 589*47eb4d1eSsl108498 * the sc_park flag in the schedctl page. 590*47eb4d1eSsl108498 * 591*47eb4d1eSsl108498 * These versions of libthread need to be modifed or emulated 592*47eb4d1eSsl108498 * to change calls to syslwp_park(1, tid, 0) to 593*47eb4d1eSsl108498 * syslwp_park(3, tid). 594*47eb4d1eSsl108498 */ 595*47eb4d1eSsl108498 error = lwp_unpark_cancel((id_t)arg1); 596*47eb4d1eSsl108498 break; 597*47eb4d1eSsl108498 case 4: 598*47eb4d1eSsl108498 /* 599*47eb4d1eSsl108498 * This subcode is not used by libc. It exists ONLY to 600*47eb4d1eSsl108498 * support older versions of libthread which do not use 601*47eb4d1eSsl108498 * the sc_park flag in the schedctl page. 602*47eb4d1eSsl108498 * 603*47eb4d1eSsl108498 * These versions of libthread need to be modified or emulated 604*47eb4d1eSsl108498 * to change calls to syslwp_park(0, ts, tid) to 605*47eb4d1eSsl108498 * syslwp_park(4, ts, tid). 606*47eb4d1eSsl108498 */ 607*47eb4d1eSsl108498 schedctl_set_park(); 608*47eb4d1eSsl108498 error = lwp_park((timespec_t *)arg1, (id_t)arg2); 609*47eb4d1eSsl108498 break; 6107c478bd9Sstevel@tonic-gate default: 6117c478bd9Sstevel@tonic-gate error = EINVAL; 6127c478bd9Sstevel@tonic-gate break; 6137c478bd9Sstevel@tonic-gate } 6147c478bd9Sstevel@tonic-gate 6157c478bd9Sstevel@tonic-gate if (error) 6167c478bd9Sstevel@tonic-gate return (set_errno(error)); 6177c478bd9Sstevel@tonic-gate return (0); 6187c478bd9Sstevel@tonic-gate } 619