10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 54570Sraf * Common Development and Distribution License (the "License"). 64570Sraf * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 214570Sraf 224570Sraf /* 23*9264SRoger.Faulkner@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 244570Sraf * Use is subject to license terms. 254570Sraf */ 264570Sraf 270Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 280Sstevel@tonic-gate /* All Rights Reserved */ 290Sstevel@tonic-gate 300Sstevel@tonic-gate #include <sys/param.h> 310Sstevel@tonic-gate #include <sys/types.h> 320Sstevel@tonic-gate #include <sys/sysmacros.h> 330Sstevel@tonic-gate #include <sys/systm.h> 340Sstevel@tonic-gate #include <sys/cred.h> 350Sstevel@tonic-gate #include <sys/user.h> 360Sstevel@tonic-gate #include <sys/errno.h> 370Sstevel@tonic-gate #include <sys/file.h> 380Sstevel@tonic-gate #include <sys/proc.h> 390Sstevel@tonic-gate #include <sys/prsystm.h> 400Sstevel@tonic-gate #include <sys/kmem.h> 410Sstevel@tonic-gate #include <sys/sobject.h> 420Sstevel@tonic-gate #include <sys/fault.h> 430Sstevel@tonic-gate #include <sys/procfs.h> 440Sstevel@tonic-gate #include <sys/watchpoint.h> 450Sstevel@tonic-gate #include <sys/time.h> 460Sstevel@tonic-gate #include <sys/cmn_err.h> 470Sstevel@tonic-gate #include <sys/machlock.h> 480Sstevel@tonic-gate #include <sys/debug.h> 490Sstevel@tonic-gate #include <sys/synch.h> 500Sstevel@tonic-gate #include <sys/synch32.h> 510Sstevel@tonic-gate #include <sys/mman.h> 520Sstevel@tonic-gate #include <sys/class.h> 530Sstevel@tonic-gate #include <sys/schedctl.h> 540Sstevel@tonic-gate #include <sys/sleepq.h> 550Sstevel@tonic-gate #include <sys/policy.h> 560Sstevel@tonic-gate #include <sys/tnf_probe.h> 570Sstevel@tonic-gate #include <sys/lwpchan_impl.h> 580Sstevel@tonic-gate #include <sys/turnstile.h> 590Sstevel@tonic-gate #include <sys/atomic.h> 600Sstevel@tonic-gate #include <sys/lwp_timer_impl.h> 610Sstevel@tonic-gate #include <sys/lwp_upimutex_impl.h> 620Sstevel@tonic-gate #include <vm/as.h> 630Sstevel@tonic-gate #include <sys/sdt.h> 640Sstevel@tonic-gate 650Sstevel@tonic-gate static kthread_t *lwpsobj_owner(caddr_t); 660Sstevel@tonic-gate static void lwp_unsleep(kthread_t *t); 670Sstevel@tonic-gate static void lwp_change_pri(kthread_t *t, pri_t pri, pri_t *t_prip); 680Sstevel@tonic-gate static void lwp_mutex_cleanup(lwpchan_entry_t *ent, uint16_t lockflg); 69*9264SRoger.Faulkner@Sun.COM static void lwp_mutex_unregister(void *uaddr); 700Sstevel@tonic-gate 710Sstevel@tonic-gate extern int lwp_cond_signal(lwp_cond_t *cv); 720Sstevel@tonic-gate 730Sstevel@tonic-gate /* 740Sstevel@tonic-gate * Maximum number of user prio inheritance locks that can be held by a thread. 750Sstevel@tonic-gate * Used to limit kmem for each thread. This is a per-thread limit that 760Sstevel@tonic-gate * can be administered on a system wide basis (using /etc/system). 770Sstevel@tonic-gate * 780Sstevel@tonic-gate * Also, when a limit, say maxlwps is added for numbers of lwps within a 790Sstevel@tonic-gate * process, the per-thread limit automatically becomes a process-wide limit 800Sstevel@tonic-gate * of maximum number of held upi locks within a process: 810Sstevel@tonic-gate * maxheldupimx = maxnestupimx * maxlwps; 820Sstevel@tonic-gate */ 830Sstevel@tonic-gate static uint32_t maxnestupimx = 2000; 840Sstevel@tonic-gate 850Sstevel@tonic-gate /* 860Sstevel@tonic-gate * The sobj_ops vector exports a set of functions needed when a thread 870Sstevel@tonic-gate * is asleep on a synchronization object of this type. 880Sstevel@tonic-gate */ 890Sstevel@tonic-gate static sobj_ops_t lwp_sobj_ops = { 900Sstevel@tonic-gate SOBJ_USER, lwpsobj_owner, lwp_unsleep, lwp_change_pri 910Sstevel@tonic-gate }; 920Sstevel@tonic-gate 930Sstevel@tonic-gate static kthread_t *lwpsobj_pi_owner(upimutex_t *up); 940Sstevel@tonic-gate 950Sstevel@tonic-gate static sobj_ops_t lwp_sobj_pi_ops = { 960Sstevel@tonic-gate SOBJ_USER_PI, lwpsobj_pi_owner, turnstile_unsleep, 970Sstevel@tonic-gate turnstile_change_pri 980Sstevel@tonic-gate }; 990Sstevel@tonic-gate 1000Sstevel@tonic-gate static sleepq_head_t lwpsleepq[NSLEEPQ]; 1010Sstevel@tonic-gate upib_t upimutextab[UPIMUTEX_TABSIZE]; 1020Sstevel@tonic-gate 1030Sstevel@tonic-gate #define LWPCHAN_LOCK_SHIFT 10 /* 1024 locks for each pool */ 1040Sstevel@tonic-gate #define LWPCHAN_LOCK_SIZE (1 << LWPCHAN_LOCK_SHIFT) 1050Sstevel@tonic-gate 1060Sstevel@tonic-gate /* 1070Sstevel@tonic-gate * We know that both lc_wchan and lc_wchan0 are addresses that most 1080Sstevel@tonic-gate * likely are 8-byte aligned, so we shift off the low-order 3 bits. 1090Sstevel@tonic-gate * 'pool' is either 0 or 1. 1100Sstevel@tonic-gate */ 1110Sstevel@tonic-gate #define LWPCHAN_LOCK_HASH(X, pool) \ 1120Sstevel@tonic-gate (((((X) >> 3) ^ ((X) >> (LWPCHAN_LOCK_SHIFT + 3))) & \ 1130Sstevel@tonic-gate (LWPCHAN_LOCK_SIZE - 1)) + ((pool)? LWPCHAN_LOCK_SIZE : 0)) 1140Sstevel@tonic-gate 1150Sstevel@tonic-gate static kmutex_t lwpchanlock[2 * LWPCHAN_LOCK_SIZE]; 1160Sstevel@tonic-gate 1170Sstevel@tonic-gate /* 1180Sstevel@tonic-gate * Is this a POSIX threads user-level lock requiring priority inheritance? 1190Sstevel@tonic-gate */ 1200Sstevel@tonic-gate #define UPIMUTEX(type) ((type) & LOCK_PRIO_INHERIT) 1210Sstevel@tonic-gate 1220Sstevel@tonic-gate static sleepq_head_t * 1230Sstevel@tonic-gate lwpsqhash(lwpchan_t *lwpchan) 1240Sstevel@tonic-gate { 1250Sstevel@tonic-gate uint_t x = (uintptr_t)lwpchan->lc_wchan ^ (uintptr_t)lwpchan->lc_wchan0; 1260Sstevel@tonic-gate return (&lwpsleepq[SQHASHINDEX(x)]); 1270Sstevel@tonic-gate } 1280Sstevel@tonic-gate 1290Sstevel@tonic-gate /* 1300Sstevel@tonic-gate * Lock an lwpchan. 1310Sstevel@tonic-gate * Keep this in sync with lwpchan_unlock(), below. 1320Sstevel@tonic-gate */ 1330Sstevel@tonic-gate static void 1340Sstevel@tonic-gate lwpchan_lock(lwpchan_t *lwpchan, int pool) 1350Sstevel@tonic-gate { 1360Sstevel@tonic-gate uint_t x = (uintptr_t)lwpchan->lc_wchan ^ (uintptr_t)lwpchan->lc_wchan0; 1370Sstevel@tonic-gate mutex_enter(&lwpchanlock[LWPCHAN_LOCK_HASH(x, pool)]); 1380Sstevel@tonic-gate } 1390Sstevel@tonic-gate 1400Sstevel@tonic-gate /* 1410Sstevel@tonic-gate * Unlock an lwpchan. 1420Sstevel@tonic-gate * Keep this in sync with lwpchan_lock(), above. 1430Sstevel@tonic-gate */ 1440Sstevel@tonic-gate static void 1450Sstevel@tonic-gate lwpchan_unlock(lwpchan_t *lwpchan, int pool) 1460Sstevel@tonic-gate { 1470Sstevel@tonic-gate uint_t x = (uintptr_t)lwpchan->lc_wchan ^ (uintptr_t)lwpchan->lc_wchan0; 1480Sstevel@tonic-gate mutex_exit(&lwpchanlock[LWPCHAN_LOCK_HASH(x, pool)]); 1490Sstevel@tonic-gate } 1500Sstevel@tonic-gate 1510Sstevel@tonic-gate /* 1520Sstevel@tonic-gate * Delete mappings from the lwpchan cache for pages that are being 1530Sstevel@tonic-gate * unmapped by as_unmap(). Given a range of addresses, "start" to "end", 1540Sstevel@tonic-gate * all mappings within the range are deleted from the lwpchan cache. 1550Sstevel@tonic-gate */ 1560Sstevel@tonic-gate void 1570Sstevel@tonic-gate lwpchan_delete_mapping(proc_t *p, caddr_t start, caddr_t end) 1580Sstevel@tonic-gate { 1590Sstevel@tonic-gate lwpchan_data_t *lcp; 1600Sstevel@tonic-gate lwpchan_hashbucket_t *hashbucket; 1610Sstevel@tonic-gate lwpchan_hashbucket_t *endbucket; 1620Sstevel@tonic-gate lwpchan_entry_t *ent; 1630Sstevel@tonic-gate lwpchan_entry_t **prev; 1640Sstevel@tonic-gate caddr_t addr; 1650Sstevel@tonic-gate 1660Sstevel@tonic-gate mutex_enter(&p->p_lcp_lock); 1670Sstevel@tonic-gate lcp = p->p_lcp; 1680Sstevel@tonic-gate hashbucket = lcp->lwpchan_cache; 1690Sstevel@tonic-gate endbucket = hashbucket + lcp->lwpchan_size; 1700Sstevel@tonic-gate for (; hashbucket < endbucket; hashbucket++) { 1710Sstevel@tonic-gate if (hashbucket->lwpchan_chain == NULL) 1720Sstevel@tonic-gate continue; 1730Sstevel@tonic-gate mutex_enter(&hashbucket->lwpchan_lock); 1740Sstevel@tonic-gate prev = &hashbucket->lwpchan_chain; 1750Sstevel@tonic-gate /* check entire chain */ 1760Sstevel@tonic-gate while ((ent = *prev) != NULL) { 1770Sstevel@tonic-gate addr = ent->lwpchan_addr; 1780Sstevel@tonic-gate if (start <= addr && addr < end) { 1790Sstevel@tonic-gate *prev = ent->lwpchan_next; 1806057Sraf /* 1816057Sraf * We do this only for the obsolete type 1826057Sraf * USYNC_PROCESS_ROBUST. Otherwise robust 1836057Sraf * locks do not draw ELOCKUNMAPPED or 1846057Sraf * EOWNERDEAD due to being unmapped. 1856057Sraf */ 1860Sstevel@tonic-gate if (ent->lwpchan_pool == LWPCHAN_MPPOOL && 1876057Sraf (ent->lwpchan_type & USYNC_PROCESS_ROBUST)) 1880Sstevel@tonic-gate lwp_mutex_cleanup(ent, LOCK_UNMAPPED); 189*9264SRoger.Faulkner@Sun.COM /* 190*9264SRoger.Faulkner@Sun.COM * If there is a user-level robust lock 191*9264SRoger.Faulkner@Sun.COM * registration, mark it as invalid. 192*9264SRoger.Faulkner@Sun.COM */ 193*9264SRoger.Faulkner@Sun.COM if ((addr = ent->lwpchan_uaddr) != NULL) 194*9264SRoger.Faulkner@Sun.COM lwp_mutex_unregister(addr); 1950Sstevel@tonic-gate kmem_free(ent, sizeof (*ent)); 1960Sstevel@tonic-gate atomic_add_32(&lcp->lwpchan_entries, -1); 1970Sstevel@tonic-gate } else { 1980Sstevel@tonic-gate prev = &ent->lwpchan_next; 1990Sstevel@tonic-gate } 2000Sstevel@tonic-gate } 2010Sstevel@tonic-gate mutex_exit(&hashbucket->lwpchan_lock); 2020Sstevel@tonic-gate } 2030Sstevel@tonic-gate mutex_exit(&p->p_lcp_lock); 2040Sstevel@tonic-gate } 2050Sstevel@tonic-gate 2060Sstevel@tonic-gate /* 2070Sstevel@tonic-gate * Given an lwpchan cache pointer and a process virtual address, 2080Sstevel@tonic-gate * return a pointer to the corresponding lwpchan hash bucket. 2090Sstevel@tonic-gate */ 2100Sstevel@tonic-gate static lwpchan_hashbucket_t * 2110Sstevel@tonic-gate lwpchan_bucket(lwpchan_data_t *lcp, uintptr_t addr) 2120Sstevel@tonic-gate { 2130Sstevel@tonic-gate uint_t i; 2140Sstevel@tonic-gate 2150Sstevel@tonic-gate /* 2160Sstevel@tonic-gate * All user-level sync object addresses are 8-byte aligned. 2170Sstevel@tonic-gate * Ignore the lowest 3 bits of the address and use the 2180Sstevel@tonic-gate * higher-order 2*lwpchan_bits bits for the hash index. 2190Sstevel@tonic-gate */ 2200Sstevel@tonic-gate addr >>= 3; 2210Sstevel@tonic-gate i = (addr ^ (addr >> lcp->lwpchan_bits)) & lcp->lwpchan_mask; 2220Sstevel@tonic-gate return (lcp->lwpchan_cache + i); 2230Sstevel@tonic-gate } 2240Sstevel@tonic-gate 2250Sstevel@tonic-gate /* 2260Sstevel@tonic-gate * (Re)allocate the per-process lwpchan cache. 2270Sstevel@tonic-gate */ 2280Sstevel@tonic-gate static void 2290Sstevel@tonic-gate lwpchan_alloc_cache(proc_t *p, uint_t bits) 2300Sstevel@tonic-gate { 2310Sstevel@tonic-gate lwpchan_data_t *lcp; 2320Sstevel@tonic-gate lwpchan_data_t *old_lcp; 2330Sstevel@tonic-gate lwpchan_hashbucket_t *hashbucket; 2340Sstevel@tonic-gate lwpchan_hashbucket_t *endbucket; 2350Sstevel@tonic-gate lwpchan_hashbucket_t *newbucket; 2360Sstevel@tonic-gate lwpchan_entry_t *ent; 2370Sstevel@tonic-gate lwpchan_entry_t *next; 2380Sstevel@tonic-gate uint_t count; 2390Sstevel@tonic-gate 2400Sstevel@tonic-gate ASSERT(bits >= LWPCHAN_INITIAL_BITS && bits <= LWPCHAN_MAX_BITS); 2410Sstevel@tonic-gate 2420Sstevel@tonic-gate lcp = kmem_alloc(sizeof (lwpchan_data_t), KM_SLEEP); 2430Sstevel@tonic-gate lcp->lwpchan_bits = bits; 2440Sstevel@tonic-gate lcp->lwpchan_size = 1 << lcp->lwpchan_bits; 2450Sstevel@tonic-gate lcp->lwpchan_mask = lcp->lwpchan_size - 1; 2460Sstevel@tonic-gate lcp->lwpchan_entries = 0; 2470Sstevel@tonic-gate lcp->lwpchan_cache = kmem_zalloc(lcp->lwpchan_size * 2486057Sraf sizeof (lwpchan_hashbucket_t), KM_SLEEP); 2490Sstevel@tonic-gate lcp->lwpchan_next_data = NULL; 2500Sstevel@tonic-gate 2510Sstevel@tonic-gate mutex_enter(&p->p_lcp_lock); 2520Sstevel@tonic-gate if ((old_lcp = p->p_lcp) != NULL) { 2530Sstevel@tonic-gate if (old_lcp->lwpchan_bits >= bits) { 2540Sstevel@tonic-gate /* someone beat us to it */ 2550Sstevel@tonic-gate mutex_exit(&p->p_lcp_lock); 2560Sstevel@tonic-gate kmem_free(lcp->lwpchan_cache, lcp->lwpchan_size * 2576057Sraf sizeof (lwpchan_hashbucket_t)); 2580Sstevel@tonic-gate kmem_free(lcp, sizeof (lwpchan_data_t)); 2590Sstevel@tonic-gate return; 2600Sstevel@tonic-gate } 2610Sstevel@tonic-gate /* 2620Sstevel@tonic-gate * Acquire all of the old hash table locks. 2630Sstevel@tonic-gate */ 2640Sstevel@tonic-gate hashbucket = old_lcp->lwpchan_cache; 2650Sstevel@tonic-gate endbucket = hashbucket + old_lcp->lwpchan_size; 2660Sstevel@tonic-gate for (; hashbucket < endbucket; hashbucket++) 2670Sstevel@tonic-gate mutex_enter(&hashbucket->lwpchan_lock); 2680Sstevel@tonic-gate /* 2690Sstevel@tonic-gate * Move all of the old hash table entries to the 2700Sstevel@tonic-gate * new hash table. The new hash table has not yet 2710Sstevel@tonic-gate * been installed so we don't need any of its locks. 2720Sstevel@tonic-gate */ 2730Sstevel@tonic-gate count = 0; 2740Sstevel@tonic-gate hashbucket = old_lcp->lwpchan_cache; 2750Sstevel@tonic-gate for (; hashbucket < endbucket; hashbucket++) { 2760Sstevel@tonic-gate ent = hashbucket->lwpchan_chain; 2770Sstevel@tonic-gate while (ent != NULL) { 2780Sstevel@tonic-gate next = ent->lwpchan_next; 2790Sstevel@tonic-gate newbucket = lwpchan_bucket(lcp, 2806057Sraf (uintptr_t)ent->lwpchan_addr); 2810Sstevel@tonic-gate ent->lwpchan_next = newbucket->lwpchan_chain; 2820Sstevel@tonic-gate newbucket->lwpchan_chain = ent; 2830Sstevel@tonic-gate ent = next; 2840Sstevel@tonic-gate count++; 2850Sstevel@tonic-gate } 2860Sstevel@tonic-gate hashbucket->lwpchan_chain = NULL; 2870Sstevel@tonic-gate } 2880Sstevel@tonic-gate lcp->lwpchan_entries = count; 2890Sstevel@tonic-gate } 2900Sstevel@tonic-gate 2910Sstevel@tonic-gate /* 2920Sstevel@tonic-gate * Retire the old hash table. We can't actually kmem_free() it 2930Sstevel@tonic-gate * now because someone may still have a pointer to it. Instead, 2940Sstevel@tonic-gate * we link it onto the new hash table's list of retired hash tables. 2950Sstevel@tonic-gate * The new hash table is double the size of the previous one, so 2960Sstevel@tonic-gate * the total size of all retired hash tables is less than the size 2970Sstevel@tonic-gate * of the new one. exit() and exec() free the retired hash tables 2980Sstevel@tonic-gate * (see lwpchan_destroy_cache(), below). 2990Sstevel@tonic-gate */ 3000Sstevel@tonic-gate lcp->lwpchan_next_data = old_lcp; 3010Sstevel@tonic-gate 3020Sstevel@tonic-gate /* 3030Sstevel@tonic-gate * As soon as we store the new lcp, future locking operations will 3040Sstevel@tonic-gate * use it. Therefore, we must ensure that all the state we've just 3050Sstevel@tonic-gate * established reaches global visibility before the new lcp does. 3060Sstevel@tonic-gate */ 3070Sstevel@tonic-gate membar_producer(); 3080Sstevel@tonic-gate p->p_lcp = lcp; 3090Sstevel@tonic-gate 3100Sstevel@tonic-gate if (old_lcp != NULL) { 3110Sstevel@tonic-gate /* 3120Sstevel@tonic-gate * Release all of the old hash table locks. 3130Sstevel@tonic-gate */ 3140Sstevel@tonic-gate hashbucket = old_lcp->lwpchan_cache; 3150Sstevel@tonic-gate for (; hashbucket < endbucket; hashbucket++) 3160Sstevel@tonic-gate mutex_exit(&hashbucket->lwpchan_lock); 3170Sstevel@tonic-gate } 3180Sstevel@tonic-gate mutex_exit(&p->p_lcp_lock); 3190Sstevel@tonic-gate } 3200Sstevel@tonic-gate 3210Sstevel@tonic-gate /* 3220Sstevel@tonic-gate * Deallocate the lwpchan cache, and any dynamically allocated mappings. 3230Sstevel@tonic-gate * Called when the process exits or execs. All lwps except one have 3240Sstevel@tonic-gate * exited so we need no locks here. 3250Sstevel@tonic-gate */ 3260Sstevel@tonic-gate void 3270Sstevel@tonic-gate lwpchan_destroy_cache(int exec) 3280Sstevel@tonic-gate { 3290Sstevel@tonic-gate proc_t *p = curproc; 3300Sstevel@tonic-gate lwpchan_hashbucket_t *hashbucket; 3310Sstevel@tonic-gate lwpchan_hashbucket_t *endbucket; 3320Sstevel@tonic-gate lwpchan_data_t *lcp; 3330Sstevel@tonic-gate lwpchan_entry_t *ent; 3340Sstevel@tonic-gate lwpchan_entry_t *next; 3350Sstevel@tonic-gate uint16_t lockflg; 3360Sstevel@tonic-gate 3370Sstevel@tonic-gate lcp = p->p_lcp; 3380Sstevel@tonic-gate p->p_lcp = NULL; 3390Sstevel@tonic-gate 3400Sstevel@tonic-gate lockflg = exec? LOCK_UNMAPPED : LOCK_OWNERDEAD; 3410Sstevel@tonic-gate hashbucket = lcp->lwpchan_cache; 3420Sstevel@tonic-gate endbucket = hashbucket + lcp->lwpchan_size; 3430Sstevel@tonic-gate for (; hashbucket < endbucket; hashbucket++) { 3440Sstevel@tonic-gate ent = hashbucket->lwpchan_chain; 3450Sstevel@tonic-gate hashbucket->lwpchan_chain = NULL; 3460Sstevel@tonic-gate while (ent != NULL) { 3470Sstevel@tonic-gate next = ent->lwpchan_next; 3480Sstevel@tonic-gate if (ent->lwpchan_pool == LWPCHAN_MPPOOL && 3497751SRoger.Faulkner@Sun.COM (ent->lwpchan_type & (USYNC_PROCESS | LOCK_ROBUST)) 3507751SRoger.Faulkner@Sun.COM == (USYNC_PROCESS | LOCK_ROBUST)) 3510Sstevel@tonic-gate lwp_mutex_cleanup(ent, lockflg); 3520Sstevel@tonic-gate kmem_free(ent, sizeof (*ent)); 3530Sstevel@tonic-gate ent = next; 3540Sstevel@tonic-gate } 3550Sstevel@tonic-gate } 3560Sstevel@tonic-gate 3570Sstevel@tonic-gate while (lcp != NULL) { 3580Sstevel@tonic-gate lwpchan_data_t *next_lcp = lcp->lwpchan_next_data; 3590Sstevel@tonic-gate kmem_free(lcp->lwpchan_cache, lcp->lwpchan_size * 3606057Sraf sizeof (lwpchan_hashbucket_t)); 3610Sstevel@tonic-gate kmem_free(lcp, sizeof (lwpchan_data_t)); 3620Sstevel@tonic-gate lcp = next_lcp; 3630Sstevel@tonic-gate } 3640Sstevel@tonic-gate } 3650Sstevel@tonic-gate 3660Sstevel@tonic-gate /* 3670Sstevel@tonic-gate * Return zero when there is an entry in the lwpchan cache for the 3680Sstevel@tonic-gate * given process virtual address and non-zero when there is not. 3690Sstevel@tonic-gate * The returned non-zero value is the current length of the 3700Sstevel@tonic-gate * hash chain plus one. The caller holds the hash bucket lock. 3710Sstevel@tonic-gate */ 3720Sstevel@tonic-gate static uint_t 3730Sstevel@tonic-gate lwpchan_cache_mapping(caddr_t addr, int type, int pool, lwpchan_t *lwpchan, 3740Sstevel@tonic-gate lwpchan_hashbucket_t *hashbucket) 3750Sstevel@tonic-gate { 3760Sstevel@tonic-gate lwpchan_entry_t *ent; 3770Sstevel@tonic-gate uint_t count = 1; 3780Sstevel@tonic-gate 3790Sstevel@tonic-gate for (ent = hashbucket->lwpchan_chain; ent; ent = ent->lwpchan_next) { 3800Sstevel@tonic-gate if (ent->lwpchan_addr == addr) { 3810Sstevel@tonic-gate if (ent->lwpchan_type != type || 3820Sstevel@tonic-gate ent->lwpchan_pool != pool) { 3830Sstevel@tonic-gate /* 3840Sstevel@tonic-gate * This shouldn't happen, but might if the 3850Sstevel@tonic-gate * process reuses its memory for different 3860Sstevel@tonic-gate * types of sync objects. We test first 3870Sstevel@tonic-gate * to avoid grabbing the memory cache line. 3880Sstevel@tonic-gate */ 3890Sstevel@tonic-gate ent->lwpchan_type = (uint16_t)type; 3900Sstevel@tonic-gate ent->lwpchan_pool = (uint16_t)pool; 3910Sstevel@tonic-gate } 3920Sstevel@tonic-gate *lwpchan = ent->lwpchan_lwpchan; 3930Sstevel@tonic-gate return (0); 3940Sstevel@tonic-gate } 3950Sstevel@tonic-gate count++; 3960Sstevel@tonic-gate } 3970Sstevel@tonic-gate return (count); 3980Sstevel@tonic-gate } 3990Sstevel@tonic-gate 4000Sstevel@tonic-gate /* 4010Sstevel@tonic-gate * Return the cached lwpchan mapping if cached, otherwise insert 4020Sstevel@tonic-gate * a virtual address to lwpchan mapping into the cache. 4030Sstevel@tonic-gate */ 4040Sstevel@tonic-gate static int 405*9264SRoger.Faulkner@Sun.COM lwpchan_get_mapping(struct as *as, caddr_t addr, caddr_t uaddr, 4060Sstevel@tonic-gate int type, lwpchan_t *lwpchan, int pool) 4070Sstevel@tonic-gate { 4080Sstevel@tonic-gate proc_t *p = curproc; 4090Sstevel@tonic-gate lwpchan_data_t *lcp; 4100Sstevel@tonic-gate lwpchan_hashbucket_t *hashbucket; 4110Sstevel@tonic-gate lwpchan_entry_t *ent; 4120Sstevel@tonic-gate memid_t memid; 4130Sstevel@tonic-gate uint_t count; 4140Sstevel@tonic-gate uint_t bits; 4150Sstevel@tonic-gate 4160Sstevel@tonic-gate top: 4170Sstevel@tonic-gate /* initialize the lwpchan cache, if necesary */ 4180Sstevel@tonic-gate if ((lcp = p->p_lcp) == NULL) { 4190Sstevel@tonic-gate lwpchan_alloc_cache(p, LWPCHAN_INITIAL_BITS); 4200Sstevel@tonic-gate goto top; 4210Sstevel@tonic-gate } 4220Sstevel@tonic-gate hashbucket = lwpchan_bucket(lcp, (uintptr_t)addr); 4230Sstevel@tonic-gate mutex_enter(&hashbucket->lwpchan_lock); 4240Sstevel@tonic-gate if (lcp != p->p_lcp) { 4250Sstevel@tonic-gate /* someone resized the lwpchan cache; start over */ 4260Sstevel@tonic-gate mutex_exit(&hashbucket->lwpchan_lock); 4270Sstevel@tonic-gate goto top; 4280Sstevel@tonic-gate } 4290Sstevel@tonic-gate if (lwpchan_cache_mapping(addr, type, pool, lwpchan, hashbucket) == 0) { 4300Sstevel@tonic-gate /* it's in the cache */ 4310Sstevel@tonic-gate mutex_exit(&hashbucket->lwpchan_lock); 4320Sstevel@tonic-gate return (1); 4330Sstevel@tonic-gate } 4340Sstevel@tonic-gate mutex_exit(&hashbucket->lwpchan_lock); 4350Sstevel@tonic-gate if (as_getmemid(as, addr, &memid) != 0) 4360Sstevel@tonic-gate return (0); 4370Sstevel@tonic-gate lwpchan->lc_wchan0 = (caddr_t)(uintptr_t)memid.val[0]; 4380Sstevel@tonic-gate lwpchan->lc_wchan = (caddr_t)(uintptr_t)memid.val[1]; 4390Sstevel@tonic-gate ent = kmem_alloc(sizeof (lwpchan_entry_t), KM_SLEEP); 4400Sstevel@tonic-gate mutex_enter(&hashbucket->lwpchan_lock); 4410Sstevel@tonic-gate if (lcp != p->p_lcp) { 4420Sstevel@tonic-gate /* someone resized the lwpchan cache; start over */ 4430Sstevel@tonic-gate mutex_exit(&hashbucket->lwpchan_lock); 4440Sstevel@tonic-gate kmem_free(ent, sizeof (*ent)); 4450Sstevel@tonic-gate goto top; 4460Sstevel@tonic-gate } 4470Sstevel@tonic-gate count = lwpchan_cache_mapping(addr, type, pool, lwpchan, hashbucket); 4480Sstevel@tonic-gate if (count == 0) { 4490Sstevel@tonic-gate /* someone else added this entry to the cache */ 4500Sstevel@tonic-gate mutex_exit(&hashbucket->lwpchan_lock); 4510Sstevel@tonic-gate kmem_free(ent, sizeof (*ent)); 4520Sstevel@tonic-gate return (1); 4530Sstevel@tonic-gate } 4540Sstevel@tonic-gate if (count > lcp->lwpchan_bits + 2 && /* larger table, longer chains */ 4550Sstevel@tonic-gate (bits = lcp->lwpchan_bits) < LWPCHAN_MAX_BITS) { 4560Sstevel@tonic-gate /* hash chain too long; reallocate the hash table */ 4570Sstevel@tonic-gate mutex_exit(&hashbucket->lwpchan_lock); 4580Sstevel@tonic-gate kmem_free(ent, sizeof (*ent)); 4590Sstevel@tonic-gate lwpchan_alloc_cache(p, bits + 1); 4600Sstevel@tonic-gate goto top; 4610Sstevel@tonic-gate } 4620Sstevel@tonic-gate ent->lwpchan_addr = addr; 463*9264SRoger.Faulkner@Sun.COM ent->lwpchan_uaddr = uaddr; 4640Sstevel@tonic-gate ent->lwpchan_type = (uint16_t)type; 4650Sstevel@tonic-gate ent->lwpchan_pool = (uint16_t)pool; 4660Sstevel@tonic-gate ent->lwpchan_lwpchan = *lwpchan; 4670Sstevel@tonic-gate ent->lwpchan_next = hashbucket->lwpchan_chain; 4680Sstevel@tonic-gate hashbucket->lwpchan_chain = ent; 4690Sstevel@tonic-gate atomic_add_32(&lcp->lwpchan_entries, 1); 4700Sstevel@tonic-gate mutex_exit(&hashbucket->lwpchan_lock); 4710Sstevel@tonic-gate return (1); 4720Sstevel@tonic-gate } 4730Sstevel@tonic-gate 4740Sstevel@tonic-gate /* 4750Sstevel@tonic-gate * Return a unique pair of identifiers that corresponds to a 4760Sstevel@tonic-gate * synchronization object's virtual address. Process-shared 4770Sstevel@tonic-gate * sync objects usually get vnode/offset from as_getmemid(). 4780Sstevel@tonic-gate */ 4790Sstevel@tonic-gate static int 4800Sstevel@tonic-gate get_lwpchan(struct as *as, caddr_t addr, int type, lwpchan_t *lwpchan, int pool) 4810Sstevel@tonic-gate { 4820Sstevel@tonic-gate /* 4830Sstevel@tonic-gate * If the lwp synch object is defined to be process-private, 4840Sstevel@tonic-gate * we just make the first field of the lwpchan be 'as' and 4850Sstevel@tonic-gate * the second field be the synch object's virtual address. 4860Sstevel@tonic-gate * (segvn_getmemid() does the same for MAP_PRIVATE mappings.) 4870Sstevel@tonic-gate * The lwpchan cache is used only for process-shared objects. 4880Sstevel@tonic-gate */ 4894574Sraf if (!(type & USYNC_PROCESS)) { 4900Sstevel@tonic-gate lwpchan->lc_wchan0 = (caddr_t)as; 4910Sstevel@tonic-gate lwpchan->lc_wchan = addr; 4920Sstevel@tonic-gate return (1); 4930Sstevel@tonic-gate } 4944574Sraf 495*9264SRoger.Faulkner@Sun.COM return (lwpchan_get_mapping(as, addr, NULL, type, lwpchan, pool)); 4960Sstevel@tonic-gate } 4970Sstevel@tonic-gate 4980Sstevel@tonic-gate static void 4990Sstevel@tonic-gate lwp_block(lwpchan_t *lwpchan) 5000Sstevel@tonic-gate { 5010Sstevel@tonic-gate kthread_t *t = curthread; 5020Sstevel@tonic-gate klwp_t *lwp = ttolwp(t); 5030Sstevel@tonic-gate sleepq_head_t *sqh; 5040Sstevel@tonic-gate 5050Sstevel@tonic-gate thread_lock(t); 5060Sstevel@tonic-gate t->t_flag |= T_WAKEABLE; 5070Sstevel@tonic-gate t->t_lwpchan = *lwpchan; 5080Sstevel@tonic-gate t->t_sobj_ops = &lwp_sobj_ops; 5090Sstevel@tonic-gate t->t_release = 0; 5100Sstevel@tonic-gate sqh = lwpsqhash(lwpchan); 5110Sstevel@tonic-gate disp_lock_enter_high(&sqh->sq_lock); 5120Sstevel@tonic-gate CL_SLEEP(t); 5130Sstevel@tonic-gate DTRACE_SCHED(sleep); 5140Sstevel@tonic-gate THREAD_SLEEP(t, &sqh->sq_lock); 5150Sstevel@tonic-gate sleepq_insert(&sqh->sq_queue, t); 5160Sstevel@tonic-gate thread_unlock(t); 5170Sstevel@tonic-gate lwp->lwp_asleep = 1; 5180Sstevel@tonic-gate lwp->lwp_sysabort = 0; 5190Sstevel@tonic-gate lwp->lwp_ru.nvcsw++; 5200Sstevel@tonic-gate (void) new_mstate(curthread, LMS_SLEEP); 5210Sstevel@tonic-gate } 5220Sstevel@tonic-gate 5230Sstevel@tonic-gate static kthread_t * 5240Sstevel@tonic-gate lwpsobj_pi_owner(upimutex_t *up) 5250Sstevel@tonic-gate { 5260Sstevel@tonic-gate return (up->upi_owner); 5270Sstevel@tonic-gate } 5280Sstevel@tonic-gate 5290Sstevel@tonic-gate static struct upimutex * 5300Sstevel@tonic-gate upi_get(upib_t *upibp, lwpchan_t *lcp) 5310Sstevel@tonic-gate { 5320Sstevel@tonic-gate struct upimutex *upip; 5330Sstevel@tonic-gate 5340Sstevel@tonic-gate for (upip = upibp->upib_first; upip != NULL; 5350Sstevel@tonic-gate upip = upip->upi_nextchain) { 5360Sstevel@tonic-gate if (upip->upi_lwpchan.lc_wchan0 == lcp->lc_wchan0 && 5370Sstevel@tonic-gate upip->upi_lwpchan.lc_wchan == lcp->lc_wchan) 5380Sstevel@tonic-gate break; 5390Sstevel@tonic-gate } 5400Sstevel@tonic-gate return (upip); 5410Sstevel@tonic-gate } 5420Sstevel@tonic-gate 5430Sstevel@tonic-gate static void 5440Sstevel@tonic-gate upi_chain_add(upib_t *upibp, struct upimutex *upimutex) 5450Sstevel@tonic-gate { 5460Sstevel@tonic-gate ASSERT(MUTEX_HELD(&upibp->upib_lock)); 5470Sstevel@tonic-gate 5480Sstevel@tonic-gate /* 5490Sstevel@tonic-gate * Insert upimutex at front of list. Maybe a bit unfair 5500Sstevel@tonic-gate * but assume that not many lwpchans hash to the same 5510Sstevel@tonic-gate * upimutextab bucket, i.e. the list of upimutexes from 5520Sstevel@tonic-gate * upib_first is not too long. 5530Sstevel@tonic-gate */ 5540Sstevel@tonic-gate upimutex->upi_nextchain = upibp->upib_first; 5550Sstevel@tonic-gate upibp->upib_first = upimutex; 5560Sstevel@tonic-gate } 5570Sstevel@tonic-gate 5580Sstevel@tonic-gate static void 5590Sstevel@tonic-gate upi_chain_del(upib_t *upibp, struct upimutex *upimutex) 5600Sstevel@tonic-gate { 5610Sstevel@tonic-gate struct upimutex **prev; 5620Sstevel@tonic-gate 5630Sstevel@tonic-gate ASSERT(MUTEX_HELD(&upibp->upib_lock)); 5640Sstevel@tonic-gate 5650Sstevel@tonic-gate prev = &upibp->upib_first; 5660Sstevel@tonic-gate while (*prev != upimutex) { 5670Sstevel@tonic-gate prev = &(*prev)->upi_nextchain; 5680Sstevel@tonic-gate } 5690Sstevel@tonic-gate *prev = upimutex->upi_nextchain; 5700Sstevel@tonic-gate upimutex->upi_nextchain = NULL; 5710Sstevel@tonic-gate } 5720Sstevel@tonic-gate 5730Sstevel@tonic-gate /* 5740Sstevel@tonic-gate * Add upimutex to chain of upimutexes held by curthread. 5750Sstevel@tonic-gate * Returns number of upimutexes held by curthread. 5760Sstevel@tonic-gate */ 5770Sstevel@tonic-gate static uint32_t 5780Sstevel@tonic-gate upi_mylist_add(struct upimutex *upimutex) 5790Sstevel@tonic-gate { 5800Sstevel@tonic-gate kthread_t *t = curthread; 5810Sstevel@tonic-gate 5820Sstevel@tonic-gate /* 5830Sstevel@tonic-gate * Insert upimutex at front of list of upimutexes owned by t. This 5840Sstevel@tonic-gate * would match typical LIFO order in which nested locks are acquired 5850Sstevel@tonic-gate * and released. 5860Sstevel@tonic-gate */ 5870Sstevel@tonic-gate upimutex->upi_nextowned = t->t_upimutex; 5880Sstevel@tonic-gate t->t_upimutex = upimutex; 5890Sstevel@tonic-gate t->t_nupinest++; 5900Sstevel@tonic-gate ASSERT(t->t_nupinest > 0); 5910Sstevel@tonic-gate return (t->t_nupinest); 5920Sstevel@tonic-gate } 5930Sstevel@tonic-gate 5940Sstevel@tonic-gate /* 5950Sstevel@tonic-gate * Delete upimutex from list of upimutexes owned by curthread. 5960Sstevel@tonic-gate */ 5970Sstevel@tonic-gate static void 5980Sstevel@tonic-gate upi_mylist_del(struct upimutex *upimutex) 5990Sstevel@tonic-gate { 6000Sstevel@tonic-gate kthread_t *t = curthread; 6010Sstevel@tonic-gate struct upimutex **prev; 6020Sstevel@tonic-gate 6030Sstevel@tonic-gate /* 6040Sstevel@tonic-gate * Since the order in which nested locks are acquired and released, 6050Sstevel@tonic-gate * is typically LIFO, and typical nesting levels are not too deep, the 6060Sstevel@tonic-gate * following should not be expensive in the general case. 6070Sstevel@tonic-gate */ 6080Sstevel@tonic-gate prev = &t->t_upimutex; 6090Sstevel@tonic-gate while (*prev != upimutex) { 6100Sstevel@tonic-gate prev = &(*prev)->upi_nextowned; 6110Sstevel@tonic-gate } 6120Sstevel@tonic-gate *prev = upimutex->upi_nextowned; 6130Sstevel@tonic-gate upimutex->upi_nextowned = NULL; 6140Sstevel@tonic-gate ASSERT(t->t_nupinest > 0); 6150Sstevel@tonic-gate t->t_nupinest--; 6160Sstevel@tonic-gate } 6170Sstevel@tonic-gate 6180Sstevel@tonic-gate /* 6190Sstevel@tonic-gate * Returns true if upimutex is owned. Should be called only when upim points 6200Sstevel@tonic-gate * to kmem which cannot disappear from underneath. 6210Sstevel@tonic-gate */ 6220Sstevel@tonic-gate static int 6230Sstevel@tonic-gate upi_owned(upimutex_t *upim) 6240Sstevel@tonic-gate { 6250Sstevel@tonic-gate return (upim->upi_owner == curthread); 6260Sstevel@tonic-gate } 6270Sstevel@tonic-gate 6280Sstevel@tonic-gate /* 6290Sstevel@tonic-gate * Returns pointer to kernel object (upimutex_t *) if lp is owned. 6300Sstevel@tonic-gate */ 6310Sstevel@tonic-gate static struct upimutex * 6320Sstevel@tonic-gate lwp_upimutex_owned(lwp_mutex_t *lp, uint8_t type) 6330Sstevel@tonic-gate { 6340Sstevel@tonic-gate lwpchan_t lwpchan; 6350Sstevel@tonic-gate upib_t *upibp; 6360Sstevel@tonic-gate struct upimutex *upimutex; 6370Sstevel@tonic-gate 6380Sstevel@tonic-gate if (!get_lwpchan(curproc->p_as, (caddr_t)lp, type, 6390Sstevel@tonic-gate &lwpchan, LWPCHAN_MPPOOL)) 6400Sstevel@tonic-gate return (NULL); 6410Sstevel@tonic-gate 6420Sstevel@tonic-gate upibp = &UPI_CHAIN(lwpchan); 6430Sstevel@tonic-gate mutex_enter(&upibp->upib_lock); 6440Sstevel@tonic-gate upimutex = upi_get(upibp, &lwpchan); 6450Sstevel@tonic-gate if (upimutex == NULL || upimutex->upi_owner != curthread) { 6460Sstevel@tonic-gate mutex_exit(&upibp->upib_lock); 6470Sstevel@tonic-gate return (NULL); 6480Sstevel@tonic-gate } 6490Sstevel@tonic-gate mutex_exit(&upibp->upib_lock); 6500Sstevel@tonic-gate return (upimutex); 6510Sstevel@tonic-gate } 6520Sstevel@tonic-gate 6530Sstevel@tonic-gate /* 6540Sstevel@tonic-gate * Unlocks upimutex, waking up waiters if any. upimutex kmem is freed if 6550Sstevel@tonic-gate * no lock hand-off occurrs. 6560Sstevel@tonic-gate */ 6570Sstevel@tonic-gate static void 6580Sstevel@tonic-gate upimutex_unlock(struct upimutex *upimutex, uint16_t flag) 6590Sstevel@tonic-gate { 6600Sstevel@tonic-gate turnstile_t *ts; 6610Sstevel@tonic-gate upib_t *upibp; 6620Sstevel@tonic-gate kthread_t *newowner; 6630Sstevel@tonic-gate 6640Sstevel@tonic-gate upi_mylist_del(upimutex); 6650Sstevel@tonic-gate upibp = upimutex->upi_upibp; 6660Sstevel@tonic-gate mutex_enter(&upibp->upib_lock); 6670Sstevel@tonic-gate if (upimutex->upi_waiter != 0) { /* if waiters */ 6680Sstevel@tonic-gate ts = turnstile_lookup(upimutex); 6690Sstevel@tonic-gate if (ts != NULL && !(flag & LOCK_NOTRECOVERABLE)) { 6700Sstevel@tonic-gate /* hand-off lock to highest prio waiter */ 6710Sstevel@tonic-gate newowner = ts->ts_sleepq[TS_WRITER_Q].sq_first; 6720Sstevel@tonic-gate upimutex->upi_owner = newowner; 6730Sstevel@tonic-gate if (ts->ts_waiters == 1) 6740Sstevel@tonic-gate upimutex->upi_waiter = 0; 6750Sstevel@tonic-gate turnstile_wakeup(ts, TS_WRITER_Q, 1, newowner); 6760Sstevel@tonic-gate mutex_exit(&upibp->upib_lock); 6770Sstevel@tonic-gate return; 6780Sstevel@tonic-gate } else if (ts != NULL) { 6790Sstevel@tonic-gate /* LOCK_NOTRECOVERABLE: wakeup all */ 6800Sstevel@tonic-gate turnstile_wakeup(ts, TS_WRITER_Q, ts->ts_waiters, NULL); 6810Sstevel@tonic-gate } else { 6820Sstevel@tonic-gate /* 6830Sstevel@tonic-gate * Misleading w bit. Waiters might have been 6840Sstevel@tonic-gate * interrupted. No need to clear the w bit (upimutex 6850Sstevel@tonic-gate * will soon be freed). Re-calculate PI from existing 6860Sstevel@tonic-gate * waiters. 6870Sstevel@tonic-gate */ 6880Sstevel@tonic-gate turnstile_exit(upimutex); 6890Sstevel@tonic-gate turnstile_pi_recalc(); 6900Sstevel@tonic-gate } 6910Sstevel@tonic-gate } 6920Sstevel@tonic-gate /* 6930Sstevel@tonic-gate * no waiters, or LOCK_NOTRECOVERABLE. 6940Sstevel@tonic-gate * remove from the bucket chain of upi mutexes. 6950Sstevel@tonic-gate * de-allocate kernel memory (upimutex). 6960Sstevel@tonic-gate */ 6970Sstevel@tonic-gate upi_chain_del(upimutex->upi_upibp, upimutex); 6980Sstevel@tonic-gate mutex_exit(&upibp->upib_lock); 6990Sstevel@tonic-gate kmem_free(upimutex, sizeof (upimutex_t)); 7000Sstevel@tonic-gate } 7010Sstevel@tonic-gate 7020Sstevel@tonic-gate static int 7030Sstevel@tonic-gate lwp_upimutex_lock(lwp_mutex_t *lp, uint8_t type, int try, lwp_timer_t *lwptp) 7040Sstevel@tonic-gate { 7050Sstevel@tonic-gate label_t ljb; 7060Sstevel@tonic-gate int error = 0; 7070Sstevel@tonic-gate lwpchan_t lwpchan; 7080Sstevel@tonic-gate uint16_t flag; 7090Sstevel@tonic-gate upib_t *upibp; 7100Sstevel@tonic-gate volatile struct upimutex *upimutex = NULL; 7110Sstevel@tonic-gate turnstile_t *ts; 7120Sstevel@tonic-gate uint32_t nupinest; 7130Sstevel@tonic-gate volatile int upilocked = 0; 7140Sstevel@tonic-gate 7150Sstevel@tonic-gate if (on_fault(&ljb)) { 7160Sstevel@tonic-gate if (upilocked) 7170Sstevel@tonic-gate upimutex_unlock((upimutex_t *)upimutex, 0); 7180Sstevel@tonic-gate error = EFAULT; 7190Sstevel@tonic-gate goto out; 7200Sstevel@tonic-gate } 7210Sstevel@tonic-gate if (!get_lwpchan(curproc->p_as, (caddr_t)lp, type, 7220Sstevel@tonic-gate &lwpchan, LWPCHAN_MPPOOL)) { 7230Sstevel@tonic-gate error = EFAULT; 7240Sstevel@tonic-gate goto out; 7250Sstevel@tonic-gate } 7260Sstevel@tonic-gate upibp = &UPI_CHAIN(lwpchan); 7270Sstevel@tonic-gate retry: 7280Sstevel@tonic-gate mutex_enter(&upibp->upib_lock); 7290Sstevel@tonic-gate upimutex = upi_get(upibp, &lwpchan); 7300Sstevel@tonic-gate if (upimutex == NULL) { 7310Sstevel@tonic-gate /* lock available since lwpchan has no upimutex */ 7320Sstevel@tonic-gate upimutex = kmem_zalloc(sizeof (upimutex_t), KM_SLEEP); 7330Sstevel@tonic-gate upi_chain_add(upibp, (upimutex_t *)upimutex); 7340Sstevel@tonic-gate upimutex->upi_owner = curthread; /* grab lock */ 7350Sstevel@tonic-gate upimutex->upi_upibp = upibp; 7360Sstevel@tonic-gate upimutex->upi_vaddr = lp; 7370Sstevel@tonic-gate upimutex->upi_lwpchan = lwpchan; 7380Sstevel@tonic-gate mutex_exit(&upibp->upib_lock); 7390Sstevel@tonic-gate nupinest = upi_mylist_add((upimutex_t *)upimutex); 7400Sstevel@tonic-gate upilocked = 1; 7410Sstevel@tonic-gate fuword16_noerr(&lp->mutex_flag, &flag); 7420Sstevel@tonic-gate if (nupinest > maxnestupimx && 7430Sstevel@tonic-gate secpolicy_resource(CRED()) != 0) { 7440Sstevel@tonic-gate upimutex_unlock((upimutex_t *)upimutex, flag); 7450Sstevel@tonic-gate error = ENOMEM; 7460Sstevel@tonic-gate goto out; 7470Sstevel@tonic-gate } 7484574Sraf if (flag & LOCK_NOTRECOVERABLE) { 7490Sstevel@tonic-gate /* 7500Sstevel@tonic-gate * Since the setting of LOCK_NOTRECOVERABLE 7510Sstevel@tonic-gate * was done under the high-level upi mutex, 7520Sstevel@tonic-gate * in lwp_upimutex_unlock(), this flag needs to 7530Sstevel@tonic-gate * be checked while holding the upi mutex. 7544574Sraf * If set, this thread should return without 7554574Sraf * the lock held, and with the right error code. 7560Sstevel@tonic-gate */ 7570Sstevel@tonic-gate upimutex_unlock((upimutex_t *)upimutex, flag); 7580Sstevel@tonic-gate upilocked = 0; 7590Sstevel@tonic-gate error = ENOTRECOVERABLE; 7604574Sraf } else if (flag & (LOCK_OWNERDEAD | LOCK_UNMAPPED)) { 7614574Sraf if (flag & LOCK_OWNERDEAD) 7624574Sraf error = EOWNERDEAD; 7634574Sraf else if (type & USYNC_PROCESS_ROBUST) 7644574Sraf error = ELOCKUNMAPPED; 7654574Sraf else 7664574Sraf error = EOWNERDEAD; 7670Sstevel@tonic-gate } 7680Sstevel@tonic-gate goto out; 7690Sstevel@tonic-gate } 7700Sstevel@tonic-gate /* 7710Sstevel@tonic-gate * If a upimutex object exists, it must have an owner. 7720Sstevel@tonic-gate * This is due to lock hand-off, and release of upimutex when no 7730Sstevel@tonic-gate * waiters are present at unlock time, 7740Sstevel@tonic-gate */ 7750Sstevel@tonic-gate ASSERT(upimutex->upi_owner != NULL); 7760Sstevel@tonic-gate if (upimutex->upi_owner == curthread) { 7770Sstevel@tonic-gate /* 7780Sstevel@tonic-gate * The user wrapper can check if the mutex type is 7790Sstevel@tonic-gate * ERRORCHECK: if not, it should stall at user-level. 7800Sstevel@tonic-gate * If so, it should return the error code. 7810Sstevel@tonic-gate */ 7820Sstevel@tonic-gate mutex_exit(&upibp->upib_lock); 7830Sstevel@tonic-gate error = EDEADLK; 7840Sstevel@tonic-gate goto out; 7850Sstevel@tonic-gate } 7860Sstevel@tonic-gate if (try == UPIMUTEX_TRY) { 7870Sstevel@tonic-gate mutex_exit(&upibp->upib_lock); 7880Sstevel@tonic-gate error = EBUSY; 7890Sstevel@tonic-gate goto out; 7900Sstevel@tonic-gate } 7910Sstevel@tonic-gate /* 7920Sstevel@tonic-gate * Block for the lock. 7930Sstevel@tonic-gate * Put the lwp in an orderly state for debugging. 7940Sstevel@tonic-gate * Calling prstop() has to be done here, and not in 7950Sstevel@tonic-gate * turnstile_block(), since the preceding call to 7960Sstevel@tonic-gate * turnstile_lookup() raises the PIL to a level 7970Sstevel@tonic-gate * at which calls to prstop() should not be made. 7980Sstevel@tonic-gate */ 7990Sstevel@tonic-gate if ((error = lwptp->lwpt_time_error) != 0) { 8000Sstevel@tonic-gate /* 8010Sstevel@tonic-gate * The SUSV3 Posix spec is very clear that we 8020Sstevel@tonic-gate * should get no error from validating the 8030Sstevel@tonic-gate * timer until we would actually sleep. 8040Sstevel@tonic-gate */ 8050Sstevel@tonic-gate mutex_exit(&upibp->upib_lock); 8060Sstevel@tonic-gate goto out; 8070Sstevel@tonic-gate } 8080Sstevel@tonic-gate prstop(PR_REQUESTED, 0); 8090Sstevel@tonic-gate if (lwptp->lwpt_tsp != NULL) { 8100Sstevel@tonic-gate /* 8116622Sraf * Unlike the protocol for other lwp timedwait operations, 8126622Sraf * we must drop t_delay_lock before going to sleep in 8136622Sraf * turnstile_block() for a upi mutex. 8146622Sraf * See the comments below and in turnstile.c 8150Sstevel@tonic-gate */ 8160Sstevel@tonic-gate mutex_enter(&curthread->t_delay_lock); 8176622Sraf (void) lwp_timer_enqueue(lwptp); 8186622Sraf mutex_exit(&curthread->t_delay_lock); 8190Sstevel@tonic-gate } 8200Sstevel@tonic-gate /* 8210Sstevel@tonic-gate * Now, set the waiter bit and block for the lock in turnstile_block(). 8220Sstevel@tonic-gate * No need to preserve the previous wbit since a lock try is not 8230Sstevel@tonic-gate * attempted after setting the wait bit. Wait bit is set under 8240Sstevel@tonic-gate * the upib_lock, which is not released until the turnstile lock 8250Sstevel@tonic-gate * is acquired. Say, the upimutex is L: 8260Sstevel@tonic-gate * 8270Sstevel@tonic-gate * 1. upib_lock is held so the waiter does not have to retry L after 8280Sstevel@tonic-gate * setting the wait bit: since the owner has to grab the upib_lock 8290Sstevel@tonic-gate * to unlock L, it will certainly see the wait bit set. 8300Sstevel@tonic-gate * 2. upib_lock is not released until the turnstile lock is acquired. 8310Sstevel@tonic-gate * This is the key to preventing a missed wake-up. Otherwise, the 8320Sstevel@tonic-gate * owner could acquire the upib_lock, and the tc_lock, to call 8330Sstevel@tonic-gate * turnstile_wakeup(). All this, before the waiter gets tc_lock 8340Sstevel@tonic-gate * to sleep in turnstile_block(). turnstile_wakeup() will then not 8350Sstevel@tonic-gate * find this waiter, resulting in the missed wakeup. 8360Sstevel@tonic-gate * 3. The upib_lock, being a kernel mutex, cannot be released while 8370Sstevel@tonic-gate * holding the tc_lock (since mutex_exit() could need to acquire 8380Sstevel@tonic-gate * the same tc_lock)...and so is held when calling turnstile_block(). 8390Sstevel@tonic-gate * The address of upib_lock is passed to turnstile_block() which 8400Sstevel@tonic-gate * releases it after releasing all turnstile locks, and before going 8410Sstevel@tonic-gate * to sleep in swtch(). 8420Sstevel@tonic-gate * 4. The waiter value cannot be a count of waiters, because a waiter 8430Sstevel@tonic-gate * can be interrupted. The interrupt occurs under the tc_lock, at 8440Sstevel@tonic-gate * which point, the upib_lock cannot be locked, to decrement waiter 8450Sstevel@tonic-gate * count. So, just treat the waiter state as a bit, not a count. 8460Sstevel@tonic-gate */ 8470Sstevel@tonic-gate ts = turnstile_lookup((upimutex_t *)upimutex); 8480Sstevel@tonic-gate upimutex->upi_waiter = 1; 8490Sstevel@tonic-gate error = turnstile_block(ts, TS_WRITER_Q, (upimutex_t *)upimutex, 8500Sstevel@tonic-gate &lwp_sobj_pi_ops, &upibp->upib_lock, lwptp); 8510Sstevel@tonic-gate /* 8520Sstevel@tonic-gate * Hand-off implies that we wakeup holding the lock, except when: 8530Sstevel@tonic-gate * - deadlock is detected 8540Sstevel@tonic-gate * - lock is not recoverable 8550Sstevel@tonic-gate * - we got an interrupt or timeout 8560Sstevel@tonic-gate * If we wake up due to an interrupt or timeout, we may 8570Sstevel@tonic-gate * or may not be holding the lock due to mutex hand-off. 8580Sstevel@tonic-gate * Use lwp_upimutex_owned() to check if we do hold the lock. 8590Sstevel@tonic-gate */ 8600Sstevel@tonic-gate if (error != 0) { 8610Sstevel@tonic-gate if ((error == EINTR || error == ETIME) && 8620Sstevel@tonic-gate (upimutex = lwp_upimutex_owned(lp, type))) { 8630Sstevel@tonic-gate /* 8640Sstevel@tonic-gate * Unlock and return - the re-startable syscall will 8650Sstevel@tonic-gate * try the lock again if we got EINTR. 8660Sstevel@tonic-gate */ 8670Sstevel@tonic-gate (void) upi_mylist_add((upimutex_t *)upimutex); 8680Sstevel@tonic-gate upimutex_unlock((upimutex_t *)upimutex, 0); 8690Sstevel@tonic-gate } 8700Sstevel@tonic-gate /* 8710Sstevel@tonic-gate * The only other possible error is EDEADLK. If so, upimutex 8720Sstevel@tonic-gate * is valid, since its owner is deadlocked with curthread. 8730Sstevel@tonic-gate */ 8740Sstevel@tonic-gate ASSERT(error == EINTR || error == ETIME || 8750Sstevel@tonic-gate (error == EDEADLK && !upi_owned((upimutex_t *)upimutex))); 8760Sstevel@tonic-gate ASSERT(!lwp_upimutex_owned(lp, type)); 8770Sstevel@tonic-gate goto out; 8780Sstevel@tonic-gate } 8790Sstevel@tonic-gate if (lwp_upimutex_owned(lp, type)) { 8800Sstevel@tonic-gate ASSERT(lwp_upimutex_owned(lp, type) == upimutex); 8810Sstevel@tonic-gate nupinest = upi_mylist_add((upimutex_t *)upimutex); 8820Sstevel@tonic-gate upilocked = 1; 8830Sstevel@tonic-gate } 8840Sstevel@tonic-gate /* 8850Sstevel@tonic-gate * Now, need to read the user-level lp->mutex_flag to do the following: 8860Sstevel@tonic-gate * 8874574Sraf * - if lock is held, check if EOWNERDEAD or ELOCKUNMAPPED 8884574Sraf * should be returned. 8894574Sraf * - if lock isn't held, check if ENOTRECOVERABLE should 8904574Sraf * be returned. 8910Sstevel@tonic-gate * 8920Sstevel@tonic-gate * Now, either lp->mutex_flag is readable or it's not. If not 8934574Sraf * readable, the on_fault path will cause a return with EFAULT 8944574Sraf * as it should. If it is readable, the state of the flag 8954574Sraf * encodes the robustness state of the lock: 8960Sstevel@tonic-gate * 8974574Sraf * If the upimutex is locked here, the flag's LOCK_OWNERDEAD 8984574Sraf * or LOCK_UNMAPPED setting will influence the return code 8994574Sraf * appropriately. If the upimutex is not locked here, this 9004574Sraf * could be due to a spurious wake-up or a NOTRECOVERABLE 9014574Sraf * event. The flag's setting can be used to distinguish 9020Sstevel@tonic-gate * between these two events. 9030Sstevel@tonic-gate */ 9040Sstevel@tonic-gate fuword16_noerr(&lp->mutex_flag, &flag); 9050Sstevel@tonic-gate if (upilocked) { 9060Sstevel@tonic-gate /* 9070Sstevel@tonic-gate * If the thread wakes up from turnstile_block with the lock 9080Sstevel@tonic-gate * held, the flag could not be set to LOCK_NOTRECOVERABLE, 9090Sstevel@tonic-gate * since it would not have been handed-off the lock. 9100Sstevel@tonic-gate * So, no need to check for this case. 9110Sstevel@tonic-gate */ 9120Sstevel@tonic-gate if (nupinest > maxnestupimx && 9130Sstevel@tonic-gate secpolicy_resource(CRED()) != 0) { 9140Sstevel@tonic-gate upimutex_unlock((upimutex_t *)upimutex, flag); 9150Sstevel@tonic-gate upilocked = 0; 9160Sstevel@tonic-gate error = ENOMEM; 9174574Sraf } else if (flag & (LOCK_OWNERDEAD | LOCK_UNMAPPED)) { 9184574Sraf if (flag & LOCK_OWNERDEAD) 9194574Sraf error = EOWNERDEAD; 9204574Sraf else if (type & USYNC_PROCESS_ROBUST) 9214574Sraf error = ELOCKUNMAPPED; 9224574Sraf else 9234574Sraf error = EOWNERDEAD; 9240Sstevel@tonic-gate } 9250Sstevel@tonic-gate } else { 9260Sstevel@tonic-gate /* 9270Sstevel@tonic-gate * Wake-up without the upimutex held. Either this is a 9280Sstevel@tonic-gate * spurious wake-up (due to signals, forkall(), whatever), or 9290Sstevel@tonic-gate * it is a LOCK_NOTRECOVERABLE robustness event. The setting 9300Sstevel@tonic-gate * of the mutex flag can be used to distinguish between the 9310Sstevel@tonic-gate * two events. 9320Sstevel@tonic-gate */ 9330Sstevel@tonic-gate if (flag & LOCK_NOTRECOVERABLE) { 9340Sstevel@tonic-gate error = ENOTRECOVERABLE; 9350Sstevel@tonic-gate } else { 9360Sstevel@tonic-gate /* 9370Sstevel@tonic-gate * Here, the flag could be set to LOCK_OWNERDEAD or 9380Sstevel@tonic-gate * not. In both cases, this is a spurious wakeup, 9390Sstevel@tonic-gate * since the upi lock is not held, but the thread 9400Sstevel@tonic-gate * has returned from turnstile_block(). 9410Sstevel@tonic-gate * 9420Sstevel@tonic-gate * The user flag could be LOCK_OWNERDEAD if, at the 9430Sstevel@tonic-gate * same time as curthread having been woken up 9440Sstevel@tonic-gate * spuriously, the owner (say Tdead) has died, marked 9450Sstevel@tonic-gate * the mutex flag accordingly, and handed off the lock 9460Sstevel@tonic-gate * to some other waiter (say Tnew). curthread just 9470Sstevel@tonic-gate * happened to read the flag while Tnew has yet to deal 9480Sstevel@tonic-gate * with the owner-dead event. 9490Sstevel@tonic-gate * 9500Sstevel@tonic-gate * In this event, curthread should retry the lock. 9510Sstevel@tonic-gate * If Tnew is able to cleanup the lock, curthread 9520Sstevel@tonic-gate * will eventually get the lock with a zero error code, 9530Sstevel@tonic-gate * If Tnew is unable to cleanup, its eventual call to 9540Sstevel@tonic-gate * unlock the lock will result in the mutex flag being 9550Sstevel@tonic-gate * set to LOCK_NOTRECOVERABLE, and the wake-up of 9560Sstevel@tonic-gate * all waiters, including curthread, which will then 9570Sstevel@tonic-gate * eventually return ENOTRECOVERABLE due to the above 9580Sstevel@tonic-gate * check. 9590Sstevel@tonic-gate * 9600Sstevel@tonic-gate * Of course, if the user-flag is not set with 9610Sstevel@tonic-gate * LOCK_OWNERDEAD, retrying is the thing to do, since 9620Sstevel@tonic-gate * this is definitely a spurious wakeup. 9630Sstevel@tonic-gate */ 9640Sstevel@tonic-gate goto retry; 9650Sstevel@tonic-gate } 9660Sstevel@tonic-gate } 9670Sstevel@tonic-gate 9680Sstevel@tonic-gate out: 9690Sstevel@tonic-gate no_fault(); 9700Sstevel@tonic-gate return (error); 9710Sstevel@tonic-gate } 9720Sstevel@tonic-gate 9730Sstevel@tonic-gate 9740Sstevel@tonic-gate static int 9750Sstevel@tonic-gate lwp_upimutex_unlock(lwp_mutex_t *lp, uint8_t type) 9760Sstevel@tonic-gate { 9770Sstevel@tonic-gate label_t ljb; 9780Sstevel@tonic-gate int error = 0; 9790Sstevel@tonic-gate lwpchan_t lwpchan; 9800Sstevel@tonic-gate uint16_t flag; 9810Sstevel@tonic-gate upib_t *upibp; 9820Sstevel@tonic-gate volatile struct upimutex *upimutex = NULL; 9830Sstevel@tonic-gate volatile int upilocked = 0; 9840Sstevel@tonic-gate 9850Sstevel@tonic-gate if (on_fault(&ljb)) { 9860Sstevel@tonic-gate if (upilocked) 9870Sstevel@tonic-gate upimutex_unlock((upimutex_t *)upimutex, 0); 9880Sstevel@tonic-gate error = EFAULT; 9890Sstevel@tonic-gate goto out; 9900Sstevel@tonic-gate } 9910Sstevel@tonic-gate if (!get_lwpchan(curproc->p_as, (caddr_t)lp, type, 9920Sstevel@tonic-gate &lwpchan, LWPCHAN_MPPOOL)) { 9930Sstevel@tonic-gate error = EFAULT; 9940Sstevel@tonic-gate goto out; 9950Sstevel@tonic-gate } 9960Sstevel@tonic-gate upibp = &UPI_CHAIN(lwpchan); 9970Sstevel@tonic-gate mutex_enter(&upibp->upib_lock); 9980Sstevel@tonic-gate upimutex = upi_get(upibp, &lwpchan); 9990Sstevel@tonic-gate /* 10000Sstevel@tonic-gate * If the lock is not held, or the owner is not curthread, return 10010Sstevel@tonic-gate * error. The user-level wrapper can return this error or stall, 10020Sstevel@tonic-gate * depending on whether mutex is of ERRORCHECK type or not. 10030Sstevel@tonic-gate */ 10040Sstevel@tonic-gate if (upimutex == NULL || upimutex->upi_owner != curthread) { 10050Sstevel@tonic-gate mutex_exit(&upibp->upib_lock); 10060Sstevel@tonic-gate error = EPERM; 10070Sstevel@tonic-gate goto out; 10080Sstevel@tonic-gate } 10090Sstevel@tonic-gate mutex_exit(&upibp->upib_lock); /* release for user memory access */ 10100Sstevel@tonic-gate upilocked = 1; 10110Sstevel@tonic-gate fuword16_noerr(&lp->mutex_flag, &flag); 10124574Sraf if (flag & (LOCK_OWNERDEAD | LOCK_UNMAPPED)) { 10130Sstevel@tonic-gate /* 10140Sstevel@tonic-gate * transition mutex to the LOCK_NOTRECOVERABLE state. 10150Sstevel@tonic-gate */ 10164574Sraf flag &= ~(LOCK_OWNERDEAD | LOCK_UNMAPPED); 10170Sstevel@tonic-gate flag |= LOCK_NOTRECOVERABLE; 10180Sstevel@tonic-gate suword16_noerr(&lp->mutex_flag, flag); 10190Sstevel@tonic-gate } 10204574Sraf if (type & USYNC_PROCESS) 10214574Sraf suword32_noerr(&lp->mutex_ownerpid, 0); 10220Sstevel@tonic-gate upimutex_unlock((upimutex_t *)upimutex, flag); 10230Sstevel@tonic-gate upilocked = 0; 10240Sstevel@tonic-gate out: 10250Sstevel@tonic-gate no_fault(); 10260Sstevel@tonic-gate return (error); 10270Sstevel@tonic-gate } 10280Sstevel@tonic-gate 10290Sstevel@tonic-gate /* 10304574Sraf * Clear the contents of a user-level mutex; return the flags. 10314574Sraf * Used only by upi_dead() and lwp_mutex_cleanup(), below. 10324574Sraf */ 10334574Sraf static uint16_t 10344574Sraf lwp_clear_mutex(lwp_mutex_t *lp, uint16_t lockflg) 10354574Sraf { 10364574Sraf uint16_t flag; 10374574Sraf 10384574Sraf fuword16_noerr(&lp->mutex_flag, &flag); 10396057Sraf if ((flag & 10406057Sraf (LOCK_OWNERDEAD | LOCK_UNMAPPED | LOCK_NOTRECOVERABLE)) == 0) { 10414574Sraf flag |= lockflg; 10424574Sraf suword16_noerr(&lp->mutex_flag, flag); 10434574Sraf } 10444574Sraf suword32_noerr((uint32_t *)&lp->mutex_owner, 0); 10454574Sraf suword32_noerr((uint32_t *)&lp->mutex_owner + 1, 0); 10464574Sraf suword32_noerr(&lp->mutex_ownerpid, 0); 10474574Sraf suword8_noerr(&lp->mutex_rcount, 0); 10484574Sraf 10494574Sraf return (flag); 10504574Sraf } 10514574Sraf 10524574Sraf /* 10534574Sraf * Mark user mutex state, corresponding to kernel upimutex, 10544574Sraf * as LOCK_UNMAPPED or LOCK_OWNERDEAD, as appropriate 10550Sstevel@tonic-gate */ 10560Sstevel@tonic-gate static int 10574574Sraf upi_dead(upimutex_t *upip, uint16_t lockflg) 10580Sstevel@tonic-gate { 10590Sstevel@tonic-gate label_t ljb; 10600Sstevel@tonic-gate int error = 0; 10610Sstevel@tonic-gate lwp_mutex_t *lp; 10620Sstevel@tonic-gate 10630Sstevel@tonic-gate if (on_fault(&ljb)) { 10640Sstevel@tonic-gate error = EFAULT; 10650Sstevel@tonic-gate goto out; 10660Sstevel@tonic-gate } 10670Sstevel@tonic-gate 10680Sstevel@tonic-gate lp = upip->upi_vaddr; 10694574Sraf (void) lwp_clear_mutex(lp, lockflg); 10704574Sraf suword8_noerr(&lp->mutex_lockw, 0); 10710Sstevel@tonic-gate out: 10720Sstevel@tonic-gate no_fault(); 10730Sstevel@tonic-gate return (error); 10740Sstevel@tonic-gate } 10750Sstevel@tonic-gate 10760Sstevel@tonic-gate /* 10770Sstevel@tonic-gate * Unlock all upimutexes held by curthread, since curthread is dying. 10780Sstevel@tonic-gate * For each upimutex, attempt to mark its corresponding user mutex object as 10790Sstevel@tonic-gate * dead. 10800Sstevel@tonic-gate */ 10810Sstevel@tonic-gate void 10820Sstevel@tonic-gate upimutex_cleanup() 10830Sstevel@tonic-gate { 10840Sstevel@tonic-gate kthread_t *t = curthread; 10854574Sraf uint16_t lockflg = (ttoproc(t)->p_proc_flag & P_PR_EXEC)? 10864574Sraf LOCK_UNMAPPED : LOCK_OWNERDEAD; 10870Sstevel@tonic-gate struct upimutex *upip; 10880Sstevel@tonic-gate 10890Sstevel@tonic-gate while ((upip = t->t_upimutex) != NULL) { 10904574Sraf if (upi_dead(upip, lockflg) != 0) { 10910Sstevel@tonic-gate /* 10920Sstevel@tonic-gate * If the user object associated with this upimutex is 10930Sstevel@tonic-gate * unmapped, unlock upimutex with the 10940Sstevel@tonic-gate * LOCK_NOTRECOVERABLE flag, so that all waiters are 10950Sstevel@tonic-gate * woken up. Since user object is unmapped, it could 10960Sstevel@tonic-gate * not be marked as dead or notrecoverable. 10970Sstevel@tonic-gate * The waiters will now all wake up and return 10980Sstevel@tonic-gate * ENOTRECOVERABLE, since they would find that the lock 10990Sstevel@tonic-gate * has not been handed-off to them. 11000Sstevel@tonic-gate * See lwp_upimutex_lock(). 11010Sstevel@tonic-gate */ 11020Sstevel@tonic-gate upimutex_unlock(upip, LOCK_NOTRECOVERABLE); 11030Sstevel@tonic-gate } else { 11040Sstevel@tonic-gate /* 11050Sstevel@tonic-gate * The user object has been updated as dead. 11060Sstevel@tonic-gate * Unlock the upimutex: if no waiters, upip kmem will 11070Sstevel@tonic-gate * be freed. If there is a waiter, the lock will be 11080Sstevel@tonic-gate * handed off. If exit() is in progress, each existing 11090Sstevel@tonic-gate * waiter will successively get the lock, as owners 11100Sstevel@tonic-gate * die, and each new owner will call this routine as 11110Sstevel@tonic-gate * it dies. The last owner will free kmem, since 11120Sstevel@tonic-gate * it will find the upimutex has no waiters. So, 11130Sstevel@tonic-gate * eventually, the kmem is guaranteed to be freed. 11140Sstevel@tonic-gate */ 11150Sstevel@tonic-gate upimutex_unlock(upip, 0); 11160Sstevel@tonic-gate } 11170Sstevel@tonic-gate /* 11180Sstevel@tonic-gate * Note that the call to upimutex_unlock() above will delete 11190Sstevel@tonic-gate * upimutex from the t_upimutexes chain. And so the 11200Sstevel@tonic-gate * while loop will eventually terminate. 11210Sstevel@tonic-gate */ 11220Sstevel@tonic-gate } 11230Sstevel@tonic-gate } 11240Sstevel@tonic-gate 11250Sstevel@tonic-gate int 11260Sstevel@tonic-gate lwp_mutex_timedlock(lwp_mutex_t *lp, timespec_t *tsp) 11270Sstevel@tonic-gate { 11280Sstevel@tonic-gate kthread_t *t = curthread; 11290Sstevel@tonic-gate klwp_t *lwp = ttolwp(t); 11300Sstevel@tonic-gate proc_t *p = ttoproc(t); 11310Sstevel@tonic-gate lwp_timer_t lwpt; 11320Sstevel@tonic-gate caddr_t timedwait; 11330Sstevel@tonic-gate int error = 0; 11340Sstevel@tonic-gate int time_error; 11350Sstevel@tonic-gate clock_t tim = -1; 11360Sstevel@tonic-gate uchar_t waiters; 11370Sstevel@tonic-gate volatile int locked = 0; 11380Sstevel@tonic-gate volatile int watched = 0; 11390Sstevel@tonic-gate label_t ljb; 11400Sstevel@tonic-gate volatile uint8_t type = 0; 11410Sstevel@tonic-gate lwpchan_t lwpchan; 11420Sstevel@tonic-gate sleepq_head_t *sqh; 11430Sstevel@tonic-gate static int iswanted(); 11440Sstevel@tonic-gate uint16_t flag; 11450Sstevel@tonic-gate int imm_timeout = 0; 11460Sstevel@tonic-gate 11470Sstevel@tonic-gate if ((caddr_t)lp >= p->p_as->a_userlimit) 11480Sstevel@tonic-gate return (set_errno(EFAULT)); 11490Sstevel@tonic-gate 11500Sstevel@tonic-gate timedwait = (caddr_t)tsp; 11510Sstevel@tonic-gate if ((time_error = lwp_timer_copyin(&lwpt, tsp)) == 0 && 11520Sstevel@tonic-gate lwpt.lwpt_imm_timeout) { 11530Sstevel@tonic-gate imm_timeout = 1; 11540Sstevel@tonic-gate timedwait = NULL; 11550Sstevel@tonic-gate } 11560Sstevel@tonic-gate 11570Sstevel@tonic-gate /* 11580Sstevel@tonic-gate * Although LMS_USER_LOCK implies "asleep waiting for user-mode lock", 11590Sstevel@tonic-gate * this micro state is really a run state. If the thread indeed blocks, 11600Sstevel@tonic-gate * this state becomes valid. If not, the state is converted back to 11610Sstevel@tonic-gate * LMS_SYSTEM. So, it is OK to set the mstate here, instead of just 11620Sstevel@tonic-gate * when blocking. 11630Sstevel@tonic-gate */ 11640Sstevel@tonic-gate (void) new_mstate(t, LMS_USER_LOCK); 11650Sstevel@tonic-gate if (on_fault(&ljb)) { 11660Sstevel@tonic-gate if (locked) 11670Sstevel@tonic-gate lwpchan_unlock(&lwpchan, LWPCHAN_MPPOOL); 11680Sstevel@tonic-gate error = EFAULT; 11690Sstevel@tonic-gate goto out; 11700Sstevel@tonic-gate } 11716577Sraf /* 11726577Sraf * Force Copy-on-write if necessary and ensure that the 11736577Sraf * synchronization object resides in read/write memory. 11746577Sraf * Cause an EFAULT return now if this is not so. 11756577Sraf */ 11760Sstevel@tonic-gate fuword8_noerr(&lp->mutex_type, (uint8_t *)&type); 11776577Sraf suword8_noerr(&lp->mutex_type, type); 11780Sstevel@tonic-gate if (UPIMUTEX(type)) { 11790Sstevel@tonic-gate no_fault(); 11800Sstevel@tonic-gate error = lwp_upimutex_lock(lp, type, UPIMUTEX_BLOCK, &lwpt); 11814574Sraf if ((type & USYNC_PROCESS) && 11824574Sraf (error == 0 || 11834574Sraf error == EOWNERDEAD || error == ELOCKUNMAPPED)) 11840Sstevel@tonic-gate (void) suword32(&lp->mutex_ownerpid, p->p_pid); 11850Sstevel@tonic-gate if (tsp && !time_error) /* copyout the residual time left */ 11860Sstevel@tonic-gate error = lwp_timer_copyout(&lwpt, error); 11870Sstevel@tonic-gate if (error) 11880Sstevel@tonic-gate return (set_errno(error)); 11890Sstevel@tonic-gate return (0); 11900Sstevel@tonic-gate } 11910Sstevel@tonic-gate if (!get_lwpchan(curproc->p_as, (caddr_t)lp, type, 11920Sstevel@tonic-gate &lwpchan, LWPCHAN_MPPOOL)) { 11930Sstevel@tonic-gate error = EFAULT; 11940Sstevel@tonic-gate goto out; 11950Sstevel@tonic-gate } 11960Sstevel@tonic-gate lwpchan_lock(&lwpchan, LWPCHAN_MPPOOL); 11970Sstevel@tonic-gate locked = 1; 11984574Sraf if (type & LOCK_ROBUST) { 11990Sstevel@tonic-gate fuword16_noerr(&lp->mutex_flag, &flag); 12000Sstevel@tonic-gate if (flag & LOCK_NOTRECOVERABLE) { 12010Sstevel@tonic-gate lwpchan_unlock(&lwpchan, LWPCHAN_MPPOOL); 12020Sstevel@tonic-gate error = ENOTRECOVERABLE; 12030Sstevel@tonic-gate goto out; 12040Sstevel@tonic-gate } 12050Sstevel@tonic-gate } 12064574Sraf fuword8_noerr(&lp->mutex_waiters, &waiters); 12074574Sraf suword8_noerr(&lp->mutex_waiters, 1); 12080Sstevel@tonic-gate 12090Sstevel@tonic-gate /* 12100Sstevel@tonic-gate * If watchpoints are set, they need to be restored, since 12110Sstevel@tonic-gate * atomic accesses of memory such as the call to ulock_try() 12120Sstevel@tonic-gate * below cannot be watched. 12130Sstevel@tonic-gate */ 12140Sstevel@tonic-gate 12150Sstevel@tonic-gate watched = watch_disable_addr((caddr_t)lp, sizeof (*lp), S_WRITE); 12160Sstevel@tonic-gate 12170Sstevel@tonic-gate while (!ulock_try(&lp->mutex_lockw)) { 12180Sstevel@tonic-gate if (time_error) { 12190Sstevel@tonic-gate /* 12200Sstevel@tonic-gate * The SUSV3 Posix spec is very clear that we 12210Sstevel@tonic-gate * should get no error from validating the 12220Sstevel@tonic-gate * timer until we would actually sleep. 12230Sstevel@tonic-gate */ 12240Sstevel@tonic-gate error = time_error; 12250Sstevel@tonic-gate break; 12260Sstevel@tonic-gate } 12270Sstevel@tonic-gate 12280Sstevel@tonic-gate if (watched) { 12290Sstevel@tonic-gate watch_enable_addr((caddr_t)lp, sizeof (*lp), S_WRITE); 12300Sstevel@tonic-gate watched = 0; 12310Sstevel@tonic-gate } 12320Sstevel@tonic-gate 12330Sstevel@tonic-gate /* 12340Sstevel@tonic-gate * Put the lwp in an orderly state for debugging. 12350Sstevel@tonic-gate */ 12360Sstevel@tonic-gate prstop(PR_REQUESTED, 0); 12370Sstevel@tonic-gate if (timedwait) { 12380Sstevel@tonic-gate /* 12390Sstevel@tonic-gate * If we successfully queue the timeout, 12400Sstevel@tonic-gate * then don't drop t_delay_lock until 12410Sstevel@tonic-gate * we are on the sleep queue (below). 12420Sstevel@tonic-gate */ 12430Sstevel@tonic-gate mutex_enter(&t->t_delay_lock); 12440Sstevel@tonic-gate if (lwp_timer_enqueue(&lwpt) != 0) { 12450Sstevel@tonic-gate mutex_exit(&t->t_delay_lock); 12460Sstevel@tonic-gate imm_timeout = 1; 12470Sstevel@tonic-gate timedwait = NULL; 12480Sstevel@tonic-gate } 12490Sstevel@tonic-gate } 12500Sstevel@tonic-gate lwp_block(&lwpchan); 12510Sstevel@tonic-gate /* 12520Sstevel@tonic-gate * Nothing should happen to cause the lwp to go to 12530Sstevel@tonic-gate * sleep again until after it returns from swtch(). 12540Sstevel@tonic-gate */ 12550Sstevel@tonic-gate if (timedwait) 12560Sstevel@tonic-gate mutex_exit(&t->t_delay_lock); 12570Sstevel@tonic-gate locked = 0; 12580Sstevel@tonic-gate lwpchan_unlock(&lwpchan, LWPCHAN_MPPOOL); 12590Sstevel@tonic-gate if (ISSIG(t, JUSTLOOKING) || MUSTRETURN(p, t) || imm_timeout) 12600Sstevel@tonic-gate setrun(t); 12610Sstevel@tonic-gate swtch(); 12620Sstevel@tonic-gate t->t_flag &= ~T_WAKEABLE; 12630Sstevel@tonic-gate if (timedwait) 12640Sstevel@tonic-gate tim = lwp_timer_dequeue(&lwpt); 12650Sstevel@tonic-gate setallwatch(); 12660Sstevel@tonic-gate if (ISSIG(t, FORREAL) || lwp->lwp_sysabort || MUSTRETURN(p, t)) 12670Sstevel@tonic-gate error = EINTR; 12680Sstevel@tonic-gate else if (imm_timeout || (timedwait && tim == -1)) 12690Sstevel@tonic-gate error = ETIME; 12700Sstevel@tonic-gate if (error) { 12710Sstevel@tonic-gate lwp->lwp_asleep = 0; 12720Sstevel@tonic-gate lwp->lwp_sysabort = 0; 12730Sstevel@tonic-gate watched = watch_disable_addr((caddr_t)lp, sizeof (*lp), 12740Sstevel@tonic-gate S_WRITE); 12750Sstevel@tonic-gate 12760Sstevel@tonic-gate /* 12770Sstevel@tonic-gate * Need to re-compute waiters bit. The waiters field in 12780Sstevel@tonic-gate * the lock is not reliable. Either of two things could 12790Sstevel@tonic-gate * have occurred: no lwp may have called lwp_release() 12800Sstevel@tonic-gate * for me but I have woken up due to a signal or 12810Sstevel@tonic-gate * timeout. In this case, the waiter bit is incorrect 12820Sstevel@tonic-gate * since it is still set to 1, set above. 12830Sstevel@tonic-gate * OR an lwp_release() did occur for some other lwp on 12840Sstevel@tonic-gate * the same lwpchan. In this case, the waiter bit is 12850Sstevel@tonic-gate * correct. But which event occurred, one can't tell. 12860Sstevel@tonic-gate * So, recompute. 12870Sstevel@tonic-gate */ 12880Sstevel@tonic-gate lwpchan_lock(&lwpchan, LWPCHAN_MPPOOL); 12890Sstevel@tonic-gate locked = 1; 12900Sstevel@tonic-gate sqh = lwpsqhash(&lwpchan); 12910Sstevel@tonic-gate disp_lock_enter(&sqh->sq_lock); 12920Sstevel@tonic-gate waiters = iswanted(sqh->sq_queue.sq_first, &lwpchan); 12930Sstevel@tonic-gate disp_lock_exit(&sqh->sq_lock); 12940Sstevel@tonic-gate break; 12950Sstevel@tonic-gate } 12960Sstevel@tonic-gate lwp->lwp_asleep = 0; 12970Sstevel@tonic-gate watched = watch_disable_addr((caddr_t)lp, sizeof (*lp), 12980Sstevel@tonic-gate S_WRITE); 12990Sstevel@tonic-gate lwpchan_lock(&lwpchan, LWPCHAN_MPPOOL); 13000Sstevel@tonic-gate locked = 1; 13010Sstevel@tonic-gate fuword8_noerr(&lp->mutex_waiters, &waiters); 13020Sstevel@tonic-gate suword8_noerr(&lp->mutex_waiters, 1); 13034574Sraf if (type & LOCK_ROBUST) { 13040Sstevel@tonic-gate fuword16_noerr(&lp->mutex_flag, &flag); 13050Sstevel@tonic-gate if (flag & LOCK_NOTRECOVERABLE) { 13060Sstevel@tonic-gate error = ENOTRECOVERABLE; 13070Sstevel@tonic-gate break; 13080Sstevel@tonic-gate } 13090Sstevel@tonic-gate } 13100Sstevel@tonic-gate } 13110Sstevel@tonic-gate 13120Sstevel@tonic-gate if (t->t_mstate == LMS_USER_LOCK) 13130Sstevel@tonic-gate (void) new_mstate(t, LMS_SYSTEM); 13140Sstevel@tonic-gate 13154574Sraf if (error == 0) { 13164574Sraf if (type & USYNC_PROCESS) 13174574Sraf suword32_noerr(&lp->mutex_ownerpid, p->p_pid); 13184574Sraf if (type & LOCK_ROBUST) { 13190Sstevel@tonic-gate fuword16_noerr(&lp->mutex_flag, &flag); 13204574Sraf if (flag & (LOCK_OWNERDEAD | LOCK_UNMAPPED)) { 13214574Sraf if (flag & LOCK_OWNERDEAD) 13224574Sraf error = EOWNERDEAD; 13234574Sraf else if (type & USYNC_PROCESS_ROBUST) 13244574Sraf error = ELOCKUNMAPPED; 13254574Sraf else 13264574Sraf error = EOWNERDEAD; 13274574Sraf } 13280Sstevel@tonic-gate } 13290Sstevel@tonic-gate } 13300Sstevel@tonic-gate suword8_noerr(&lp->mutex_waiters, waiters); 13310Sstevel@tonic-gate locked = 0; 13320Sstevel@tonic-gate lwpchan_unlock(&lwpchan, LWPCHAN_MPPOOL); 13330Sstevel@tonic-gate out: 13340Sstevel@tonic-gate no_fault(); 13350Sstevel@tonic-gate if (watched) 13360Sstevel@tonic-gate watch_enable_addr((caddr_t)lp, sizeof (*lp), S_WRITE); 13370Sstevel@tonic-gate if (tsp && !time_error) /* copyout the residual time left */ 13380Sstevel@tonic-gate error = lwp_timer_copyout(&lwpt, error); 13390Sstevel@tonic-gate if (error) 13400Sstevel@tonic-gate return (set_errno(error)); 13410Sstevel@tonic-gate return (0); 13420Sstevel@tonic-gate } 13430Sstevel@tonic-gate 13440Sstevel@tonic-gate /* 13450Sstevel@tonic-gate * Obsolete lwp_mutex_lock() interface, no longer called from libc. 13460Sstevel@tonic-gate * libc now calls lwp_mutex_timedlock(lp, NULL). 13470Sstevel@tonic-gate * This system call trap continues to exist solely for the benefit 13480Sstevel@tonic-gate * of old statically-linked binaries from Solaris 9 and before. 13490Sstevel@tonic-gate * It should be removed from the system when we no longer care 13500Sstevel@tonic-gate * about such applications. 13510Sstevel@tonic-gate */ 13520Sstevel@tonic-gate int 13530Sstevel@tonic-gate lwp_mutex_lock(lwp_mutex_t *lp) 13540Sstevel@tonic-gate { 13550Sstevel@tonic-gate return (lwp_mutex_timedlock(lp, NULL)); 13560Sstevel@tonic-gate } 13570Sstevel@tonic-gate 13580Sstevel@tonic-gate static int 13590Sstevel@tonic-gate iswanted(kthread_t *t, lwpchan_t *lwpchan) 13600Sstevel@tonic-gate { 13610Sstevel@tonic-gate /* 13620Sstevel@tonic-gate * The caller holds the dispatcher lock on the sleep queue. 13630Sstevel@tonic-gate */ 13640Sstevel@tonic-gate while (t != NULL) { 13650Sstevel@tonic-gate if (t->t_lwpchan.lc_wchan0 == lwpchan->lc_wchan0 && 13660Sstevel@tonic-gate t->t_lwpchan.lc_wchan == lwpchan->lc_wchan) 13670Sstevel@tonic-gate return (1); 13680Sstevel@tonic-gate t = t->t_link; 13690Sstevel@tonic-gate } 13700Sstevel@tonic-gate return (0); 13710Sstevel@tonic-gate } 13720Sstevel@tonic-gate 13730Sstevel@tonic-gate /* 13740Sstevel@tonic-gate * Return the highest priority thread sleeping on this lwpchan. 13750Sstevel@tonic-gate */ 13760Sstevel@tonic-gate static kthread_t * 13770Sstevel@tonic-gate lwp_queue_waiter(lwpchan_t *lwpchan) 13780Sstevel@tonic-gate { 13790Sstevel@tonic-gate sleepq_head_t *sqh; 13800Sstevel@tonic-gate kthread_t *tp; 13810Sstevel@tonic-gate 13820Sstevel@tonic-gate sqh = lwpsqhash(lwpchan); 13830Sstevel@tonic-gate disp_lock_enter(&sqh->sq_lock); /* lock the sleep queue */ 13840Sstevel@tonic-gate for (tp = sqh->sq_queue.sq_first; tp != NULL; tp = tp->t_link) { 13850Sstevel@tonic-gate if (tp->t_lwpchan.lc_wchan0 == lwpchan->lc_wchan0 && 13860Sstevel@tonic-gate tp->t_lwpchan.lc_wchan == lwpchan->lc_wchan) 13870Sstevel@tonic-gate break; 13880Sstevel@tonic-gate } 13890Sstevel@tonic-gate disp_lock_exit(&sqh->sq_lock); 13900Sstevel@tonic-gate return (tp); 13910Sstevel@tonic-gate } 13920Sstevel@tonic-gate 13930Sstevel@tonic-gate static int 13940Sstevel@tonic-gate lwp_release(lwpchan_t *lwpchan, uchar_t *waiters, int sync_type) 13950Sstevel@tonic-gate { 13960Sstevel@tonic-gate sleepq_head_t *sqh; 13970Sstevel@tonic-gate kthread_t *tp; 13980Sstevel@tonic-gate kthread_t **tpp; 13990Sstevel@tonic-gate 14000Sstevel@tonic-gate sqh = lwpsqhash(lwpchan); 14010Sstevel@tonic-gate disp_lock_enter(&sqh->sq_lock); /* lock the sleep queue */ 14020Sstevel@tonic-gate tpp = &sqh->sq_queue.sq_first; 14030Sstevel@tonic-gate while ((tp = *tpp) != NULL) { 14040Sstevel@tonic-gate if (tp->t_lwpchan.lc_wchan0 == lwpchan->lc_wchan0 && 14050Sstevel@tonic-gate tp->t_lwpchan.lc_wchan == lwpchan->lc_wchan) { 14060Sstevel@tonic-gate /* 14070Sstevel@tonic-gate * The following is typically false. It could be true 14080Sstevel@tonic-gate * only if lwp_release() is called from 14090Sstevel@tonic-gate * lwp_mutex_wakeup() after reading the waiters field 14100Sstevel@tonic-gate * from memory in which the lwp lock used to be, but has 14110Sstevel@tonic-gate * since been re-used to hold a lwp cv or lwp semaphore. 14120Sstevel@tonic-gate * The thread "tp" found to match the lwp lock's wchan 14130Sstevel@tonic-gate * is actually sleeping for the cv or semaphore which 14140Sstevel@tonic-gate * now has the same wchan. In this case, lwp_release() 14150Sstevel@tonic-gate * should return failure. 14160Sstevel@tonic-gate */ 14170Sstevel@tonic-gate if (sync_type != (tp->t_flag & T_WAITCVSEM)) { 14180Sstevel@tonic-gate ASSERT(sync_type == 0); 14190Sstevel@tonic-gate /* 14200Sstevel@tonic-gate * assert that this can happen only for mutexes 14210Sstevel@tonic-gate * i.e. sync_type == 0, for correctly written 14220Sstevel@tonic-gate * user programs. 14230Sstevel@tonic-gate */ 14240Sstevel@tonic-gate disp_lock_exit(&sqh->sq_lock); 14250Sstevel@tonic-gate return (0); 14260Sstevel@tonic-gate } 14270Sstevel@tonic-gate *waiters = iswanted(tp->t_link, lwpchan); 14280Sstevel@tonic-gate sleepq_unlink(tpp, tp); 14290Sstevel@tonic-gate DTRACE_SCHED1(wakeup, kthread_t *, tp); 14300Sstevel@tonic-gate tp->t_wchan0 = NULL; 14310Sstevel@tonic-gate tp->t_wchan = NULL; 14320Sstevel@tonic-gate tp->t_sobj_ops = NULL; 14330Sstevel@tonic-gate tp->t_release = 1; 14340Sstevel@tonic-gate THREAD_TRANSITION(tp); /* drops sleepq lock */ 14350Sstevel@tonic-gate CL_WAKEUP(tp); 14360Sstevel@tonic-gate thread_unlock(tp); /* drop run queue lock */ 14370Sstevel@tonic-gate return (1); 14380Sstevel@tonic-gate } 14390Sstevel@tonic-gate tpp = &tp->t_link; 14400Sstevel@tonic-gate } 14410Sstevel@tonic-gate *waiters = 0; 14420Sstevel@tonic-gate disp_lock_exit(&sqh->sq_lock); 14430Sstevel@tonic-gate return (0); 14440Sstevel@tonic-gate } 14450Sstevel@tonic-gate 14460Sstevel@tonic-gate static void 14470Sstevel@tonic-gate lwp_release_all(lwpchan_t *lwpchan) 14480Sstevel@tonic-gate { 14490Sstevel@tonic-gate sleepq_head_t *sqh; 14500Sstevel@tonic-gate kthread_t *tp; 14510Sstevel@tonic-gate kthread_t **tpp; 14520Sstevel@tonic-gate 14530Sstevel@tonic-gate sqh = lwpsqhash(lwpchan); 14540Sstevel@tonic-gate disp_lock_enter(&sqh->sq_lock); /* lock sleep q queue */ 14550Sstevel@tonic-gate tpp = &sqh->sq_queue.sq_first; 14560Sstevel@tonic-gate while ((tp = *tpp) != NULL) { 14570Sstevel@tonic-gate if (tp->t_lwpchan.lc_wchan0 == lwpchan->lc_wchan0 && 14580Sstevel@tonic-gate tp->t_lwpchan.lc_wchan == lwpchan->lc_wchan) { 14590Sstevel@tonic-gate sleepq_unlink(tpp, tp); 14600Sstevel@tonic-gate DTRACE_SCHED1(wakeup, kthread_t *, tp); 14610Sstevel@tonic-gate tp->t_wchan0 = NULL; 14620Sstevel@tonic-gate tp->t_wchan = NULL; 14630Sstevel@tonic-gate tp->t_sobj_ops = NULL; 14640Sstevel@tonic-gate CL_WAKEUP(tp); 14650Sstevel@tonic-gate thread_unlock_high(tp); /* release run queue lock */ 14660Sstevel@tonic-gate } else { 14670Sstevel@tonic-gate tpp = &tp->t_link; 14680Sstevel@tonic-gate } 14690Sstevel@tonic-gate } 14700Sstevel@tonic-gate disp_lock_exit(&sqh->sq_lock); /* drop sleep q lock */ 14710Sstevel@tonic-gate } 14720Sstevel@tonic-gate 14730Sstevel@tonic-gate /* 14740Sstevel@tonic-gate * unblock a lwp that is trying to acquire this mutex. the blocked 14750Sstevel@tonic-gate * lwp resumes and retries to acquire the lock. 14760Sstevel@tonic-gate */ 14770Sstevel@tonic-gate int 14784574Sraf lwp_mutex_wakeup(lwp_mutex_t *lp, int release_all) 14790Sstevel@tonic-gate { 14800Sstevel@tonic-gate proc_t *p = ttoproc(curthread); 14810Sstevel@tonic-gate lwpchan_t lwpchan; 14820Sstevel@tonic-gate uchar_t waiters; 14830Sstevel@tonic-gate volatile int locked = 0; 14840Sstevel@tonic-gate volatile int watched = 0; 14850Sstevel@tonic-gate volatile uint8_t type = 0; 14860Sstevel@tonic-gate label_t ljb; 14870Sstevel@tonic-gate int error = 0; 14880Sstevel@tonic-gate 14890Sstevel@tonic-gate if ((caddr_t)lp >= p->p_as->a_userlimit) 14900Sstevel@tonic-gate return (set_errno(EFAULT)); 14910Sstevel@tonic-gate 14920Sstevel@tonic-gate watched = watch_disable_addr((caddr_t)lp, sizeof (*lp), S_WRITE); 14930Sstevel@tonic-gate 14940Sstevel@tonic-gate if (on_fault(&ljb)) { 14950Sstevel@tonic-gate if (locked) 14960Sstevel@tonic-gate lwpchan_unlock(&lwpchan, LWPCHAN_MPPOOL); 14970Sstevel@tonic-gate error = EFAULT; 14980Sstevel@tonic-gate goto out; 14990Sstevel@tonic-gate } 15000Sstevel@tonic-gate /* 15016577Sraf * Force Copy-on-write if necessary and ensure that the 15026577Sraf * synchronization object resides in read/write memory. 15036577Sraf * Cause an EFAULT return now if this is not so. 15040Sstevel@tonic-gate */ 15050Sstevel@tonic-gate fuword8_noerr(&lp->mutex_type, (uint8_t *)&type); 15060Sstevel@tonic-gate suword8_noerr(&lp->mutex_type, type); 15070Sstevel@tonic-gate if (!get_lwpchan(curproc->p_as, (caddr_t)lp, type, 15080Sstevel@tonic-gate &lwpchan, LWPCHAN_MPPOOL)) { 15090Sstevel@tonic-gate error = EFAULT; 15100Sstevel@tonic-gate goto out; 15110Sstevel@tonic-gate } 15120Sstevel@tonic-gate lwpchan_lock(&lwpchan, LWPCHAN_MPPOOL); 15130Sstevel@tonic-gate locked = 1; 15140Sstevel@tonic-gate /* 15150Sstevel@tonic-gate * Always wake up an lwp (if any) waiting on lwpchan. The woken lwp will 15160Sstevel@tonic-gate * re-try the lock in lwp_mutex_timedlock(). The call to lwp_release() 15170Sstevel@tonic-gate * may fail. If it fails, do not write into the waiter bit. 15180Sstevel@tonic-gate * The call to lwp_release() might fail due to one of three reasons: 15190Sstevel@tonic-gate * 15200Sstevel@tonic-gate * 1. due to the thread which set the waiter bit not actually 15210Sstevel@tonic-gate * sleeping since it got the lock on the re-try. The waiter 15220Sstevel@tonic-gate * bit will then be correctly updated by that thread. This 15230Sstevel@tonic-gate * window may be closed by reading the wait bit again here 15240Sstevel@tonic-gate * and not calling lwp_release() at all if it is zero. 15250Sstevel@tonic-gate * 2. the thread which set the waiter bit and went to sleep 15260Sstevel@tonic-gate * was woken up by a signal. This time, the waiter recomputes 15270Sstevel@tonic-gate * the wait bit in the return with EINTR code. 15280Sstevel@tonic-gate * 3. the waiter bit read by lwp_mutex_wakeup() was in 15290Sstevel@tonic-gate * memory that has been re-used after the lock was dropped. 15300Sstevel@tonic-gate * In this case, writing into the waiter bit would cause data 15310Sstevel@tonic-gate * corruption. 15320Sstevel@tonic-gate */ 15334574Sraf if (release_all) 15344574Sraf lwp_release_all(&lwpchan); 15356057Sraf else if (lwp_release(&lwpchan, &waiters, 0)) 15360Sstevel@tonic-gate suword8_noerr(&lp->mutex_waiters, waiters); 15370Sstevel@tonic-gate lwpchan_unlock(&lwpchan, LWPCHAN_MPPOOL); 15380Sstevel@tonic-gate out: 15390Sstevel@tonic-gate no_fault(); 15400Sstevel@tonic-gate if (watched) 15410Sstevel@tonic-gate watch_enable_addr((caddr_t)lp, sizeof (*lp), S_WRITE); 15420Sstevel@tonic-gate if (error) 15430Sstevel@tonic-gate return (set_errno(error)); 15440Sstevel@tonic-gate return (0); 15450Sstevel@tonic-gate } 15460Sstevel@tonic-gate 15470Sstevel@tonic-gate /* 15480Sstevel@tonic-gate * lwp_cond_wait() has four arguments, a pointer to a condition variable, 15490Sstevel@tonic-gate * a pointer to a mutex, a pointer to a timespec for a timed wait and 15500Sstevel@tonic-gate * a flag telling the kernel whether or not to honor the kernel/user 15510Sstevel@tonic-gate * schedctl parking protocol (see schedctl_is_park() in schedctl.c). 15520Sstevel@tonic-gate * The kernel puts the lwp to sleep on a unique pair of caddr_t's called an 15530Sstevel@tonic-gate * lwpchan, returned by get_lwpchan(). If the timespec pointer is non-NULL, 15540Sstevel@tonic-gate * it is used an an in/out parameter. On entry, it contains the relative 15550Sstevel@tonic-gate * time until timeout. On exit, we copyout the residual time left to it. 15560Sstevel@tonic-gate */ 15570Sstevel@tonic-gate int 15580Sstevel@tonic-gate lwp_cond_wait(lwp_cond_t *cv, lwp_mutex_t *mp, timespec_t *tsp, int check_park) 15590Sstevel@tonic-gate { 15600Sstevel@tonic-gate kthread_t *t = curthread; 15610Sstevel@tonic-gate klwp_t *lwp = ttolwp(t); 15620Sstevel@tonic-gate proc_t *p = ttoproc(t); 15630Sstevel@tonic-gate lwp_timer_t lwpt; 15640Sstevel@tonic-gate lwpchan_t cv_lwpchan; 15650Sstevel@tonic-gate lwpchan_t m_lwpchan; 15660Sstevel@tonic-gate caddr_t timedwait; 15670Sstevel@tonic-gate volatile uint16_t type = 0; 15680Sstevel@tonic-gate volatile uint8_t mtype = 0; 15690Sstevel@tonic-gate uchar_t waiters; 15700Sstevel@tonic-gate volatile int error; 15710Sstevel@tonic-gate clock_t tim = -1; 15720Sstevel@tonic-gate volatile int locked = 0; 15730Sstevel@tonic-gate volatile int m_locked = 0; 15740Sstevel@tonic-gate volatile int cvwatched = 0; 15750Sstevel@tonic-gate volatile int mpwatched = 0; 15760Sstevel@tonic-gate label_t ljb; 15770Sstevel@tonic-gate volatile int no_lwpchan = 1; 15780Sstevel@tonic-gate int imm_timeout = 0; 15790Sstevel@tonic-gate int imm_unpark = 0; 15800Sstevel@tonic-gate 15810Sstevel@tonic-gate if ((caddr_t)cv >= p->p_as->a_userlimit || 15820Sstevel@tonic-gate (caddr_t)mp >= p->p_as->a_userlimit) 15830Sstevel@tonic-gate return (set_errno(EFAULT)); 15840Sstevel@tonic-gate 15850Sstevel@tonic-gate timedwait = (caddr_t)tsp; 15860Sstevel@tonic-gate if ((error = lwp_timer_copyin(&lwpt, tsp)) != 0) 15870Sstevel@tonic-gate return (set_errno(error)); 15880Sstevel@tonic-gate if (lwpt.lwpt_imm_timeout) { 15890Sstevel@tonic-gate imm_timeout = 1; 15900Sstevel@tonic-gate timedwait = NULL; 15910Sstevel@tonic-gate } 15920Sstevel@tonic-gate 15930Sstevel@tonic-gate (void) new_mstate(t, LMS_USER_LOCK); 15940Sstevel@tonic-gate 15950Sstevel@tonic-gate if (on_fault(&ljb)) { 15960Sstevel@tonic-gate if (no_lwpchan) { 15970Sstevel@tonic-gate error = EFAULT; 15980Sstevel@tonic-gate goto out; 15990Sstevel@tonic-gate } 16000Sstevel@tonic-gate if (m_locked) { 16010Sstevel@tonic-gate m_locked = 0; 16020Sstevel@tonic-gate lwpchan_unlock(&m_lwpchan, LWPCHAN_MPPOOL); 16030Sstevel@tonic-gate } 16040Sstevel@tonic-gate if (locked) { 16050Sstevel@tonic-gate locked = 0; 16060Sstevel@tonic-gate lwpchan_unlock(&cv_lwpchan, LWPCHAN_CVPOOL); 16070Sstevel@tonic-gate } 16080Sstevel@tonic-gate /* 16090Sstevel@tonic-gate * set up another on_fault() for a possible fault 16100Sstevel@tonic-gate * on the user lock accessed at "efault" 16110Sstevel@tonic-gate */ 16120Sstevel@tonic-gate if (on_fault(&ljb)) { 16130Sstevel@tonic-gate if (m_locked) { 16140Sstevel@tonic-gate m_locked = 0; 16150Sstevel@tonic-gate lwpchan_unlock(&m_lwpchan, LWPCHAN_MPPOOL); 16160Sstevel@tonic-gate } 16170Sstevel@tonic-gate goto out; 16180Sstevel@tonic-gate } 16190Sstevel@tonic-gate error = EFAULT; 16200Sstevel@tonic-gate goto efault; 16210Sstevel@tonic-gate } 16220Sstevel@tonic-gate 16230Sstevel@tonic-gate /* 16246577Sraf * Force Copy-on-write if necessary and ensure that the 16256577Sraf * synchronization object resides in read/write memory. 16266577Sraf * Cause an EFAULT return now if this is not so. 16270Sstevel@tonic-gate */ 16280Sstevel@tonic-gate fuword8_noerr(&mp->mutex_type, (uint8_t *)&mtype); 16296577Sraf suword8_noerr(&mp->mutex_type, mtype); 16300Sstevel@tonic-gate if (UPIMUTEX(mtype) == 0) { 16310Sstevel@tonic-gate /* convert user level mutex, "mp", to a unique lwpchan */ 16320Sstevel@tonic-gate /* check if mtype is ok to use below, instead of type from cv */ 16330Sstevel@tonic-gate if (!get_lwpchan(p->p_as, (caddr_t)mp, mtype, 16340Sstevel@tonic-gate &m_lwpchan, LWPCHAN_MPPOOL)) { 16350Sstevel@tonic-gate error = EFAULT; 16360Sstevel@tonic-gate goto out; 16370Sstevel@tonic-gate } 16380Sstevel@tonic-gate } 16390Sstevel@tonic-gate fuword16_noerr(&cv->cond_type, (uint16_t *)&type); 16400Sstevel@tonic-gate suword16_noerr(&cv->cond_type, type); 16410Sstevel@tonic-gate /* convert user level condition variable, "cv", to a unique lwpchan */ 16420Sstevel@tonic-gate if (!get_lwpchan(p->p_as, (caddr_t)cv, type, 16430Sstevel@tonic-gate &cv_lwpchan, LWPCHAN_CVPOOL)) { 16440Sstevel@tonic-gate error = EFAULT; 16450Sstevel@tonic-gate goto out; 16460Sstevel@tonic-gate } 16470Sstevel@tonic-gate no_lwpchan = 0; 16480Sstevel@tonic-gate cvwatched = watch_disable_addr((caddr_t)cv, sizeof (*cv), S_WRITE); 16490Sstevel@tonic-gate if (UPIMUTEX(mtype) == 0) 16500Sstevel@tonic-gate mpwatched = watch_disable_addr((caddr_t)mp, sizeof (*mp), 16510Sstevel@tonic-gate S_WRITE); 16520Sstevel@tonic-gate 16530Sstevel@tonic-gate /* 16540Sstevel@tonic-gate * lwpchan_lock ensures that the calling lwp is put to sleep atomically 16550Sstevel@tonic-gate * with respect to a possible wakeup which is a result of either 16560Sstevel@tonic-gate * an lwp_cond_signal() or an lwp_cond_broadcast(). 16570Sstevel@tonic-gate * 16580Sstevel@tonic-gate * What's misleading, is that the lwp is put to sleep after the 16590Sstevel@tonic-gate * condition variable's mutex is released. This is OK as long as 16600Sstevel@tonic-gate * the release operation is also done while holding lwpchan_lock. 16610Sstevel@tonic-gate * The lwp is then put to sleep when the possibility of pagefaulting 16620Sstevel@tonic-gate * or sleeping is completely eliminated. 16630Sstevel@tonic-gate */ 16640Sstevel@tonic-gate lwpchan_lock(&cv_lwpchan, LWPCHAN_CVPOOL); 16650Sstevel@tonic-gate locked = 1; 16660Sstevel@tonic-gate if (UPIMUTEX(mtype) == 0) { 16670Sstevel@tonic-gate lwpchan_lock(&m_lwpchan, LWPCHAN_MPPOOL); 16680Sstevel@tonic-gate m_locked = 1; 16690Sstevel@tonic-gate suword8_noerr(&cv->cond_waiters_kernel, 1); 16700Sstevel@tonic-gate /* 16710Sstevel@tonic-gate * unlock the condition variable's mutex. (pagefaults are 16720Sstevel@tonic-gate * possible here.) 16730Sstevel@tonic-gate */ 16746057Sraf if (mtype & USYNC_PROCESS) 16756057Sraf suword32_noerr(&mp->mutex_ownerpid, 0); 16760Sstevel@tonic-gate ulock_clear(&mp->mutex_lockw); 16770Sstevel@tonic-gate fuword8_noerr(&mp->mutex_waiters, &waiters); 16780Sstevel@tonic-gate if (waiters != 0) { 16790Sstevel@tonic-gate /* 16800Sstevel@tonic-gate * Given the locking of lwpchan_lock around the release 16810Sstevel@tonic-gate * of the mutex and checking for waiters, the following 16820Sstevel@tonic-gate * call to lwp_release() can fail ONLY if the lock 16830Sstevel@tonic-gate * acquirer is interrupted after setting the waiter bit, 16840Sstevel@tonic-gate * calling lwp_block() and releasing lwpchan_lock. 16850Sstevel@tonic-gate * In this case, it could get pulled off the lwp sleep 16860Sstevel@tonic-gate * q (via setrun()) before the following call to 16870Sstevel@tonic-gate * lwp_release() occurs. In this case, the lock 16880Sstevel@tonic-gate * requestor will update the waiter bit correctly by 16890Sstevel@tonic-gate * re-evaluating it. 16900Sstevel@tonic-gate */ 16916057Sraf if (lwp_release(&m_lwpchan, &waiters, 0)) 16920Sstevel@tonic-gate suword8_noerr(&mp->mutex_waiters, waiters); 16930Sstevel@tonic-gate } 16940Sstevel@tonic-gate m_locked = 0; 16950Sstevel@tonic-gate lwpchan_unlock(&m_lwpchan, LWPCHAN_MPPOOL); 16960Sstevel@tonic-gate } else { 16970Sstevel@tonic-gate suword8_noerr(&cv->cond_waiters_kernel, 1); 16980Sstevel@tonic-gate error = lwp_upimutex_unlock(mp, mtype); 16990Sstevel@tonic-gate if (error) { /* if the upimutex unlock failed */ 17000Sstevel@tonic-gate locked = 0; 17010Sstevel@tonic-gate lwpchan_unlock(&cv_lwpchan, LWPCHAN_CVPOOL); 17020Sstevel@tonic-gate goto out; 17030Sstevel@tonic-gate } 17040Sstevel@tonic-gate } 17050Sstevel@tonic-gate no_fault(); 17060Sstevel@tonic-gate 17070Sstevel@tonic-gate if (mpwatched) { 17080Sstevel@tonic-gate watch_enable_addr((caddr_t)mp, sizeof (*mp), S_WRITE); 17090Sstevel@tonic-gate mpwatched = 0; 17100Sstevel@tonic-gate } 17110Sstevel@tonic-gate if (cvwatched) { 17120Sstevel@tonic-gate watch_enable_addr((caddr_t)cv, sizeof (*cv), S_WRITE); 17130Sstevel@tonic-gate cvwatched = 0; 17140Sstevel@tonic-gate } 17150Sstevel@tonic-gate 17160Sstevel@tonic-gate /* 17170Sstevel@tonic-gate * Put the lwp in an orderly state for debugging. 17180Sstevel@tonic-gate */ 17190Sstevel@tonic-gate prstop(PR_REQUESTED, 0); 17200Sstevel@tonic-gate if (check_park && (!schedctl_is_park() || t->t_unpark)) { 17210Sstevel@tonic-gate /* 17220Sstevel@tonic-gate * We received a signal at user-level before calling here 17230Sstevel@tonic-gate * or another thread wants us to return immediately 17240Sstevel@tonic-gate * with EINTR. See lwp_unpark(). 17250Sstevel@tonic-gate */ 17260Sstevel@tonic-gate imm_unpark = 1; 17270Sstevel@tonic-gate t->t_unpark = 0; 17280Sstevel@tonic-gate timedwait = NULL; 17290Sstevel@tonic-gate } else if (timedwait) { 17300Sstevel@tonic-gate /* 17310Sstevel@tonic-gate * If we successfully queue the timeout, 17320Sstevel@tonic-gate * then don't drop t_delay_lock until 17330Sstevel@tonic-gate * we are on the sleep queue (below). 17340Sstevel@tonic-gate */ 17350Sstevel@tonic-gate mutex_enter(&t->t_delay_lock); 17360Sstevel@tonic-gate if (lwp_timer_enqueue(&lwpt) != 0) { 17370Sstevel@tonic-gate mutex_exit(&t->t_delay_lock); 17380Sstevel@tonic-gate imm_timeout = 1; 17390Sstevel@tonic-gate timedwait = NULL; 17400Sstevel@tonic-gate } 17410Sstevel@tonic-gate } 17420Sstevel@tonic-gate t->t_flag |= T_WAITCVSEM; 17430Sstevel@tonic-gate lwp_block(&cv_lwpchan); 17440Sstevel@tonic-gate /* 17450Sstevel@tonic-gate * Nothing should happen to cause the lwp to go to sleep 17460Sstevel@tonic-gate * until after it returns from swtch(). 17470Sstevel@tonic-gate */ 17480Sstevel@tonic-gate if (timedwait) 17490Sstevel@tonic-gate mutex_exit(&t->t_delay_lock); 17500Sstevel@tonic-gate locked = 0; 17510Sstevel@tonic-gate lwpchan_unlock(&cv_lwpchan, LWPCHAN_CVPOOL); 17520Sstevel@tonic-gate if (ISSIG(t, JUSTLOOKING) || MUSTRETURN(p, t) || 17530Sstevel@tonic-gate (imm_timeout | imm_unpark)) 17540Sstevel@tonic-gate setrun(t); 17550Sstevel@tonic-gate swtch(); 17560Sstevel@tonic-gate t->t_flag &= ~(T_WAITCVSEM | T_WAKEABLE); 17570Sstevel@tonic-gate if (timedwait) 17580Sstevel@tonic-gate tim = lwp_timer_dequeue(&lwpt); 17590Sstevel@tonic-gate if (ISSIG(t, FORREAL) || lwp->lwp_sysabort || 17600Sstevel@tonic-gate MUSTRETURN(p, t) || imm_unpark) 17610Sstevel@tonic-gate error = EINTR; 17620Sstevel@tonic-gate else if (imm_timeout || (timedwait && tim == -1)) 17630Sstevel@tonic-gate error = ETIME; 17640Sstevel@tonic-gate lwp->lwp_asleep = 0; 17650Sstevel@tonic-gate lwp->lwp_sysabort = 0; 17660Sstevel@tonic-gate setallwatch(); 17670Sstevel@tonic-gate 17680Sstevel@tonic-gate if (t->t_mstate == LMS_USER_LOCK) 17690Sstevel@tonic-gate (void) new_mstate(t, LMS_SYSTEM); 17700Sstevel@tonic-gate 17710Sstevel@tonic-gate if (tsp && check_park) /* copyout the residual time left */ 17720Sstevel@tonic-gate error = lwp_timer_copyout(&lwpt, error); 17730Sstevel@tonic-gate 17740Sstevel@tonic-gate /* the mutex is reacquired by the caller on return to user level */ 17750Sstevel@tonic-gate if (error) { 17760Sstevel@tonic-gate /* 17770Sstevel@tonic-gate * If we were concurrently lwp_cond_signal()d and we 17780Sstevel@tonic-gate * received a UNIX signal or got a timeout, then perform 17790Sstevel@tonic-gate * another lwp_cond_signal() to avoid consuming the wakeup. 17800Sstevel@tonic-gate */ 17810Sstevel@tonic-gate if (t->t_release) 17820Sstevel@tonic-gate (void) lwp_cond_signal(cv); 17830Sstevel@tonic-gate return (set_errno(error)); 17840Sstevel@tonic-gate } 17850Sstevel@tonic-gate return (0); 17860Sstevel@tonic-gate 17870Sstevel@tonic-gate efault: 17880Sstevel@tonic-gate /* 17890Sstevel@tonic-gate * make sure that the user level lock is dropped before 17900Sstevel@tonic-gate * returning to caller, since the caller always re-acquires it. 17910Sstevel@tonic-gate */ 17920Sstevel@tonic-gate if (UPIMUTEX(mtype) == 0) { 17930Sstevel@tonic-gate lwpchan_lock(&m_lwpchan, LWPCHAN_MPPOOL); 17940Sstevel@tonic-gate m_locked = 1; 17956057Sraf if (mtype & USYNC_PROCESS) 17966057Sraf suword32_noerr(&mp->mutex_ownerpid, 0); 17970Sstevel@tonic-gate ulock_clear(&mp->mutex_lockw); 17980Sstevel@tonic-gate fuword8_noerr(&mp->mutex_waiters, &waiters); 17990Sstevel@tonic-gate if (waiters != 0) { 18000Sstevel@tonic-gate /* 18010Sstevel@tonic-gate * See comment above on lock clearing and lwp_release() 18020Sstevel@tonic-gate * success/failure. 18030Sstevel@tonic-gate */ 18046057Sraf if (lwp_release(&m_lwpchan, &waiters, 0)) 18050Sstevel@tonic-gate suword8_noerr(&mp->mutex_waiters, waiters); 18060Sstevel@tonic-gate } 18070Sstevel@tonic-gate m_locked = 0; 18080Sstevel@tonic-gate lwpchan_unlock(&m_lwpchan, LWPCHAN_MPPOOL); 18090Sstevel@tonic-gate } else { 18100Sstevel@tonic-gate (void) lwp_upimutex_unlock(mp, mtype); 18110Sstevel@tonic-gate } 18120Sstevel@tonic-gate out: 18130Sstevel@tonic-gate no_fault(); 18140Sstevel@tonic-gate if (mpwatched) 18150Sstevel@tonic-gate watch_enable_addr((caddr_t)mp, sizeof (*mp), S_WRITE); 18160Sstevel@tonic-gate if (cvwatched) 18170Sstevel@tonic-gate watch_enable_addr((caddr_t)cv, sizeof (*cv), S_WRITE); 18180Sstevel@tonic-gate if (t->t_mstate == LMS_USER_LOCK) 18190Sstevel@tonic-gate (void) new_mstate(t, LMS_SYSTEM); 18200Sstevel@tonic-gate return (set_errno(error)); 18210Sstevel@tonic-gate } 18220Sstevel@tonic-gate 18230Sstevel@tonic-gate /* 18240Sstevel@tonic-gate * wakeup one lwp that's blocked on this condition variable. 18250Sstevel@tonic-gate */ 18260Sstevel@tonic-gate int 18270Sstevel@tonic-gate lwp_cond_signal(lwp_cond_t *cv) 18280Sstevel@tonic-gate { 18290Sstevel@tonic-gate proc_t *p = ttoproc(curthread); 18300Sstevel@tonic-gate lwpchan_t lwpchan; 18310Sstevel@tonic-gate uchar_t waiters; 18320Sstevel@tonic-gate volatile uint16_t type = 0; 18330Sstevel@tonic-gate volatile int locked = 0; 18340Sstevel@tonic-gate volatile int watched = 0; 18350Sstevel@tonic-gate label_t ljb; 18360Sstevel@tonic-gate int error = 0; 18370Sstevel@tonic-gate 18380Sstevel@tonic-gate if ((caddr_t)cv >= p->p_as->a_userlimit) 18390Sstevel@tonic-gate return (set_errno(EFAULT)); 18400Sstevel@tonic-gate 18410Sstevel@tonic-gate watched = watch_disable_addr((caddr_t)cv, sizeof (*cv), S_WRITE); 18420Sstevel@tonic-gate 18430Sstevel@tonic-gate if (on_fault(&ljb)) { 18440Sstevel@tonic-gate if (locked) 18450Sstevel@tonic-gate lwpchan_unlock(&lwpchan, LWPCHAN_CVPOOL); 18460Sstevel@tonic-gate error = EFAULT; 18470Sstevel@tonic-gate goto out; 18480Sstevel@tonic-gate } 18490Sstevel@tonic-gate /* 18506577Sraf * Force Copy-on-write if necessary and ensure that the 18516577Sraf * synchronization object resides in read/write memory. 18526577Sraf * Cause an EFAULT return now if this is not so. 18530Sstevel@tonic-gate */ 18540Sstevel@tonic-gate fuword16_noerr(&cv->cond_type, (uint16_t *)&type); 18550Sstevel@tonic-gate suword16_noerr(&cv->cond_type, type); 18560Sstevel@tonic-gate if (!get_lwpchan(curproc->p_as, (caddr_t)cv, type, 18570Sstevel@tonic-gate &lwpchan, LWPCHAN_CVPOOL)) { 18580Sstevel@tonic-gate error = EFAULT; 18590Sstevel@tonic-gate goto out; 18600Sstevel@tonic-gate } 18610Sstevel@tonic-gate lwpchan_lock(&lwpchan, LWPCHAN_CVPOOL); 18620Sstevel@tonic-gate locked = 1; 18630Sstevel@tonic-gate fuword8_noerr(&cv->cond_waiters_kernel, &waiters); 18640Sstevel@tonic-gate if (waiters != 0) { 18650Sstevel@tonic-gate /* 18660Sstevel@tonic-gate * The following call to lwp_release() might fail but it is 18670Sstevel@tonic-gate * OK to write into the waiters bit below, since the memory 18680Sstevel@tonic-gate * could not have been re-used or unmapped (for correctly 18690Sstevel@tonic-gate * written user programs) as in the case of lwp_mutex_wakeup(). 18700Sstevel@tonic-gate * For an incorrect program, we should not care about data 18710Sstevel@tonic-gate * corruption since this is just one instance of other places 18720Sstevel@tonic-gate * where corruption can occur for such a program. Of course 18730Sstevel@tonic-gate * if the memory is unmapped, normal fault recovery occurs. 18740Sstevel@tonic-gate */ 18750Sstevel@tonic-gate (void) lwp_release(&lwpchan, &waiters, T_WAITCVSEM); 18760Sstevel@tonic-gate suword8_noerr(&cv->cond_waiters_kernel, waiters); 18770Sstevel@tonic-gate } 18780Sstevel@tonic-gate lwpchan_unlock(&lwpchan, LWPCHAN_CVPOOL); 18790Sstevel@tonic-gate out: 18800Sstevel@tonic-gate no_fault(); 18810Sstevel@tonic-gate if (watched) 18820Sstevel@tonic-gate watch_enable_addr((caddr_t)cv, sizeof (*cv), S_WRITE); 18830Sstevel@tonic-gate if (error) 18840Sstevel@tonic-gate return (set_errno(error)); 18850Sstevel@tonic-gate return (0); 18860Sstevel@tonic-gate } 18870Sstevel@tonic-gate 18880Sstevel@tonic-gate /* 18890Sstevel@tonic-gate * wakeup every lwp that's blocked on this condition variable. 18900Sstevel@tonic-gate */ 18910Sstevel@tonic-gate int 18920Sstevel@tonic-gate lwp_cond_broadcast(lwp_cond_t *cv) 18930Sstevel@tonic-gate { 18940Sstevel@tonic-gate proc_t *p = ttoproc(curthread); 18950Sstevel@tonic-gate lwpchan_t lwpchan; 18960Sstevel@tonic-gate volatile uint16_t type = 0; 18970Sstevel@tonic-gate volatile int locked = 0; 18980Sstevel@tonic-gate volatile int watched = 0; 18990Sstevel@tonic-gate label_t ljb; 19000Sstevel@tonic-gate uchar_t waiters; 19010Sstevel@tonic-gate int error = 0; 19020Sstevel@tonic-gate 19030Sstevel@tonic-gate if ((caddr_t)cv >= p->p_as->a_userlimit) 19040Sstevel@tonic-gate return (set_errno(EFAULT)); 19050Sstevel@tonic-gate 19060Sstevel@tonic-gate watched = watch_disable_addr((caddr_t)cv, sizeof (*cv), S_WRITE); 19070Sstevel@tonic-gate 19080Sstevel@tonic-gate if (on_fault(&ljb)) { 19090Sstevel@tonic-gate if (locked) 19100Sstevel@tonic-gate lwpchan_unlock(&lwpchan, LWPCHAN_CVPOOL); 19110Sstevel@tonic-gate error = EFAULT; 19120Sstevel@tonic-gate goto out; 19130Sstevel@tonic-gate } 19140Sstevel@tonic-gate /* 19156577Sraf * Force Copy-on-write if necessary and ensure that the 19166577Sraf * synchronization object resides in read/write memory. 19176577Sraf * Cause an EFAULT return now if this is not so. 19180Sstevel@tonic-gate */ 19190Sstevel@tonic-gate fuword16_noerr(&cv->cond_type, (uint16_t *)&type); 19200Sstevel@tonic-gate suword16_noerr(&cv->cond_type, type); 19210Sstevel@tonic-gate if (!get_lwpchan(curproc->p_as, (caddr_t)cv, type, 19220Sstevel@tonic-gate &lwpchan, LWPCHAN_CVPOOL)) { 19230Sstevel@tonic-gate error = EFAULT; 19240Sstevel@tonic-gate goto out; 19250Sstevel@tonic-gate } 19260Sstevel@tonic-gate lwpchan_lock(&lwpchan, LWPCHAN_CVPOOL); 19270Sstevel@tonic-gate locked = 1; 19280Sstevel@tonic-gate fuword8_noerr(&cv->cond_waiters_kernel, &waiters); 19290Sstevel@tonic-gate if (waiters != 0) { 19300Sstevel@tonic-gate lwp_release_all(&lwpchan); 19310Sstevel@tonic-gate suword8_noerr(&cv->cond_waiters_kernel, 0); 19320Sstevel@tonic-gate } 19330Sstevel@tonic-gate lwpchan_unlock(&lwpchan, LWPCHAN_CVPOOL); 19340Sstevel@tonic-gate out: 19350Sstevel@tonic-gate no_fault(); 19360Sstevel@tonic-gate if (watched) 19370Sstevel@tonic-gate watch_enable_addr((caddr_t)cv, sizeof (*cv), S_WRITE); 19380Sstevel@tonic-gate if (error) 19390Sstevel@tonic-gate return (set_errno(error)); 19400Sstevel@tonic-gate return (0); 19410Sstevel@tonic-gate } 19420Sstevel@tonic-gate 19430Sstevel@tonic-gate int 19440Sstevel@tonic-gate lwp_sema_trywait(lwp_sema_t *sp) 19450Sstevel@tonic-gate { 19460Sstevel@tonic-gate kthread_t *t = curthread; 19470Sstevel@tonic-gate proc_t *p = ttoproc(t); 19480Sstevel@tonic-gate label_t ljb; 19490Sstevel@tonic-gate volatile int locked = 0; 19500Sstevel@tonic-gate volatile int watched = 0; 19510Sstevel@tonic-gate volatile uint16_t type = 0; 19520Sstevel@tonic-gate int count; 19530Sstevel@tonic-gate lwpchan_t lwpchan; 19540Sstevel@tonic-gate uchar_t waiters; 19550Sstevel@tonic-gate int error = 0; 19560Sstevel@tonic-gate 19570Sstevel@tonic-gate if ((caddr_t)sp >= p->p_as->a_userlimit) 19580Sstevel@tonic-gate return (set_errno(EFAULT)); 19590Sstevel@tonic-gate 19600Sstevel@tonic-gate watched = watch_disable_addr((caddr_t)sp, sizeof (*sp), S_WRITE); 19610Sstevel@tonic-gate 19620Sstevel@tonic-gate if (on_fault(&ljb)) { 19630Sstevel@tonic-gate if (locked) 19640Sstevel@tonic-gate lwpchan_unlock(&lwpchan, LWPCHAN_CVPOOL); 19650Sstevel@tonic-gate error = EFAULT; 19660Sstevel@tonic-gate goto out; 19670Sstevel@tonic-gate } 19680Sstevel@tonic-gate /* 19696577Sraf * Force Copy-on-write if necessary and ensure that the 19706577Sraf * synchronization object resides in read/write memory. 19716577Sraf * Cause an EFAULT return now if this is not so. 19720Sstevel@tonic-gate */ 19730Sstevel@tonic-gate fuword16_noerr((void *)&sp->sema_type, (uint16_t *)&type); 19740Sstevel@tonic-gate suword16_noerr((void *)&sp->sema_type, type); 19750Sstevel@tonic-gate if (!get_lwpchan(p->p_as, (caddr_t)sp, type, 19760Sstevel@tonic-gate &lwpchan, LWPCHAN_CVPOOL)) { 19770Sstevel@tonic-gate error = EFAULT; 19780Sstevel@tonic-gate goto out; 19790Sstevel@tonic-gate } 19800Sstevel@tonic-gate lwpchan_lock(&lwpchan, LWPCHAN_CVPOOL); 19810Sstevel@tonic-gate locked = 1; 19820Sstevel@tonic-gate fuword32_noerr((void *)&sp->sema_count, (uint32_t *)&count); 19830Sstevel@tonic-gate if (count == 0) 19840Sstevel@tonic-gate error = EBUSY; 19850Sstevel@tonic-gate else 19860Sstevel@tonic-gate suword32_noerr((void *)&sp->sema_count, --count); 19870Sstevel@tonic-gate if (count != 0) { 19880Sstevel@tonic-gate fuword8_noerr(&sp->sema_waiters, &waiters); 19890Sstevel@tonic-gate if (waiters != 0) { 19900Sstevel@tonic-gate (void) lwp_release(&lwpchan, &waiters, T_WAITCVSEM); 19910Sstevel@tonic-gate suword8_noerr(&sp->sema_waiters, waiters); 19920Sstevel@tonic-gate } 19930Sstevel@tonic-gate } 19940Sstevel@tonic-gate lwpchan_unlock(&lwpchan, LWPCHAN_CVPOOL); 19950Sstevel@tonic-gate out: 19960Sstevel@tonic-gate no_fault(); 19970Sstevel@tonic-gate if (watched) 19980Sstevel@tonic-gate watch_enable_addr((caddr_t)sp, sizeof (*sp), S_WRITE); 19990Sstevel@tonic-gate if (error) 20000Sstevel@tonic-gate return (set_errno(error)); 20010Sstevel@tonic-gate return (0); 20020Sstevel@tonic-gate } 20030Sstevel@tonic-gate 20040Sstevel@tonic-gate /* 20050Sstevel@tonic-gate * See lwp_cond_wait(), above, for an explanation of the 'check_park' argument. 20060Sstevel@tonic-gate */ 20070Sstevel@tonic-gate int 20080Sstevel@tonic-gate lwp_sema_timedwait(lwp_sema_t *sp, timespec_t *tsp, int check_park) 20090Sstevel@tonic-gate { 20100Sstevel@tonic-gate kthread_t *t = curthread; 20110Sstevel@tonic-gate klwp_t *lwp = ttolwp(t); 20120Sstevel@tonic-gate proc_t *p = ttoproc(t); 20130Sstevel@tonic-gate lwp_timer_t lwpt; 20140Sstevel@tonic-gate caddr_t timedwait; 20150Sstevel@tonic-gate clock_t tim = -1; 20160Sstevel@tonic-gate label_t ljb; 20170Sstevel@tonic-gate volatile int locked = 0; 20180Sstevel@tonic-gate volatile int watched = 0; 20190Sstevel@tonic-gate volatile uint16_t type = 0; 20200Sstevel@tonic-gate int count; 20210Sstevel@tonic-gate lwpchan_t lwpchan; 20220Sstevel@tonic-gate uchar_t waiters; 20230Sstevel@tonic-gate int error = 0; 20240Sstevel@tonic-gate int time_error; 20250Sstevel@tonic-gate int imm_timeout = 0; 20260Sstevel@tonic-gate int imm_unpark = 0; 20270Sstevel@tonic-gate 20280Sstevel@tonic-gate if ((caddr_t)sp >= p->p_as->a_userlimit) 20290Sstevel@tonic-gate return (set_errno(EFAULT)); 20300Sstevel@tonic-gate 20310Sstevel@tonic-gate timedwait = (caddr_t)tsp; 20320Sstevel@tonic-gate if ((time_error = lwp_timer_copyin(&lwpt, tsp)) == 0 && 20330Sstevel@tonic-gate lwpt.lwpt_imm_timeout) { 20340Sstevel@tonic-gate imm_timeout = 1; 20350Sstevel@tonic-gate timedwait = NULL; 20360Sstevel@tonic-gate } 20370Sstevel@tonic-gate 20380Sstevel@tonic-gate watched = watch_disable_addr((caddr_t)sp, sizeof (*sp), S_WRITE); 20390Sstevel@tonic-gate 20400Sstevel@tonic-gate if (on_fault(&ljb)) { 20410Sstevel@tonic-gate if (locked) 20420Sstevel@tonic-gate lwpchan_unlock(&lwpchan, LWPCHAN_CVPOOL); 20430Sstevel@tonic-gate error = EFAULT; 20440Sstevel@tonic-gate goto out; 20450Sstevel@tonic-gate } 20460Sstevel@tonic-gate /* 20476577Sraf * Force Copy-on-write if necessary and ensure that the 20486577Sraf * synchronization object resides in read/write memory. 20496577Sraf * Cause an EFAULT return now if this is not so. 20500Sstevel@tonic-gate */ 20510Sstevel@tonic-gate fuword16_noerr((void *)&sp->sema_type, (uint16_t *)&type); 20520Sstevel@tonic-gate suword16_noerr((void *)&sp->sema_type, type); 20530Sstevel@tonic-gate if (!get_lwpchan(p->p_as, (caddr_t)sp, type, 20540Sstevel@tonic-gate &lwpchan, LWPCHAN_CVPOOL)) { 20550Sstevel@tonic-gate error = EFAULT; 20560Sstevel@tonic-gate goto out; 20570Sstevel@tonic-gate } 20580Sstevel@tonic-gate lwpchan_lock(&lwpchan, LWPCHAN_CVPOOL); 20590Sstevel@tonic-gate locked = 1; 20600Sstevel@tonic-gate fuword32_noerr((void *)&sp->sema_count, (uint32_t *)&count); 20610Sstevel@tonic-gate while (error == 0 && count == 0) { 20620Sstevel@tonic-gate if (time_error) { 20630Sstevel@tonic-gate /* 20640Sstevel@tonic-gate * The SUSV3 Posix spec is very clear that we 20650Sstevel@tonic-gate * should get no error from validating the 20660Sstevel@tonic-gate * timer until we would actually sleep. 20670Sstevel@tonic-gate */ 20680Sstevel@tonic-gate error = time_error; 20690Sstevel@tonic-gate break; 20700Sstevel@tonic-gate } 20710Sstevel@tonic-gate suword8_noerr(&sp->sema_waiters, 1); 20720Sstevel@tonic-gate if (watched) 20730Sstevel@tonic-gate watch_enable_addr((caddr_t)sp, sizeof (*sp), S_WRITE); 20740Sstevel@tonic-gate /* 20750Sstevel@tonic-gate * Put the lwp in an orderly state for debugging. 20760Sstevel@tonic-gate */ 20770Sstevel@tonic-gate prstop(PR_REQUESTED, 0); 20780Sstevel@tonic-gate if (check_park && (!schedctl_is_park() || t->t_unpark)) { 20790Sstevel@tonic-gate /* 20800Sstevel@tonic-gate * We received a signal at user-level before calling 20810Sstevel@tonic-gate * here or another thread wants us to return 20820Sstevel@tonic-gate * immediately with EINTR. See lwp_unpark(). 20830Sstevel@tonic-gate */ 20840Sstevel@tonic-gate imm_unpark = 1; 20850Sstevel@tonic-gate t->t_unpark = 0; 20860Sstevel@tonic-gate timedwait = NULL; 20870Sstevel@tonic-gate } else if (timedwait) { 20880Sstevel@tonic-gate /* 20890Sstevel@tonic-gate * If we successfully queue the timeout, 20900Sstevel@tonic-gate * then don't drop t_delay_lock until 20910Sstevel@tonic-gate * we are on the sleep queue (below). 20920Sstevel@tonic-gate */ 20930Sstevel@tonic-gate mutex_enter(&t->t_delay_lock); 20940Sstevel@tonic-gate if (lwp_timer_enqueue(&lwpt) != 0) { 20950Sstevel@tonic-gate mutex_exit(&t->t_delay_lock); 20960Sstevel@tonic-gate imm_timeout = 1; 20970Sstevel@tonic-gate timedwait = NULL; 20980Sstevel@tonic-gate } 20990Sstevel@tonic-gate } 21000Sstevel@tonic-gate t->t_flag |= T_WAITCVSEM; 21010Sstevel@tonic-gate lwp_block(&lwpchan); 21020Sstevel@tonic-gate /* 21030Sstevel@tonic-gate * Nothing should happen to cause the lwp to sleep 21040Sstevel@tonic-gate * again until after it returns from swtch(). 21050Sstevel@tonic-gate */ 21060Sstevel@tonic-gate if (timedwait) 21070Sstevel@tonic-gate mutex_exit(&t->t_delay_lock); 21080Sstevel@tonic-gate locked = 0; 21090Sstevel@tonic-gate lwpchan_unlock(&lwpchan, LWPCHAN_CVPOOL); 21100Sstevel@tonic-gate if (ISSIG(t, JUSTLOOKING) || MUSTRETURN(p, t) || 21110Sstevel@tonic-gate (imm_timeout | imm_unpark)) 21120Sstevel@tonic-gate setrun(t); 21130Sstevel@tonic-gate swtch(); 21140Sstevel@tonic-gate t->t_flag &= ~(T_WAITCVSEM | T_WAKEABLE); 21150Sstevel@tonic-gate if (timedwait) 21160Sstevel@tonic-gate tim = lwp_timer_dequeue(&lwpt); 21170Sstevel@tonic-gate setallwatch(); 21180Sstevel@tonic-gate if (ISSIG(t, FORREAL) || lwp->lwp_sysabort || 21190Sstevel@tonic-gate MUSTRETURN(p, t) || imm_unpark) 21200Sstevel@tonic-gate error = EINTR; 21210Sstevel@tonic-gate else if (imm_timeout || (timedwait && tim == -1)) 21220Sstevel@tonic-gate error = ETIME; 21230Sstevel@tonic-gate lwp->lwp_asleep = 0; 21240Sstevel@tonic-gate lwp->lwp_sysabort = 0; 21250Sstevel@tonic-gate watched = watch_disable_addr((caddr_t)sp, 21260Sstevel@tonic-gate sizeof (*sp), S_WRITE); 21270Sstevel@tonic-gate lwpchan_lock(&lwpchan, LWPCHAN_CVPOOL); 21280Sstevel@tonic-gate locked = 1; 21290Sstevel@tonic-gate fuword32_noerr((void *)&sp->sema_count, (uint32_t *)&count); 21300Sstevel@tonic-gate } 21310Sstevel@tonic-gate if (error == 0) 21320Sstevel@tonic-gate suword32_noerr((void *)&sp->sema_count, --count); 21330Sstevel@tonic-gate if (count != 0) { 21340Sstevel@tonic-gate (void) lwp_release(&lwpchan, &waiters, T_WAITCVSEM); 21350Sstevel@tonic-gate suword8_noerr(&sp->sema_waiters, waiters); 21360Sstevel@tonic-gate } 21370Sstevel@tonic-gate lwpchan_unlock(&lwpchan, LWPCHAN_CVPOOL); 21380Sstevel@tonic-gate out: 21390Sstevel@tonic-gate no_fault(); 21400Sstevel@tonic-gate if (watched) 21410Sstevel@tonic-gate watch_enable_addr((caddr_t)sp, sizeof (*sp), S_WRITE); 21420Sstevel@tonic-gate if (tsp && check_park && !time_error) 21430Sstevel@tonic-gate error = lwp_timer_copyout(&lwpt, error); 21440Sstevel@tonic-gate if (error) 21450Sstevel@tonic-gate return (set_errno(error)); 21460Sstevel@tonic-gate return (0); 21470Sstevel@tonic-gate } 21480Sstevel@tonic-gate 21490Sstevel@tonic-gate /* 21500Sstevel@tonic-gate * Obsolete lwp_sema_wait() interface, no longer called from libc. 21510Sstevel@tonic-gate * libc now calls lwp_sema_timedwait(). 21520Sstevel@tonic-gate * This system call trap exists solely for the benefit of old 21530Sstevel@tonic-gate * statically linked applications from Solaris 9 and before. 21540Sstevel@tonic-gate * It should be removed when we no longer care about such applications. 21550Sstevel@tonic-gate */ 21560Sstevel@tonic-gate int 21570Sstevel@tonic-gate lwp_sema_wait(lwp_sema_t *sp) 21580Sstevel@tonic-gate { 21590Sstevel@tonic-gate return (lwp_sema_timedwait(sp, NULL, 0)); 21600Sstevel@tonic-gate } 21610Sstevel@tonic-gate 21620Sstevel@tonic-gate int 21630Sstevel@tonic-gate lwp_sema_post(lwp_sema_t *sp) 21640Sstevel@tonic-gate { 21650Sstevel@tonic-gate proc_t *p = ttoproc(curthread); 21660Sstevel@tonic-gate label_t ljb; 21670Sstevel@tonic-gate volatile int locked = 0; 21680Sstevel@tonic-gate volatile int watched = 0; 21690Sstevel@tonic-gate volatile uint16_t type = 0; 21700Sstevel@tonic-gate int count; 21710Sstevel@tonic-gate lwpchan_t lwpchan; 21720Sstevel@tonic-gate uchar_t waiters; 21730Sstevel@tonic-gate int error = 0; 21740Sstevel@tonic-gate 21750Sstevel@tonic-gate if ((caddr_t)sp >= p->p_as->a_userlimit) 21760Sstevel@tonic-gate return (set_errno(EFAULT)); 21770Sstevel@tonic-gate 21780Sstevel@tonic-gate watched = watch_disable_addr((caddr_t)sp, sizeof (*sp), S_WRITE); 21790Sstevel@tonic-gate 21800Sstevel@tonic-gate if (on_fault(&ljb)) { 21810Sstevel@tonic-gate if (locked) 21820Sstevel@tonic-gate lwpchan_unlock(&lwpchan, LWPCHAN_CVPOOL); 21830Sstevel@tonic-gate error = EFAULT; 21840Sstevel@tonic-gate goto out; 21850Sstevel@tonic-gate } 21860Sstevel@tonic-gate /* 21876577Sraf * Force Copy-on-write if necessary and ensure that the 21886577Sraf * synchronization object resides in read/write memory. 21896577Sraf * Cause an EFAULT return now if this is not so. 21900Sstevel@tonic-gate */ 21910Sstevel@tonic-gate fuword16_noerr(&sp->sema_type, (uint16_t *)&type); 21920Sstevel@tonic-gate suword16_noerr(&sp->sema_type, type); 21930Sstevel@tonic-gate if (!get_lwpchan(curproc->p_as, (caddr_t)sp, type, 21940Sstevel@tonic-gate &lwpchan, LWPCHAN_CVPOOL)) { 21950Sstevel@tonic-gate error = EFAULT; 21960Sstevel@tonic-gate goto out; 21970Sstevel@tonic-gate } 21980Sstevel@tonic-gate lwpchan_lock(&lwpchan, LWPCHAN_CVPOOL); 21990Sstevel@tonic-gate locked = 1; 22000Sstevel@tonic-gate fuword32_noerr(&sp->sema_count, (uint32_t *)&count); 22010Sstevel@tonic-gate if (count == _SEM_VALUE_MAX) 22020Sstevel@tonic-gate error = EOVERFLOW; 22030Sstevel@tonic-gate else 22040Sstevel@tonic-gate suword32_noerr(&sp->sema_count, ++count); 22050Sstevel@tonic-gate if (count == 1) { 22060Sstevel@tonic-gate fuword8_noerr(&sp->sema_waiters, &waiters); 22070Sstevel@tonic-gate if (waiters) { 22080Sstevel@tonic-gate (void) lwp_release(&lwpchan, &waiters, T_WAITCVSEM); 22090Sstevel@tonic-gate suword8_noerr(&sp->sema_waiters, waiters); 22100Sstevel@tonic-gate } 22110Sstevel@tonic-gate } 22120Sstevel@tonic-gate lwpchan_unlock(&lwpchan, LWPCHAN_CVPOOL); 22130Sstevel@tonic-gate out: 22140Sstevel@tonic-gate no_fault(); 22150Sstevel@tonic-gate if (watched) 22160Sstevel@tonic-gate watch_enable_addr((caddr_t)sp, sizeof (*sp), S_WRITE); 22170Sstevel@tonic-gate if (error) 22180Sstevel@tonic-gate return (set_errno(error)); 22190Sstevel@tonic-gate return (0); 22200Sstevel@tonic-gate } 22210Sstevel@tonic-gate 22220Sstevel@tonic-gate #define TRW_WANT_WRITE 0x1 22230Sstevel@tonic-gate #define TRW_LOCK_GRANTED 0x2 22240Sstevel@tonic-gate 22250Sstevel@tonic-gate #define READ_LOCK 0 22260Sstevel@tonic-gate #define WRITE_LOCK 1 22270Sstevel@tonic-gate #define TRY_FLAG 0x10 22280Sstevel@tonic-gate #define READ_LOCK_TRY (READ_LOCK | TRY_FLAG) 22290Sstevel@tonic-gate #define WRITE_LOCK_TRY (WRITE_LOCK | TRY_FLAG) 22300Sstevel@tonic-gate 22310Sstevel@tonic-gate /* 22320Sstevel@tonic-gate * Release one writer or one or more readers. Compute the rwstate word to 22330Sstevel@tonic-gate * reflect the new state of the queue. For a safe hand-off we copy the new 22340Sstevel@tonic-gate * rwstate value back to userland before we wake any of the new lock holders. 22350Sstevel@tonic-gate * 22360Sstevel@tonic-gate * Note that sleepq_insert() implements a prioritized FIFO (with writers 22370Sstevel@tonic-gate * being given precedence over readers of the same priority). 22380Sstevel@tonic-gate * 22390Sstevel@tonic-gate * If the first thread is a reader we scan the queue releasing all readers 22400Sstevel@tonic-gate * until we hit a writer or the end of the queue. If the first thread is a 22414570Sraf * writer we still need to check for another writer. 22420Sstevel@tonic-gate */ 22430Sstevel@tonic-gate void 22440Sstevel@tonic-gate lwp_rwlock_release(lwpchan_t *lwpchan, lwp_rwlock_t *rw) 22450Sstevel@tonic-gate { 22460Sstevel@tonic-gate sleepq_head_t *sqh; 22470Sstevel@tonic-gate kthread_t *tp; 22480Sstevel@tonic-gate kthread_t **tpp; 22490Sstevel@tonic-gate kthread_t *tpnext; 22500Sstevel@tonic-gate kthread_t *wakelist = NULL; 22510Sstevel@tonic-gate uint32_t rwstate = 0; 22520Sstevel@tonic-gate int wcount = 0; 22530Sstevel@tonic-gate int rcount = 0; 22540Sstevel@tonic-gate 22550Sstevel@tonic-gate sqh = lwpsqhash(lwpchan); 22560Sstevel@tonic-gate disp_lock_enter(&sqh->sq_lock); 22570Sstevel@tonic-gate tpp = &sqh->sq_queue.sq_first; 22580Sstevel@tonic-gate while ((tp = *tpp) != NULL) { 22590Sstevel@tonic-gate if (tp->t_lwpchan.lc_wchan0 == lwpchan->lc_wchan0 && 22600Sstevel@tonic-gate tp->t_lwpchan.lc_wchan == lwpchan->lc_wchan) { 22610Sstevel@tonic-gate if (tp->t_writer & TRW_WANT_WRITE) { 22620Sstevel@tonic-gate if ((wcount++ == 0) && (rcount == 0)) { 22630Sstevel@tonic-gate rwstate |= URW_WRITE_LOCKED; 22640Sstevel@tonic-gate 22650Sstevel@tonic-gate /* Just one writer to wake. */ 22660Sstevel@tonic-gate sleepq_unlink(tpp, tp); 22670Sstevel@tonic-gate wakelist = tp; 22680Sstevel@tonic-gate 22690Sstevel@tonic-gate /* tpp already set for next thread. */ 22700Sstevel@tonic-gate continue; 22710Sstevel@tonic-gate } else { 22724570Sraf rwstate |= URW_HAS_WAITERS; 22730Sstevel@tonic-gate /* We need look no further. */ 22740Sstevel@tonic-gate break; 22750Sstevel@tonic-gate } 22760Sstevel@tonic-gate } else { 22770Sstevel@tonic-gate rcount++; 22780Sstevel@tonic-gate if (wcount == 0) { 22790Sstevel@tonic-gate rwstate++; 22800Sstevel@tonic-gate 22810Sstevel@tonic-gate /* Add reader to wake list. */ 22820Sstevel@tonic-gate sleepq_unlink(tpp, tp); 22830Sstevel@tonic-gate tp->t_link = wakelist; 22840Sstevel@tonic-gate wakelist = tp; 22850Sstevel@tonic-gate 22860Sstevel@tonic-gate /* tpp already set for next thread. */ 22870Sstevel@tonic-gate continue; 22884570Sraf } else { 22890Sstevel@tonic-gate rwstate |= URW_HAS_WAITERS; 22904570Sraf /* We need look no further. */ 22914570Sraf break; 22924570Sraf } 22930Sstevel@tonic-gate } 22940Sstevel@tonic-gate } 22950Sstevel@tonic-gate tpp = &tp->t_link; 22960Sstevel@tonic-gate } 22970Sstevel@tonic-gate 22980Sstevel@tonic-gate /* Copy the new rwstate back to userland. */ 22990Sstevel@tonic-gate suword32_noerr(&rw->rwlock_readers, rwstate); 23000Sstevel@tonic-gate 23010Sstevel@tonic-gate /* Wake the new lock holder(s) up. */ 23020Sstevel@tonic-gate tp = wakelist; 23030Sstevel@tonic-gate while (tp != NULL) { 23040Sstevel@tonic-gate DTRACE_SCHED1(wakeup, kthread_t *, tp); 23050Sstevel@tonic-gate tp->t_wchan0 = NULL; 23060Sstevel@tonic-gate tp->t_wchan = NULL; 23070Sstevel@tonic-gate tp->t_sobj_ops = NULL; 23080Sstevel@tonic-gate tp->t_writer |= TRW_LOCK_GRANTED; 23090Sstevel@tonic-gate tpnext = tp->t_link; 23100Sstevel@tonic-gate tp->t_link = NULL; 23110Sstevel@tonic-gate CL_WAKEUP(tp); 23120Sstevel@tonic-gate thread_unlock_high(tp); 23130Sstevel@tonic-gate tp = tpnext; 23140Sstevel@tonic-gate } 23150Sstevel@tonic-gate 23160Sstevel@tonic-gate disp_lock_exit(&sqh->sq_lock); 23170Sstevel@tonic-gate } 23180Sstevel@tonic-gate 23190Sstevel@tonic-gate /* 23200Sstevel@tonic-gate * We enter here holding the user-level mutex, which we must release before 23210Sstevel@tonic-gate * returning or blocking. Based on lwp_cond_wait(). 23220Sstevel@tonic-gate */ 23230Sstevel@tonic-gate static int 23240Sstevel@tonic-gate lwp_rwlock_lock(lwp_rwlock_t *rw, timespec_t *tsp, int rd_wr) 23250Sstevel@tonic-gate { 23260Sstevel@tonic-gate lwp_mutex_t *mp = NULL; 23270Sstevel@tonic-gate kthread_t *t = curthread; 23280Sstevel@tonic-gate kthread_t *tp; 23290Sstevel@tonic-gate klwp_t *lwp = ttolwp(t); 23300Sstevel@tonic-gate proc_t *p = ttoproc(t); 23310Sstevel@tonic-gate lwp_timer_t lwpt; 23320Sstevel@tonic-gate lwpchan_t lwpchan; 23330Sstevel@tonic-gate lwpchan_t mlwpchan; 23340Sstevel@tonic-gate caddr_t timedwait; 23350Sstevel@tonic-gate volatile uint16_t type = 0; 23360Sstevel@tonic-gate volatile uint8_t mtype = 0; 23370Sstevel@tonic-gate uchar_t mwaiters; 23380Sstevel@tonic-gate volatile int error = 0; 23390Sstevel@tonic-gate int time_error; 23400Sstevel@tonic-gate clock_t tim = -1; 23410Sstevel@tonic-gate volatile int locked = 0; 23420Sstevel@tonic-gate volatile int mlocked = 0; 23430Sstevel@tonic-gate volatile int watched = 0; 23440Sstevel@tonic-gate volatile int mwatched = 0; 23450Sstevel@tonic-gate label_t ljb; 23460Sstevel@tonic-gate volatile int no_lwpchan = 1; 23470Sstevel@tonic-gate int imm_timeout = 0; 23480Sstevel@tonic-gate int try_flag; 23490Sstevel@tonic-gate uint32_t rwstate; 23500Sstevel@tonic-gate int acquired = 0; 23510Sstevel@tonic-gate 23520Sstevel@tonic-gate /* We only check rw because the mutex is included in it. */ 23530Sstevel@tonic-gate if ((caddr_t)rw >= p->p_as->a_userlimit) 23540Sstevel@tonic-gate return (set_errno(EFAULT)); 23550Sstevel@tonic-gate 23560Sstevel@tonic-gate /* We must only report this error if we are about to sleep (later). */ 23570Sstevel@tonic-gate timedwait = (caddr_t)tsp; 23580Sstevel@tonic-gate if ((time_error = lwp_timer_copyin(&lwpt, tsp)) == 0 && 23590Sstevel@tonic-gate lwpt.lwpt_imm_timeout) { 23600Sstevel@tonic-gate imm_timeout = 1; 23610Sstevel@tonic-gate timedwait = NULL; 23620Sstevel@tonic-gate } 23630Sstevel@tonic-gate 23640Sstevel@tonic-gate (void) new_mstate(t, LMS_USER_LOCK); 23650Sstevel@tonic-gate 23660Sstevel@tonic-gate if (on_fault(&ljb)) { 23670Sstevel@tonic-gate if (no_lwpchan) { 23680Sstevel@tonic-gate error = EFAULT; 23690Sstevel@tonic-gate goto out_nodrop; 23700Sstevel@tonic-gate } 23710Sstevel@tonic-gate if (mlocked) { 23720Sstevel@tonic-gate mlocked = 0; 23730Sstevel@tonic-gate lwpchan_unlock(&mlwpchan, LWPCHAN_MPPOOL); 23740Sstevel@tonic-gate } 23750Sstevel@tonic-gate if (locked) { 23760Sstevel@tonic-gate locked = 0; 23770Sstevel@tonic-gate lwpchan_unlock(&lwpchan, LWPCHAN_CVPOOL); 23780Sstevel@tonic-gate } 23790Sstevel@tonic-gate /* 23800Sstevel@tonic-gate * Set up another on_fault() for a possible fault 23810Sstevel@tonic-gate * on the user lock accessed at "out_drop". 23820Sstevel@tonic-gate */ 23830Sstevel@tonic-gate if (on_fault(&ljb)) { 23840Sstevel@tonic-gate if (mlocked) { 23850Sstevel@tonic-gate mlocked = 0; 23860Sstevel@tonic-gate lwpchan_unlock(&mlwpchan, LWPCHAN_MPPOOL); 23870Sstevel@tonic-gate } 23880Sstevel@tonic-gate error = EFAULT; 23890Sstevel@tonic-gate goto out_nodrop; 23900Sstevel@tonic-gate } 23910Sstevel@tonic-gate error = EFAULT; 23920Sstevel@tonic-gate goto out_nodrop; 23930Sstevel@tonic-gate } 23940Sstevel@tonic-gate 23950Sstevel@tonic-gate /* Process rd_wr (including sanity check). */ 23960Sstevel@tonic-gate try_flag = (rd_wr & TRY_FLAG); 23970Sstevel@tonic-gate rd_wr &= ~TRY_FLAG; 23980Sstevel@tonic-gate if ((rd_wr != READ_LOCK) && (rd_wr != WRITE_LOCK)) { 23990Sstevel@tonic-gate error = EINVAL; 24000Sstevel@tonic-gate goto out_nodrop; 24010Sstevel@tonic-gate } 24020Sstevel@tonic-gate 24036577Sraf /* 24046577Sraf * Force Copy-on-write if necessary and ensure that the 24056577Sraf * synchronization object resides in read/write memory. 24066577Sraf * Cause an EFAULT return now if this is not so. 24076577Sraf */ 24080Sstevel@tonic-gate mp = &rw->mutex; 24090Sstevel@tonic-gate fuword8_noerr(&mp->mutex_type, (uint8_t *)&mtype); 24100Sstevel@tonic-gate fuword16_noerr(&rw->rwlock_type, (uint16_t *)&type); 24116577Sraf suword8_noerr(&mp->mutex_type, mtype); 24126577Sraf suword16_noerr(&rw->rwlock_type, type); 24136577Sraf 24146577Sraf /* We can only continue for simple USYNC_PROCESS locks. */ 24150Sstevel@tonic-gate if ((mtype != USYNC_PROCESS) || (type != USYNC_PROCESS)) { 24160Sstevel@tonic-gate error = EINVAL; 24170Sstevel@tonic-gate goto out_nodrop; 24180Sstevel@tonic-gate } 24190Sstevel@tonic-gate 24200Sstevel@tonic-gate /* Convert user level mutex, "mp", to a unique lwpchan. */ 24210Sstevel@tonic-gate if (!get_lwpchan(p->p_as, (caddr_t)mp, mtype, 24220Sstevel@tonic-gate &mlwpchan, LWPCHAN_MPPOOL)) { 24230Sstevel@tonic-gate error = EFAULT; 24240Sstevel@tonic-gate goto out_nodrop; 24250Sstevel@tonic-gate } 24260Sstevel@tonic-gate 24270Sstevel@tonic-gate /* Convert user level rwlock, "rw", to a unique lwpchan. */ 24280Sstevel@tonic-gate if (!get_lwpchan(p->p_as, (caddr_t)rw, type, 24290Sstevel@tonic-gate &lwpchan, LWPCHAN_CVPOOL)) { 24300Sstevel@tonic-gate error = EFAULT; 24310Sstevel@tonic-gate goto out_nodrop; 24320Sstevel@tonic-gate } 24330Sstevel@tonic-gate 24340Sstevel@tonic-gate no_lwpchan = 0; 24350Sstevel@tonic-gate watched = watch_disable_addr((caddr_t)rw, sizeof (*rw), S_WRITE); 24360Sstevel@tonic-gate mwatched = watch_disable_addr((caddr_t)mp, sizeof (*mp), S_WRITE); 24370Sstevel@tonic-gate 24380Sstevel@tonic-gate /* 24390Sstevel@tonic-gate * lwpchan_lock() ensures that the calling LWP is put to sleep 24400Sstevel@tonic-gate * atomically with respect to a possible wakeup which is a result 24410Sstevel@tonic-gate * of lwp_rwlock_unlock(). 24420Sstevel@tonic-gate * 24430Sstevel@tonic-gate * What's misleading is that the LWP is put to sleep after the 24440Sstevel@tonic-gate * rwlock's mutex is released. This is OK as long as the release 24450Sstevel@tonic-gate * operation is also done while holding mlwpchan. The LWP is then 24460Sstevel@tonic-gate * put to sleep when the possibility of pagefaulting or sleeping 24470Sstevel@tonic-gate * has been completely eliminated. 24480Sstevel@tonic-gate */ 24490Sstevel@tonic-gate lwpchan_lock(&lwpchan, LWPCHAN_CVPOOL); 24500Sstevel@tonic-gate locked = 1; 24510Sstevel@tonic-gate lwpchan_lock(&mlwpchan, LWPCHAN_MPPOOL); 24520Sstevel@tonic-gate mlocked = 1; 24530Sstevel@tonic-gate 24540Sstevel@tonic-gate /* 24550Sstevel@tonic-gate * Fetch the current rwlock state. 24560Sstevel@tonic-gate * 24574570Sraf * The possibility of spurious wake-ups or killed waiters means 24584570Sraf * rwstate's URW_HAS_WAITERS bit may indicate false positives. 24594570Sraf * We only fix these if they are important to us. 24600Sstevel@tonic-gate * 24610Sstevel@tonic-gate * Although various error states can be observed here (e.g. the lock 24620Sstevel@tonic-gate * is not held, but there are waiters) we assume these are applicaton 24630Sstevel@tonic-gate * errors and so we take no corrective action. 24640Sstevel@tonic-gate */ 24650Sstevel@tonic-gate fuword32_noerr(&rw->rwlock_readers, &rwstate); 24664570Sraf /* 24674570Sraf * We cannot legitimately get here from user-level 24684570Sraf * without URW_HAS_WAITERS being set. 24694570Sraf * Set it now to guard against user-level error. 24704570Sraf */ 24714570Sraf rwstate |= URW_HAS_WAITERS; 24720Sstevel@tonic-gate 24730Sstevel@tonic-gate /* 24744570Sraf * We can try only if the lock isn't held by a writer. 24750Sstevel@tonic-gate */ 24764570Sraf if (!(rwstate & URW_WRITE_LOCKED)) { 24770Sstevel@tonic-gate tp = lwp_queue_waiter(&lwpchan); 24780Sstevel@tonic-gate if (tp == NULL) { 24790Sstevel@tonic-gate /* 24800Sstevel@tonic-gate * Hmmm, rwstate indicates waiters but there are 24810Sstevel@tonic-gate * none queued. This could just be the result of a 24824570Sraf * spurious wakeup, so let's ignore it. 24834570Sraf * 24844570Sraf * We now have a chance to acquire the lock 24854570Sraf * uncontended, but this is the last chance for 24864570Sraf * a writer to acquire the lock without blocking. 24870Sstevel@tonic-gate */ 24880Sstevel@tonic-gate if (rd_wr == READ_LOCK) { 24890Sstevel@tonic-gate rwstate++; 24900Sstevel@tonic-gate acquired = 1; 24914570Sraf } else if ((rwstate & URW_READERS_MASK) == 0) { 24924570Sraf rwstate |= URW_WRITE_LOCKED; 24930Sstevel@tonic-gate acquired = 1; 24940Sstevel@tonic-gate } 24950Sstevel@tonic-gate } else if (rd_wr == READ_LOCK) { 24960Sstevel@tonic-gate /* 24970Sstevel@tonic-gate * This is the last chance for a reader to acquire 24980Sstevel@tonic-gate * the lock now, but it can only do so if there is 24990Sstevel@tonic-gate * no writer of equal or greater priority at the 25000Sstevel@tonic-gate * head of the queue . 25010Sstevel@tonic-gate * 25020Sstevel@tonic-gate * It is also just possible that there is a reader 25030Sstevel@tonic-gate * at the head of the queue. This may be the result 25040Sstevel@tonic-gate * of a spurious wakeup or an application failure. 25050Sstevel@tonic-gate * In this case we only acquire the lock if we have 25060Sstevel@tonic-gate * equal or greater priority. It is not our job to 25070Sstevel@tonic-gate * release spurious waiters. 25080Sstevel@tonic-gate */ 25090Sstevel@tonic-gate pri_t our_pri = DISP_PRIO(t); 25100Sstevel@tonic-gate pri_t his_pri = DISP_PRIO(tp); 25110Sstevel@tonic-gate 25120Sstevel@tonic-gate if ((our_pri > his_pri) || ((our_pri == his_pri) && 25130Sstevel@tonic-gate !(tp->t_writer & TRW_WANT_WRITE))) { 25140Sstevel@tonic-gate rwstate++; 25150Sstevel@tonic-gate acquired = 1; 25160Sstevel@tonic-gate } 25170Sstevel@tonic-gate } 25180Sstevel@tonic-gate } 25190Sstevel@tonic-gate 25200Sstevel@tonic-gate if (acquired || try_flag || time_error) { 25210Sstevel@tonic-gate /* 25224570Sraf * We're not going to block this time. 25230Sstevel@tonic-gate */ 25240Sstevel@tonic-gate suword32_noerr(&rw->rwlock_readers, rwstate); 25250Sstevel@tonic-gate lwpchan_unlock(&lwpchan, LWPCHAN_CVPOOL); 25260Sstevel@tonic-gate locked = 0; 25270Sstevel@tonic-gate 25280Sstevel@tonic-gate if (acquired) { 25290Sstevel@tonic-gate /* 25300Sstevel@tonic-gate * Got the lock! 25310Sstevel@tonic-gate */ 25320Sstevel@tonic-gate error = 0; 25330Sstevel@tonic-gate 25340Sstevel@tonic-gate } else if (try_flag) { 25350Sstevel@tonic-gate /* 25360Sstevel@tonic-gate * We didn't get the lock and we're about to block. 25370Sstevel@tonic-gate * If we're doing a trylock, return EBUSY instead. 25380Sstevel@tonic-gate */ 25390Sstevel@tonic-gate error = EBUSY; 25400Sstevel@tonic-gate 25410Sstevel@tonic-gate } else if (time_error) { 25420Sstevel@tonic-gate /* 25430Sstevel@tonic-gate * The SUSV3 POSIX spec is very clear that we should 25440Sstevel@tonic-gate * get no error from validating the timer (above) 25450Sstevel@tonic-gate * until we would actually sleep. 25460Sstevel@tonic-gate */ 25470Sstevel@tonic-gate error = time_error; 25480Sstevel@tonic-gate } 25490Sstevel@tonic-gate 25500Sstevel@tonic-gate goto out_drop; 25510Sstevel@tonic-gate } 25520Sstevel@tonic-gate 25530Sstevel@tonic-gate /* 25540Sstevel@tonic-gate * We're about to block, so indicate what kind of waiter we are. 25550Sstevel@tonic-gate */ 25560Sstevel@tonic-gate t->t_writer = 0; 25574570Sraf if (rd_wr == WRITE_LOCK) 25580Sstevel@tonic-gate t->t_writer = TRW_WANT_WRITE; 25590Sstevel@tonic-gate suword32_noerr(&rw->rwlock_readers, rwstate); 25600Sstevel@tonic-gate 25610Sstevel@tonic-gate /* 25620Sstevel@tonic-gate * Unlock the rwlock's mutex (pagefaults are possible here). 25630Sstevel@tonic-gate */ 25644570Sraf suword32_noerr((uint32_t *)&mp->mutex_owner, 0); 25654570Sraf suword32_noerr((uint32_t *)&mp->mutex_owner + 1, 0); 25664570Sraf suword32_noerr(&mp->mutex_ownerpid, 0); 25670Sstevel@tonic-gate ulock_clear(&mp->mutex_lockw); 25680Sstevel@tonic-gate fuword8_noerr(&mp->mutex_waiters, &mwaiters); 25690Sstevel@tonic-gate if (mwaiters != 0) { 25700Sstevel@tonic-gate /* 25710Sstevel@tonic-gate * Given the locking of mlwpchan around the release of 25720Sstevel@tonic-gate * the mutex and checking for waiters, the following 25730Sstevel@tonic-gate * call to lwp_release() can fail ONLY if the lock 25740Sstevel@tonic-gate * acquirer is interrupted after setting the waiter bit, 25750Sstevel@tonic-gate * calling lwp_block() and releasing mlwpchan. 25760Sstevel@tonic-gate * In this case, it could get pulled off the LWP sleep 25770Sstevel@tonic-gate * queue (via setrun()) before the following call to 25780Sstevel@tonic-gate * lwp_release() occurs, and the lock requestor will 25790Sstevel@tonic-gate * update the waiter bit correctly by re-evaluating it. 25800Sstevel@tonic-gate */ 25816057Sraf if (lwp_release(&mlwpchan, &mwaiters, 0)) 25820Sstevel@tonic-gate suword8_noerr(&mp->mutex_waiters, mwaiters); 25830Sstevel@tonic-gate } 25840Sstevel@tonic-gate lwpchan_unlock(&mlwpchan, LWPCHAN_MPPOOL); 25850Sstevel@tonic-gate mlocked = 0; 25860Sstevel@tonic-gate no_fault(); 25870Sstevel@tonic-gate 25880Sstevel@tonic-gate if (mwatched) { 25890Sstevel@tonic-gate watch_enable_addr((caddr_t)mp, sizeof (*mp), S_WRITE); 25900Sstevel@tonic-gate mwatched = 0; 25910Sstevel@tonic-gate } 25920Sstevel@tonic-gate if (watched) { 25930Sstevel@tonic-gate watch_enable_addr((caddr_t)rw, sizeof (*rw), S_WRITE); 25940Sstevel@tonic-gate watched = 0; 25950Sstevel@tonic-gate } 25960Sstevel@tonic-gate 25970Sstevel@tonic-gate /* 25980Sstevel@tonic-gate * Put the LWP in an orderly state for debugging. 25990Sstevel@tonic-gate */ 26000Sstevel@tonic-gate prstop(PR_REQUESTED, 0); 26010Sstevel@tonic-gate if (timedwait) { 26020Sstevel@tonic-gate /* 26030Sstevel@tonic-gate * If we successfully queue the timeout, 26040Sstevel@tonic-gate * then don't drop t_delay_lock until 26050Sstevel@tonic-gate * we are on the sleep queue (below). 26060Sstevel@tonic-gate */ 26070Sstevel@tonic-gate mutex_enter(&t->t_delay_lock); 26080Sstevel@tonic-gate if (lwp_timer_enqueue(&lwpt) != 0) { 26090Sstevel@tonic-gate mutex_exit(&t->t_delay_lock); 26100Sstevel@tonic-gate imm_timeout = 1; 26110Sstevel@tonic-gate timedwait = NULL; 26120Sstevel@tonic-gate } 26130Sstevel@tonic-gate } 26140Sstevel@tonic-gate t->t_flag |= T_WAITCVSEM; 26150Sstevel@tonic-gate lwp_block(&lwpchan); 26160Sstevel@tonic-gate 26170Sstevel@tonic-gate /* 26180Sstevel@tonic-gate * Nothing should happen to cause the LWp to go to sleep until after 26190Sstevel@tonic-gate * it returns from swtch(). 26200Sstevel@tonic-gate */ 26210Sstevel@tonic-gate if (timedwait) 26220Sstevel@tonic-gate mutex_exit(&t->t_delay_lock); 26230Sstevel@tonic-gate locked = 0; 26240Sstevel@tonic-gate lwpchan_unlock(&lwpchan, LWPCHAN_CVPOOL); 26256622Sraf if (ISSIG(t, JUSTLOOKING) || MUSTRETURN(p, t) || imm_timeout) 26260Sstevel@tonic-gate setrun(t); 26270Sstevel@tonic-gate swtch(); 26280Sstevel@tonic-gate 26290Sstevel@tonic-gate /* 26300Sstevel@tonic-gate * We're back, but we need to work out why. Were we interrupted? Did 26310Sstevel@tonic-gate * we timeout? Were we granted the lock? 26320Sstevel@tonic-gate */ 26330Sstevel@tonic-gate error = EAGAIN; 26340Sstevel@tonic-gate acquired = (t->t_writer & TRW_LOCK_GRANTED); 26350Sstevel@tonic-gate t->t_writer = 0; 26360Sstevel@tonic-gate t->t_flag &= ~(T_WAITCVSEM | T_WAKEABLE); 26370Sstevel@tonic-gate if (timedwait) 26380Sstevel@tonic-gate tim = lwp_timer_dequeue(&lwpt); 26390Sstevel@tonic-gate if (ISSIG(t, FORREAL) || lwp->lwp_sysabort || MUSTRETURN(p, t)) 26400Sstevel@tonic-gate error = EINTR; 26410Sstevel@tonic-gate else if (imm_timeout || (timedwait && tim == -1)) 26420Sstevel@tonic-gate error = ETIME; 26430Sstevel@tonic-gate lwp->lwp_asleep = 0; 26440Sstevel@tonic-gate lwp->lwp_sysabort = 0; 26450Sstevel@tonic-gate setallwatch(); 26460Sstevel@tonic-gate 26470Sstevel@tonic-gate /* 26480Sstevel@tonic-gate * If we were granted the lock we don't care about EINTR or ETIME. 26490Sstevel@tonic-gate */ 26500Sstevel@tonic-gate if (acquired) 26510Sstevel@tonic-gate error = 0; 26520Sstevel@tonic-gate 26530Sstevel@tonic-gate if (t->t_mstate == LMS_USER_LOCK) 26540Sstevel@tonic-gate (void) new_mstate(t, LMS_SYSTEM); 26550Sstevel@tonic-gate 26560Sstevel@tonic-gate if (error) 26570Sstevel@tonic-gate return (set_errno(error)); 26580Sstevel@tonic-gate return (0); 26590Sstevel@tonic-gate 26600Sstevel@tonic-gate out_drop: 26610Sstevel@tonic-gate /* 26620Sstevel@tonic-gate * Make sure that the user level lock is dropped before returning 26630Sstevel@tonic-gate * to the caller. 26640Sstevel@tonic-gate */ 26650Sstevel@tonic-gate if (!mlocked) { 26660Sstevel@tonic-gate lwpchan_lock(&mlwpchan, LWPCHAN_MPPOOL); 26670Sstevel@tonic-gate mlocked = 1; 26680Sstevel@tonic-gate } 26694570Sraf suword32_noerr((uint32_t *)&mp->mutex_owner, 0); 26704570Sraf suword32_noerr((uint32_t *)&mp->mutex_owner + 1, 0); 26710Sstevel@tonic-gate suword32_noerr(&mp->mutex_ownerpid, 0); 26720Sstevel@tonic-gate ulock_clear(&mp->mutex_lockw); 26730Sstevel@tonic-gate fuword8_noerr(&mp->mutex_waiters, &mwaiters); 26740Sstevel@tonic-gate if (mwaiters != 0) { 26750Sstevel@tonic-gate /* 26760Sstevel@tonic-gate * See comment above on lock clearing and lwp_release() 26770Sstevel@tonic-gate * success/failure. 26780Sstevel@tonic-gate */ 26796057Sraf if (lwp_release(&mlwpchan, &mwaiters, 0)) 26800Sstevel@tonic-gate suword8_noerr(&mp->mutex_waiters, mwaiters); 26810Sstevel@tonic-gate } 26820Sstevel@tonic-gate lwpchan_unlock(&mlwpchan, LWPCHAN_MPPOOL); 26830Sstevel@tonic-gate mlocked = 0; 26840Sstevel@tonic-gate 26850Sstevel@tonic-gate out_nodrop: 26860Sstevel@tonic-gate no_fault(); 26870Sstevel@tonic-gate if (mwatched) 26880Sstevel@tonic-gate watch_enable_addr((caddr_t)mp, sizeof (*mp), S_WRITE); 26890Sstevel@tonic-gate if (watched) 26900Sstevel@tonic-gate watch_enable_addr((caddr_t)rw, sizeof (*rw), S_WRITE); 26910Sstevel@tonic-gate if (t->t_mstate == LMS_USER_LOCK) 26920Sstevel@tonic-gate (void) new_mstate(t, LMS_SYSTEM); 26930Sstevel@tonic-gate if (error) 26940Sstevel@tonic-gate return (set_errno(error)); 26950Sstevel@tonic-gate return (0); 26960Sstevel@tonic-gate } 26970Sstevel@tonic-gate 26980Sstevel@tonic-gate /* 26990Sstevel@tonic-gate * We enter here holding the user-level mutex but, unlike lwp_rwlock_lock(), 27000Sstevel@tonic-gate * we never drop the lock. 27010Sstevel@tonic-gate */ 27020Sstevel@tonic-gate static int 27030Sstevel@tonic-gate lwp_rwlock_unlock(lwp_rwlock_t *rw) 27040Sstevel@tonic-gate { 27050Sstevel@tonic-gate kthread_t *t = curthread; 27060Sstevel@tonic-gate proc_t *p = ttoproc(t); 27070Sstevel@tonic-gate lwpchan_t lwpchan; 27080Sstevel@tonic-gate volatile uint16_t type = 0; 27090Sstevel@tonic-gate volatile int error = 0; 27100Sstevel@tonic-gate volatile int locked = 0; 27110Sstevel@tonic-gate volatile int watched = 0; 27120Sstevel@tonic-gate label_t ljb; 27130Sstevel@tonic-gate volatile int no_lwpchan = 1; 27140Sstevel@tonic-gate uint32_t rwstate; 27150Sstevel@tonic-gate 27160Sstevel@tonic-gate /* We only check rw because the mutex is included in it. */ 27170Sstevel@tonic-gate if ((caddr_t)rw >= p->p_as->a_userlimit) 27180Sstevel@tonic-gate return (set_errno(EFAULT)); 27190Sstevel@tonic-gate 27200Sstevel@tonic-gate if (on_fault(&ljb)) { 27210Sstevel@tonic-gate if (no_lwpchan) { 27220Sstevel@tonic-gate error = EFAULT; 27230Sstevel@tonic-gate goto out_nodrop; 27240Sstevel@tonic-gate } 27250Sstevel@tonic-gate if (locked) { 27260Sstevel@tonic-gate locked = 0; 27270Sstevel@tonic-gate lwpchan_unlock(&lwpchan, LWPCHAN_CVPOOL); 27280Sstevel@tonic-gate } 27290Sstevel@tonic-gate error = EFAULT; 27300Sstevel@tonic-gate goto out_nodrop; 27310Sstevel@tonic-gate } 27320Sstevel@tonic-gate 27336577Sraf /* 27346577Sraf * Force Copy-on-write if necessary and ensure that the 27356577Sraf * synchronization object resides in read/write memory. 27366577Sraf * Cause an EFAULT return now if this is not so. 27376577Sraf */ 27386577Sraf fuword16_noerr(&rw->rwlock_type, (uint16_t *)&type); 27396577Sraf suword16_noerr(&rw->rwlock_type, type); 27406577Sraf 27410Sstevel@tonic-gate /* We can only continue for simple USYNC_PROCESS locks. */ 27420Sstevel@tonic-gate if (type != USYNC_PROCESS) { 27430Sstevel@tonic-gate error = EINVAL; 27440Sstevel@tonic-gate goto out_nodrop; 27450Sstevel@tonic-gate } 27460Sstevel@tonic-gate 27470Sstevel@tonic-gate /* Convert user level rwlock, "rw", to a unique lwpchan. */ 27480Sstevel@tonic-gate if (!get_lwpchan(p->p_as, (caddr_t)rw, type, 27490Sstevel@tonic-gate &lwpchan, LWPCHAN_CVPOOL)) { 27500Sstevel@tonic-gate error = EFAULT; 27510Sstevel@tonic-gate goto out_nodrop; 27520Sstevel@tonic-gate } 27530Sstevel@tonic-gate 27540Sstevel@tonic-gate no_lwpchan = 0; 27550Sstevel@tonic-gate watched = watch_disable_addr((caddr_t)rw, sizeof (*rw), S_WRITE); 27560Sstevel@tonic-gate 27570Sstevel@tonic-gate lwpchan_lock(&lwpchan, LWPCHAN_CVPOOL); 27580Sstevel@tonic-gate locked = 1; 27590Sstevel@tonic-gate 27600Sstevel@tonic-gate /* 27610Sstevel@tonic-gate * We can resolve multiple readers (except the last reader) here. 27620Sstevel@tonic-gate * For the last reader or a writer we need lwp_rwlock_release(), 27630Sstevel@tonic-gate * to which we also delegate the task of copying the new rwstate 27640Sstevel@tonic-gate * back to userland (see the comment there). 27650Sstevel@tonic-gate */ 27660Sstevel@tonic-gate fuword32_noerr(&rw->rwlock_readers, &rwstate); 27670Sstevel@tonic-gate if (rwstate & URW_WRITE_LOCKED) 27680Sstevel@tonic-gate lwp_rwlock_release(&lwpchan, rw); 27690Sstevel@tonic-gate else if ((rwstate & URW_READERS_MASK) > 0) { 27700Sstevel@tonic-gate rwstate--; 27710Sstevel@tonic-gate if ((rwstate & URW_READERS_MASK) == 0) 27720Sstevel@tonic-gate lwp_rwlock_release(&lwpchan, rw); 27730Sstevel@tonic-gate else 27740Sstevel@tonic-gate suword32_noerr(&rw->rwlock_readers, rwstate); 27750Sstevel@tonic-gate } 27760Sstevel@tonic-gate 27770Sstevel@tonic-gate lwpchan_unlock(&lwpchan, LWPCHAN_CVPOOL); 27780Sstevel@tonic-gate locked = 0; 27790Sstevel@tonic-gate error = 0; 27800Sstevel@tonic-gate 27810Sstevel@tonic-gate out_nodrop: 27820Sstevel@tonic-gate no_fault(); 27830Sstevel@tonic-gate if (watched) 27840Sstevel@tonic-gate watch_enable_addr((caddr_t)rw, sizeof (*rw), S_WRITE); 27850Sstevel@tonic-gate if (error) 27860Sstevel@tonic-gate return (set_errno(error)); 27870Sstevel@tonic-gate return (0); 27880Sstevel@tonic-gate } 27890Sstevel@tonic-gate 27900Sstevel@tonic-gate int 27910Sstevel@tonic-gate lwp_rwlock_sys(int subcode, lwp_rwlock_t *rwlp, timespec_t *tsp) 27920Sstevel@tonic-gate { 27930Sstevel@tonic-gate switch (subcode) { 27940Sstevel@tonic-gate case 0: 27950Sstevel@tonic-gate return (lwp_rwlock_lock(rwlp, tsp, READ_LOCK)); 27960Sstevel@tonic-gate case 1: 27970Sstevel@tonic-gate return (lwp_rwlock_lock(rwlp, tsp, WRITE_LOCK)); 27980Sstevel@tonic-gate case 2: 27990Sstevel@tonic-gate return (lwp_rwlock_lock(rwlp, NULL, READ_LOCK_TRY)); 28000Sstevel@tonic-gate case 3: 28010Sstevel@tonic-gate return (lwp_rwlock_lock(rwlp, NULL, WRITE_LOCK_TRY)); 28020Sstevel@tonic-gate case 4: 28030Sstevel@tonic-gate return (lwp_rwlock_unlock(rwlp)); 28040Sstevel@tonic-gate } 28050Sstevel@tonic-gate return (set_errno(EINVAL)); 28060Sstevel@tonic-gate } 28070Sstevel@tonic-gate 28080Sstevel@tonic-gate /* 28090Sstevel@tonic-gate * Return the owner of the user-level s-object. 28100Sstevel@tonic-gate * Since we can't really do this, return NULL. 28110Sstevel@tonic-gate */ 28120Sstevel@tonic-gate /* ARGSUSED */ 28130Sstevel@tonic-gate static kthread_t * 28140Sstevel@tonic-gate lwpsobj_owner(caddr_t sobj) 28150Sstevel@tonic-gate { 28160Sstevel@tonic-gate return ((kthread_t *)NULL); 28170Sstevel@tonic-gate } 28180Sstevel@tonic-gate 28190Sstevel@tonic-gate /* 28200Sstevel@tonic-gate * Wake up a thread asleep on a user-level synchronization 28210Sstevel@tonic-gate * object. 28220Sstevel@tonic-gate */ 28230Sstevel@tonic-gate static void 28240Sstevel@tonic-gate lwp_unsleep(kthread_t *t) 28250Sstevel@tonic-gate { 28260Sstevel@tonic-gate ASSERT(THREAD_LOCK_HELD(t)); 28270Sstevel@tonic-gate if (t->t_wchan0 != NULL) { 28280Sstevel@tonic-gate sleepq_head_t *sqh; 28290Sstevel@tonic-gate sleepq_t *sqp = t->t_sleepq; 28300Sstevel@tonic-gate 28310Sstevel@tonic-gate if (sqp != NULL) { 28320Sstevel@tonic-gate sqh = lwpsqhash(&t->t_lwpchan); 28330Sstevel@tonic-gate ASSERT(&sqh->sq_queue == sqp); 28340Sstevel@tonic-gate sleepq_unsleep(t); 28350Sstevel@tonic-gate disp_lock_exit_high(&sqh->sq_lock); 28360Sstevel@tonic-gate CL_SETRUN(t); 28370Sstevel@tonic-gate return; 28380Sstevel@tonic-gate } 28390Sstevel@tonic-gate } 28400Sstevel@tonic-gate panic("lwp_unsleep: thread %p not on sleepq", (void *)t); 28410Sstevel@tonic-gate } 28420Sstevel@tonic-gate 28430Sstevel@tonic-gate /* 28440Sstevel@tonic-gate * Change the priority of a thread asleep on a user-level 28450Sstevel@tonic-gate * synchronization object. To maintain proper priority order, 28460Sstevel@tonic-gate * we: 28470Sstevel@tonic-gate * o dequeue the thread. 28480Sstevel@tonic-gate * o change its priority. 28490Sstevel@tonic-gate * o re-enqueue the thread. 28500Sstevel@tonic-gate * Assumption: the thread is locked on entry. 28510Sstevel@tonic-gate */ 28520Sstevel@tonic-gate static void 28530Sstevel@tonic-gate lwp_change_pri(kthread_t *t, pri_t pri, pri_t *t_prip) 28540Sstevel@tonic-gate { 28550Sstevel@tonic-gate ASSERT(THREAD_LOCK_HELD(t)); 28560Sstevel@tonic-gate if (t->t_wchan0 != NULL) { 28570Sstevel@tonic-gate sleepq_t *sqp = t->t_sleepq; 28580Sstevel@tonic-gate 28590Sstevel@tonic-gate sleepq_dequeue(t); 28600Sstevel@tonic-gate *t_prip = pri; 28610Sstevel@tonic-gate sleepq_insert(sqp, t); 28620Sstevel@tonic-gate } else 28630Sstevel@tonic-gate panic("lwp_change_pri: %p not on a sleep queue", (void *)t); 28640Sstevel@tonic-gate } 28650Sstevel@tonic-gate 28660Sstevel@tonic-gate /* 28677751SRoger.Faulkner@Sun.COM * Clean up a left-over process-shared robust mutex 28680Sstevel@tonic-gate */ 28690Sstevel@tonic-gate static void 28700Sstevel@tonic-gate lwp_mutex_cleanup(lwpchan_entry_t *ent, uint16_t lockflg) 28710Sstevel@tonic-gate { 28720Sstevel@tonic-gate uint16_t flag; 28730Sstevel@tonic-gate uchar_t waiters; 28740Sstevel@tonic-gate label_t ljb; 28750Sstevel@tonic-gate pid_t owner_pid; 28760Sstevel@tonic-gate lwp_mutex_t *lp; 28770Sstevel@tonic-gate volatile int locked = 0; 28780Sstevel@tonic-gate volatile int watched = 0; 28794574Sraf volatile struct upimutex *upimutex = NULL; 28804574Sraf volatile int upilocked = 0; 28810Sstevel@tonic-gate 28827751SRoger.Faulkner@Sun.COM if ((ent->lwpchan_type & (USYNC_PROCESS | LOCK_ROBUST)) 28837751SRoger.Faulkner@Sun.COM != (USYNC_PROCESS | LOCK_ROBUST)) 28847751SRoger.Faulkner@Sun.COM return; 28850Sstevel@tonic-gate 28860Sstevel@tonic-gate lp = (lwp_mutex_t *)ent->lwpchan_addr; 28870Sstevel@tonic-gate watched = watch_disable_addr((caddr_t)lp, sizeof (*lp), S_WRITE); 28880Sstevel@tonic-gate if (on_fault(&ljb)) { 28890Sstevel@tonic-gate if (locked) 28900Sstevel@tonic-gate lwpchan_unlock(&ent->lwpchan_lwpchan, LWPCHAN_MPPOOL); 28914574Sraf if (upilocked) 28924574Sraf upimutex_unlock((upimutex_t *)upimutex, 0); 28930Sstevel@tonic-gate goto out; 28940Sstevel@tonic-gate } 28957751SRoger.Faulkner@Sun.COM 28967751SRoger.Faulkner@Sun.COM fuword32_noerr(&lp->mutex_ownerpid, (uint32_t *)&owner_pid); 28977751SRoger.Faulkner@Sun.COM 28984574Sraf if (UPIMUTEX(ent->lwpchan_type)) { 28994574Sraf lwpchan_t lwpchan = ent->lwpchan_lwpchan; 29004574Sraf upib_t *upibp = &UPI_CHAIN(lwpchan); 29014574Sraf 29027751SRoger.Faulkner@Sun.COM if (owner_pid != curproc->p_pid) 29037751SRoger.Faulkner@Sun.COM goto out; 29044574Sraf mutex_enter(&upibp->upib_lock); 29054574Sraf upimutex = upi_get(upibp, &lwpchan); 29064574Sraf if (upimutex == NULL || upimutex->upi_owner != curthread) { 29074574Sraf mutex_exit(&upibp->upib_lock); 29084574Sraf goto out; 29094574Sraf } 29104574Sraf mutex_exit(&upibp->upib_lock); 29114574Sraf upilocked = 1; 29124574Sraf flag = lwp_clear_mutex(lp, lockflg); 29134574Sraf suword8_noerr(&lp->mutex_lockw, 0); 29144574Sraf upimutex_unlock((upimutex_t *)upimutex, flag); 29154574Sraf } else { 29164574Sraf lwpchan_lock(&ent->lwpchan_lwpchan, LWPCHAN_MPPOOL); 29174574Sraf locked = 1; 29187751SRoger.Faulkner@Sun.COM /* 29197751SRoger.Faulkner@Sun.COM * Clear the spinners count because one of our 29207751SRoger.Faulkner@Sun.COM * threads could have been spinning for this lock 29217751SRoger.Faulkner@Sun.COM * at user level when the process was suddenly killed. 29227751SRoger.Faulkner@Sun.COM * There is no harm in this since user-level libc code 29237751SRoger.Faulkner@Sun.COM * will adapt to the sudden change in the spinner count. 29247751SRoger.Faulkner@Sun.COM */ 29257751SRoger.Faulkner@Sun.COM suword8_noerr(&lp->mutex_spinners, 0); 29267751SRoger.Faulkner@Sun.COM if (owner_pid != curproc->p_pid) { 29276057Sraf /* 29287751SRoger.Faulkner@Sun.COM * We are not the owner. There may or may not be one. 29297751SRoger.Faulkner@Sun.COM * If there are waiters, we wake up one or all of them. 29307751SRoger.Faulkner@Sun.COM * It doesn't hurt to wake them up in error since 29317751SRoger.Faulkner@Sun.COM * they will just retry the lock and go to sleep 29327751SRoger.Faulkner@Sun.COM * again if necessary. 29336057Sraf */ 29346057Sraf fuword8_noerr(&lp->mutex_waiters, &waiters); 29356057Sraf if (waiters != 0) { /* there are waiters */ 29366057Sraf fuword16_noerr(&lp->mutex_flag, &flag); 29376057Sraf if (flag & LOCK_NOTRECOVERABLE) { 29386057Sraf lwp_release_all(&ent->lwpchan_lwpchan); 29396057Sraf suword8_noerr(&lp->mutex_waiters, 0); 29406057Sraf } else if (lwp_release(&ent->lwpchan_lwpchan, 29416057Sraf &waiters, 0)) { 29426057Sraf suword8_noerr(&lp->mutex_waiters, 29436057Sraf waiters); 29446057Sraf } 29456057Sraf } 29466057Sraf } else { 29477751SRoger.Faulkner@Sun.COM /* 29487751SRoger.Faulkner@Sun.COM * We are the owner. Release it. 29497751SRoger.Faulkner@Sun.COM */ 29506057Sraf (void) lwp_clear_mutex(lp, lockflg); 29516057Sraf ulock_clear(&lp->mutex_lockw); 29526057Sraf fuword8_noerr(&lp->mutex_waiters, &waiters); 29536057Sraf if (waiters && 29546057Sraf lwp_release(&ent->lwpchan_lwpchan, &waiters, 0)) 29556057Sraf suword8_noerr(&lp->mutex_waiters, waiters); 29566057Sraf } 29574574Sraf lwpchan_unlock(&ent->lwpchan_lwpchan, LWPCHAN_MPPOOL); 29584574Sraf } 29590Sstevel@tonic-gate out: 29600Sstevel@tonic-gate no_fault(); 29610Sstevel@tonic-gate if (watched) 29620Sstevel@tonic-gate watch_enable_addr((caddr_t)lp, sizeof (*lp), S_WRITE); 29630Sstevel@tonic-gate } 29640Sstevel@tonic-gate 29650Sstevel@tonic-gate /* 29664574Sraf * Register a process-shared robust mutex in the lwpchan cache. 29670Sstevel@tonic-gate */ 29680Sstevel@tonic-gate int 2969*9264SRoger.Faulkner@Sun.COM lwp_mutex_register(lwp_mutex_t *lp, caddr_t uaddr) 29700Sstevel@tonic-gate { 29710Sstevel@tonic-gate int error = 0; 29724574Sraf volatile int watched; 29730Sstevel@tonic-gate label_t ljb; 29744574Sraf uint8_t type; 29750Sstevel@tonic-gate lwpchan_t lwpchan; 29760Sstevel@tonic-gate 29770Sstevel@tonic-gate if ((caddr_t)lp >= (caddr_t)USERLIMIT) 29780Sstevel@tonic-gate return (set_errno(EFAULT)); 29790Sstevel@tonic-gate 29800Sstevel@tonic-gate watched = watch_disable_addr((caddr_t)lp, sizeof (*lp), S_WRITE); 29810Sstevel@tonic-gate 29820Sstevel@tonic-gate if (on_fault(&ljb)) { 29830Sstevel@tonic-gate error = EFAULT; 29844574Sraf } else { 29856577Sraf /* 29866577Sraf * Force Copy-on-write if necessary and ensure that the 29876577Sraf * synchronization object resides in read/write memory. 29886577Sraf * Cause an EFAULT return now if this is not so. 29896577Sraf */ 29904574Sraf fuword8_noerr(&lp->mutex_type, &type); 29916577Sraf suword8_noerr(&lp->mutex_type, type); 29924574Sraf if ((type & (USYNC_PROCESS|LOCK_ROBUST)) 29934574Sraf != (USYNC_PROCESS|LOCK_ROBUST)) { 29944574Sraf error = EINVAL; 2995*9264SRoger.Faulkner@Sun.COM } else if (!lwpchan_get_mapping(curproc->p_as, (caddr_t)lp, 2996*9264SRoger.Faulkner@Sun.COM uaddr, type, &lwpchan, LWPCHAN_MPPOOL)) { 29976577Sraf error = EFAULT; 29984574Sraf } 29990Sstevel@tonic-gate } 30000Sstevel@tonic-gate no_fault(); 30010Sstevel@tonic-gate if (watched) 30020Sstevel@tonic-gate watch_enable_addr((caddr_t)lp, sizeof (*lp), S_WRITE); 30030Sstevel@tonic-gate if (error) 30040Sstevel@tonic-gate return (set_errno(error)); 30050Sstevel@tonic-gate return (0); 30060Sstevel@tonic-gate } 30070Sstevel@tonic-gate 3008*9264SRoger.Faulkner@Sun.COM /* 3009*9264SRoger.Faulkner@Sun.COM * There is a user-level robust lock registration in libc. 3010*9264SRoger.Faulkner@Sun.COM * Mark it as invalid by storing -1 into the location of the pointer. 3011*9264SRoger.Faulkner@Sun.COM */ 3012*9264SRoger.Faulkner@Sun.COM static void 3013*9264SRoger.Faulkner@Sun.COM lwp_mutex_unregister(void *uaddr) 3014*9264SRoger.Faulkner@Sun.COM { 3015*9264SRoger.Faulkner@Sun.COM if (get_udatamodel() == DATAMODEL_NATIVE) { 3016*9264SRoger.Faulkner@Sun.COM (void) sulword(uaddr, (ulong_t)-1); 3017*9264SRoger.Faulkner@Sun.COM #ifdef _SYSCALL32_IMPL 3018*9264SRoger.Faulkner@Sun.COM } else { 3019*9264SRoger.Faulkner@Sun.COM (void) suword32(uaddr, (uint32_t)-1); 3020*9264SRoger.Faulkner@Sun.COM #endif 3021*9264SRoger.Faulkner@Sun.COM } 3022*9264SRoger.Faulkner@Sun.COM } 3023*9264SRoger.Faulkner@Sun.COM 30240Sstevel@tonic-gate int 30250Sstevel@tonic-gate lwp_mutex_trylock(lwp_mutex_t *lp) 30260Sstevel@tonic-gate { 30270Sstevel@tonic-gate kthread_t *t = curthread; 30280Sstevel@tonic-gate proc_t *p = ttoproc(t); 30290Sstevel@tonic-gate int error = 0; 30300Sstevel@tonic-gate volatile int locked = 0; 30310Sstevel@tonic-gate volatile int watched = 0; 30320Sstevel@tonic-gate label_t ljb; 30330Sstevel@tonic-gate volatile uint8_t type = 0; 30340Sstevel@tonic-gate uint16_t flag; 30350Sstevel@tonic-gate lwpchan_t lwpchan; 30360Sstevel@tonic-gate 30370Sstevel@tonic-gate if ((caddr_t)lp >= p->p_as->a_userlimit) 30380Sstevel@tonic-gate return (set_errno(EFAULT)); 30390Sstevel@tonic-gate 30400Sstevel@tonic-gate (void) new_mstate(t, LMS_USER_LOCK); 30410Sstevel@tonic-gate 30420Sstevel@tonic-gate if (on_fault(&ljb)) { 30430Sstevel@tonic-gate if (locked) 30440Sstevel@tonic-gate lwpchan_unlock(&lwpchan, LWPCHAN_MPPOOL); 30450Sstevel@tonic-gate error = EFAULT; 30460Sstevel@tonic-gate goto out; 30470Sstevel@tonic-gate } 30486577Sraf /* 30496577Sraf * Force Copy-on-write if necessary and ensure that the 30506577Sraf * synchronization object resides in read/write memory. 30516577Sraf * Cause an EFAULT return now if this is not so. 30526577Sraf */ 30530Sstevel@tonic-gate fuword8_noerr(&lp->mutex_type, (uint8_t *)&type); 30546577Sraf suword8_noerr(&lp->mutex_type, type); 30550Sstevel@tonic-gate if (UPIMUTEX(type)) { 30560Sstevel@tonic-gate no_fault(); 30570Sstevel@tonic-gate error = lwp_upimutex_lock(lp, type, UPIMUTEX_TRY, NULL); 30584574Sraf if ((type & USYNC_PROCESS) && 30594574Sraf (error == 0 || 30604574Sraf error == EOWNERDEAD || error == ELOCKUNMAPPED)) 30610Sstevel@tonic-gate (void) suword32(&lp->mutex_ownerpid, p->p_pid); 30620Sstevel@tonic-gate if (error) 30630Sstevel@tonic-gate return (set_errno(error)); 30640Sstevel@tonic-gate return (0); 30650Sstevel@tonic-gate } 30660Sstevel@tonic-gate if (!get_lwpchan(curproc->p_as, (caddr_t)lp, type, 30670Sstevel@tonic-gate &lwpchan, LWPCHAN_MPPOOL)) { 30680Sstevel@tonic-gate error = EFAULT; 30690Sstevel@tonic-gate goto out; 30700Sstevel@tonic-gate } 30710Sstevel@tonic-gate lwpchan_lock(&lwpchan, LWPCHAN_MPPOOL); 30720Sstevel@tonic-gate locked = 1; 30734574Sraf if (type & LOCK_ROBUST) { 30744574Sraf fuword16_noerr(&lp->mutex_flag, &flag); 30750Sstevel@tonic-gate if (flag & LOCK_NOTRECOVERABLE) { 30760Sstevel@tonic-gate lwpchan_unlock(&lwpchan, LWPCHAN_MPPOOL); 30770Sstevel@tonic-gate error = ENOTRECOVERABLE; 30780Sstevel@tonic-gate goto out; 30790Sstevel@tonic-gate } 30800Sstevel@tonic-gate } 30810Sstevel@tonic-gate 30820Sstevel@tonic-gate watched = watch_disable_addr((caddr_t)lp, sizeof (*lp), S_WRITE); 30830Sstevel@tonic-gate 30840Sstevel@tonic-gate if (!ulock_try(&lp->mutex_lockw)) 30850Sstevel@tonic-gate error = EBUSY; 30864574Sraf else { 30874574Sraf if (type & USYNC_PROCESS) 30884574Sraf suword32_noerr(&lp->mutex_ownerpid, p->p_pid); 30894574Sraf if (type & LOCK_ROBUST) { 30904574Sraf fuword16_noerr(&lp->mutex_flag, &flag); 30914574Sraf if (flag & (LOCK_OWNERDEAD | LOCK_UNMAPPED)) { 30924574Sraf if (flag & LOCK_OWNERDEAD) 30934574Sraf error = EOWNERDEAD; 30944574Sraf else if (type & USYNC_PROCESS_ROBUST) 30954574Sraf error = ELOCKUNMAPPED; 30964574Sraf else 30974574Sraf error = EOWNERDEAD; 30984574Sraf } 30990Sstevel@tonic-gate } 31000Sstevel@tonic-gate } 31010Sstevel@tonic-gate locked = 0; 31020Sstevel@tonic-gate lwpchan_unlock(&lwpchan, LWPCHAN_MPPOOL); 31030Sstevel@tonic-gate out: 31040Sstevel@tonic-gate 31050Sstevel@tonic-gate if (t->t_mstate == LMS_USER_LOCK) 31060Sstevel@tonic-gate (void) new_mstate(t, LMS_SYSTEM); 31070Sstevel@tonic-gate 31080Sstevel@tonic-gate no_fault(); 31090Sstevel@tonic-gate if (watched) 31100Sstevel@tonic-gate watch_enable_addr((caddr_t)lp, sizeof (*lp), S_WRITE); 31110Sstevel@tonic-gate if (error) 31120Sstevel@tonic-gate return (set_errno(error)); 31130Sstevel@tonic-gate return (0); 31140Sstevel@tonic-gate } 31150Sstevel@tonic-gate 31160Sstevel@tonic-gate /* 31170Sstevel@tonic-gate * unlock the mutex and unblock lwps that is trying to acquire this mutex. 31180Sstevel@tonic-gate * the blocked lwp resumes and retries to acquire the lock. 31190Sstevel@tonic-gate */ 31200Sstevel@tonic-gate int 31210Sstevel@tonic-gate lwp_mutex_unlock(lwp_mutex_t *lp) 31220Sstevel@tonic-gate { 31230Sstevel@tonic-gate proc_t *p = ttoproc(curthread); 31240Sstevel@tonic-gate lwpchan_t lwpchan; 31250Sstevel@tonic-gate uchar_t waiters; 31260Sstevel@tonic-gate volatile int locked = 0; 31270Sstevel@tonic-gate volatile int watched = 0; 31280Sstevel@tonic-gate volatile uint8_t type = 0; 31290Sstevel@tonic-gate label_t ljb; 31300Sstevel@tonic-gate uint16_t flag; 31310Sstevel@tonic-gate int error = 0; 31320Sstevel@tonic-gate 31330Sstevel@tonic-gate if ((caddr_t)lp >= p->p_as->a_userlimit) 31340Sstevel@tonic-gate return (set_errno(EFAULT)); 31350Sstevel@tonic-gate 31360Sstevel@tonic-gate if (on_fault(&ljb)) { 31370Sstevel@tonic-gate if (locked) 31380Sstevel@tonic-gate lwpchan_unlock(&lwpchan, LWPCHAN_MPPOOL); 31390Sstevel@tonic-gate error = EFAULT; 31400Sstevel@tonic-gate goto out; 31410Sstevel@tonic-gate } 31426577Sraf 31436577Sraf /* 31446577Sraf * Force Copy-on-write if necessary and ensure that the 31456577Sraf * synchronization object resides in read/write memory. 31466577Sraf * Cause an EFAULT return now if this is not so. 31476577Sraf */ 31480Sstevel@tonic-gate fuword8_noerr(&lp->mutex_type, (uint8_t *)&type); 31496577Sraf suword8_noerr(&lp->mutex_type, type); 31506577Sraf 31510Sstevel@tonic-gate if (UPIMUTEX(type)) { 31520Sstevel@tonic-gate no_fault(); 31530Sstevel@tonic-gate error = lwp_upimutex_unlock(lp, type); 31540Sstevel@tonic-gate if (error) 31550Sstevel@tonic-gate return (set_errno(error)); 31560Sstevel@tonic-gate return (0); 31570Sstevel@tonic-gate } 31580Sstevel@tonic-gate 31590Sstevel@tonic-gate watched = watch_disable_addr((caddr_t)lp, sizeof (*lp), S_WRITE); 31600Sstevel@tonic-gate 31610Sstevel@tonic-gate if (!get_lwpchan(curproc->p_as, (caddr_t)lp, type, 31620Sstevel@tonic-gate &lwpchan, LWPCHAN_MPPOOL)) { 31630Sstevel@tonic-gate error = EFAULT; 31640Sstevel@tonic-gate goto out; 31650Sstevel@tonic-gate } 31660Sstevel@tonic-gate lwpchan_lock(&lwpchan, LWPCHAN_MPPOOL); 31670Sstevel@tonic-gate locked = 1; 31684574Sraf if (type & LOCK_ROBUST) { 31694574Sraf fuword16_noerr(&lp->mutex_flag, &flag); 31704574Sraf if (flag & (LOCK_OWNERDEAD | LOCK_UNMAPPED)) { 31714574Sraf flag &= ~(LOCK_OWNERDEAD | LOCK_UNMAPPED); 31724574Sraf flag |= LOCK_NOTRECOVERABLE; 31734574Sraf suword16_noerr(&lp->mutex_flag, flag); 31740Sstevel@tonic-gate } 31754574Sraf } 31764574Sraf if (type & USYNC_PROCESS) 31770Sstevel@tonic-gate suword32_noerr(&lp->mutex_ownerpid, 0); 31780Sstevel@tonic-gate ulock_clear(&lp->mutex_lockw); 31790Sstevel@tonic-gate /* 31800Sstevel@tonic-gate * Always wake up an lwp (if any) waiting on lwpchan. The woken lwp will 31810Sstevel@tonic-gate * re-try the lock in lwp_mutex_timedlock(). The call to lwp_release() 31820Sstevel@tonic-gate * may fail. If it fails, do not write into the waiter bit. 31830Sstevel@tonic-gate * The call to lwp_release() might fail due to one of three reasons: 31840Sstevel@tonic-gate * 31850Sstevel@tonic-gate * 1. due to the thread which set the waiter bit not actually 31860Sstevel@tonic-gate * sleeping since it got the lock on the re-try. The waiter 31870Sstevel@tonic-gate * bit will then be correctly updated by that thread. This 31880Sstevel@tonic-gate * window may be closed by reading the wait bit again here 31890Sstevel@tonic-gate * and not calling lwp_release() at all if it is zero. 31900Sstevel@tonic-gate * 2. the thread which set the waiter bit and went to sleep 31910Sstevel@tonic-gate * was woken up by a signal. This time, the waiter recomputes 31920Sstevel@tonic-gate * the wait bit in the return with EINTR code. 31930Sstevel@tonic-gate * 3. the waiter bit read by lwp_mutex_wakeup() was in 31940Sstevel@tonic-gate * memory that has been re-used after the lock was dropped. 31950Sstevel@tonic-gate * In this case, writing into the waiter bit would cause data 31960Sstevel@tonic-gate * corruption. 31970Sstevel@tonic-gate */ 31980Sstevel@tonic-gate fuword8_noerr(&lp->mutex_waiters, &waiters); 31990Sstevel@tonic-gate if (waiters) { 32004574Sraf if ((type & LOCK_ROBUST) && 32010Sstevel@tonic-gate (flag & LOCK_NOTRECOVERABLE)) { 32020Sstevel@tonic-gate lwp_release_all(&lwpchan); 32030Sstevel@tonic-gate suword8_noerr(&lp->mutex_waiters, 0); 32046057Sraf } else if (lwp_release(&lwpchan, &waiters, 0)) { 32050Sstevel@tonic-gate suword8_noerr(&lp->mutex_waiters, waiters); 32060Sstevel@tonic-gate } 32070Sstevel@tonic-gate } 32080Sstevel@tonic-gate 32090Sstevel@tonic-gate lwpchan_unlock(&lwpchan, LWPCHAN_MPPOOL); 32100Sstevel@tonic-gate out: 32110Sstevel@tonic-gate no_fault(); 32120Sstevel@tonic-gate if (watched) 32130Sstevel@tonic-gate watch_enable_addr((caddr_t)lp, sizeof (*lp), S_WRITE); 32140Sstevel@tonic-gate if (error) 32150Sstevel@tonic-gate return (set_errno(error)); 32160Sstevel@tonic-gate return (0); 32170Sstevel@tonic-gate } 3218